diff --git a/apps/enm/migrations/0001_initial.py b/apps/enm/migrations/0001_initial.py index 9cdebe3b..81b322c9 100644 --- a/apps/enm/migrations/0001_initial.py +++ b/apps/enm/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 3.2.12 on 2023-06-15 08:27 +# Generated by Django 3.2.12 on 2023-06-20 09:05 from django.conf import settings from django.db import migrations, models @@ -11,27 +11,26 @@ class Migration(migrations.Migration): initial = True dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), ('em', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), ('system', '0002_myschedule'), ] operations = [ migrations.CreateModel( - name='Mgroup', + 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='删除标记')), - ('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='最后编辑人')), + ('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='当前值')), ], options={ - 'verbose_name': '测点集', + 'abstract': False, }, ), migrations.CreateModel( @@ -49,135 +48,11 @@ class Migration(migrations.Migration): ('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='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='MpointStat', fields=[ @@ -197,53 +72,4 @@ class Migration(migrations.Migration): '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='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/migrations/0002_initial.py b/apps/enm/migrations/0002_initial.py new file mode 100644 index 00000000..83be74dd --- /dev/null +++ b/apps/enm/migrations/0002_initial.py @@ -0,0 +1,34 @@ +# Generated by Django 3.2.12 on 2023-06-20 09:05 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('enm', '0001_initial'), + ('mtm', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AddField( + model_name='mpoint', + name='mgroup', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='mtm.mgroup', verbose_name='所在集合'), + ), + migrations.AddField( + model_name='mpoint', + name='update_by', + field=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='最后编辑人'), + ), + migrations.AddField( + model_name='mplog', + name='mpoint', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='enm.mpoint', verbose_name='关联测点'), + ), + ] diff --git a/apps/enm/models.py b/apps/enm/models.py index 01b88b4b..356def8b 100644 --- a/apps/enm/models.py +++ b/apps/enm/models.py @@ -1,44 +1,8 @@ from django.db import models -from apps.utils.models import CommonBDModel, BaseModel, CommonADModel, CommonAModel, CommonBModel - -class Product(CommonAModel): - """ - 产品 - """ - name = models.CharField('名称', max_length=50) - code = models.CharField('编号', max_length=50, null=True, blank=True) - - class Meta: - verbose_name = '产品' - -class Shift(CommonAModel): - """班次 - """ - name = models.CharField('名称', max_length=50) - start_time_o = models.TimeField('开始时间') - end_time_o = models.TimeField('结束时间') - - class Meta: - verbose_name = '班次' - -class Mgroup(CommonBModel): - """测点集 - """ - name = models.CharField('名称', max_length=50) - cate = models.CharField('分类', max_length=50, default='section') # section是工段 - - class Meta: - verbose_name = '测点集' +from apps.utils.models import BaseModel, CommonBModel -class Team(CommonBModel): - """班组 - """ - name = models.CharField('名称', max_length=50) - leader = models.ForeignKey('system.user', verbose_name='班长', on_delete=models.CASCADE) - - -class Mpoint(CommonBDModel): +class Mpoint(CommonBModel): """测点 """ name = models.CharField('测点名称', max_length=50) @@ -47,7 +11,7 @@ class Mpoint(CommonBDModel): 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) + mgroup = models.ForeignKey('mtm.mgroup', verbose_name='所在集合', on_delete=models.SET_NULL, null=True, blank=True) class MpLog(BaseModel): @@ -58,42 +22,7 @@ class MpLog(BaseModel): 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 SfLog(CommonADModel): - """值班记录 - """ - mgroup = models.ForeignKey(Mgroup, verbose_name='关联工段', on_delete=models.CASCADE) - team = models.ForeignKey(Team, 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('值班结束') - 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 MpointStat(BaseModel): """测点统计表 @@ -104,27 +33,4 @@ class MpointStat(BaseModel): day = models.PositiveSmallIntegerField('日', null=True, blank=True) hour = models.PositiveSmallIntegerField('时', null=True, blank=True) mpoint = models.ForeignKey(Mpoint, verbose_name='关联测点', on_delete=models.CASCADE) - val = models.FloatField('统计值', default=0) - - -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 + val = models.FloatField('统计值', default=0) \ No newline at end of file diff --git a/apps/enm/serializers.py b/apps/enm/serializers.py index b6be4f07..2b1135c7 100644 --- a/apps/enm/serializers.py +++ b/apps/enm/serializers.py @@ -1,25 +1,8 @@ from apps.utils.serializers import CustomModelSerializer -from apps.enm.models import Mpoint, Mgroup, MpLog, Team, SfLog, StLog, StSfLog -from apps.system.models import Dept -from apps.system.serializers import DeptSimpleSerializer -from apps.utils.constants import EXCLUDE_FIELDS, EXCLUDE_FIELDS_BASE +from apps.enm.models import Mpoint, MpLog +from apps.utils.constants import EXCLUDE_FIELDS from rest_framework import serializers -class MgroupSerializer(CustomModelSerializer): - belong_dept = serializers.PrimaryKeyRelatedField(label="所属部门", queryset=Dept.objects.all(), required=True) - belong_dept_name = serializers.CharField(source='belong_dept.name', read_only=True) - class Meta: - model = Mgroup - fields = '__all__' - read_only_fields = EXCLUDE_FIELDS - -class TeamSerializer(CustomModelSerializer): - leader_name = serializers.CharField(source='leader.name', read_only=True) - belong_dept_name = serializers.CharField(source='belong_dept.name', read_only=True) - class Meta: - model = Team - fields = '__all__' - read_only_fields = EXCLUDE_FIELDS class MpointSerializer(CustomModelSerializer): mgroup_name = serializers.CharField(source='mgroup.name', read_only=True) @@ -37,39 +20,4 @@ class MpLogSerializer(CustomModelSerializer): class Meta: model = MpLog fields = '__all__' - read_only_fields = EXCLUDE_FIELDS + ['mpoint_name'] - - -class StLogSerializer(CustomModelSerializer): - mgroup_name = serializers.CharField(source='mgroup.name', read_only=True) - class Meta: - model = StLog - fields = '__all__' - - -class SfLogSerializer(CustomModelSerializer): - mgroup_name = serializers.CharField(source='mgroup.name', read_only=True) - team_name = serializers.CharField(source='team.name', read_only=True) - shift_name = serializers.CharField(source='shift.name', read_only=True) - leader_name = serializers.CharField(source='leader.name', read_only=True) - class Meta: - model = SfLog - fields = '__all__' - read_only_fields = EXCLUDE_FIELDS - 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) - - -class StSfLogSerializer(CustomModelSerializer): - stlog_ = StLogSerializer(source='stlog', read_only=True) - sflog_ = SfLogSerializer(source='sflog', read_only=True) - class Meta: - model = StSfLog - fields = '__all__' - read_only_fields = EXCLUDE_FIELDS + ['stlog', 'sflog', 'is_current_down'] \ No newline at end of file + read_only_fields = EXCLUDE_FIELDS + ['mpoint_name'] \ No newline at end of file diff --git a/apps/enm/tasks.py b/apps/enm/tasks.py index 599524ed..2cfa5382 100644 --- a/apps/enm/tasks.py +++ b/apps/enm/tasks.py @@ -103,4 +103,6 @@ def cal_mpointstats(is_now=1): cal_mpointstat_hour.delay(mpoint.id, now.year, now.moth, now.day, now.hour) else: for mpoint in Mpoint.objects.all(): - cal_mpointstat_hour.delay(mpoint.id, pre.year, pre.month, pre.day, pre.hour) \ No newline at end of file + cal_mpointstat_hour.delay(mpoint.id, pre.year, pre.month, pre.day, pre.hour) + + diff --git a/apps/enm/urls.py b/apps/enm/urls.py index 8463ebf3..f72278c9 100644 --- a/apps/enm/urls.py +++ b/apps/enm/urls.py @@ -1,18 +1,13 @@ from django.urls import path, include from rest_framework.routers import DefaultRouter -from apps.enm.views import MpointViewSet, MgroupViewSet, TeamViewSet, MpLogViewSet, SfLogViewSet, StLogViewSet, StSfLogViewSet +from apps.enm.views import (MpointViewSet, MpLogViewSet) API_BASE_URL = 'api/enm/' HTML_BASE_URL = 'enm/' 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') -router.register('stsflog', StSfLogViewSet, basename='stsflog') 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 d8ab37da..391ad460 100644 --- a/apps/enm/views.py +++ b/apps/enm/views.py @@ -1,36 +1,8 @@ from django.shortcuts import render -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, UpdateModelMixin -from apps.enm.serializers import MpointSerializer, TeamSerializer, MgroupSerializer, MpLogSerializer, SfLogSerializer, StLogSerializer, StSfLogSerializer -from rest_framework.exceptions import ParseError -from django.db import transaction -from django.db.models import Q - -class MgroupViewSet(CustomModelViewSet): - """ - list:测点集 - - 测点集 - """ - queryset = Mgroup.objects.all() - serializer_class = MgroupSerializer - select_related_fields = ['create_by', 'belong_dept'] - filterset_fields = ['belong_dept'] - search_fields = ['number'] - - -class TeamViewSet(CustomModelViewSet): - """ - list:班组 - - 班组 - """ - queryset = Team.objects.all() - serializer_class = TeamSerializer - select_related_fields = ['belong_dept', 'leader'] - filterset_fields = ['belong_dept'] - search_fields = ['name'] +from apps.enm.models import Mpoint, MpLog +from apps.utils.viewsets import CustomModelViewSet, CustomGenericViewSet +from rest_framework.mixins import ListModelMixin +from apps.enm.serializers import (MpointSerializer, MpLogSerializer) class MpointViewSet(CustomModelViewSet): @@ -46,7 +18,7 @@ class MpointViewSet(CustomModelViewSet): search_fields = ['number', 'code'] -class MpLogViewSet(ListModelMixin, GenericViewSet): +class MpLogViewSet(ListModelMixin, CustomGenericViewSet): """ list:测点原始记录 @@ -55,64 +27,4 @@ class MpLogViewSet(ListModelMixin, GenericViewSet): queryset = MpLog.objects.all() serializer_class = MpLogSerializer select_related_fields = ['mpoint'] - filterset_fields = ['mpoint'] - - -class StLogViewSet(ListModelMixin, GenericViewSet): - """ - list:停机记录 - - 停机记录 - """ - queryset = StLog.objects.all() - serializer_class = StLogSerializer - select_related_fields = ['mgroup'] - filterset_fields = ['mgroup'] - ordering = ['-start_time'] - - -class SfLogViewSet(CustomModelViewSet): - """ - list:值班记录 - - 值班记录 - """ - 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() - - -class StSfLogViewSet(ListModelMixin, UpdateModelMixin, GenericViewSet): - """ - list:值班停机关系 - - 值班停机关系 - """ - queryset = StSfLog.objects.all() - serializer_class = StSfLogSerializer - select_related_fields = ['stlog', 'sflog'] - filterset_fields = ['stlog', 'sflog'] - search_fields = ['reason'] - - def filter_queryset(self, queryset): - params = self.request.query_params - if 'stlog' not in params or 'sflog' not in params: - raise ParseError('请指定所属停机或值班记录') - return super().filter_queryset(queryset) \ No newline at end of file + filterset_fields = ['mpoint'] \ No newline at end of file diff --git a/apps/mtm/__init__.py b/apps/mtm/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/mtm/admin.py b/apps/mtm/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/apps/mtm/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/apps/mtm/apps.py b/apps/mtm/apps.py new file mode 100644 index 00000000..870b0d0b --- /dev/null +++ b/apps/mtm/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class MtmConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'apps.mtm' diff --git a/apps/mtm/migrations/0001_initial.py b/apps/mtm/migrations/0001_initial.py new file mode 100644 index 00000000..1bfe053e --- /dev/null +++ b/apps/mtm/migrations/0001_initial.py @@ -0,0 +1,121 @@ +# Generated by Django 3.2.12 on 2023-06-20 09:05 + +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), + ('system', '0002_myschedule'), + ] + + operations = [ + migrations.CreateModel( + name='Material', + 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='标识')), + ('type', models.PositiveSmallIntegerField(choices=[(10, '成品'), (20, '半成品'), (30, '主要原料'), (40, '辅助材料'), (50, '加工工具'), (60, '辅助工装')], default=1, help_text="((10, '成品'), (20, '半成品'), (30, '主要原料'), (40, '辅助材料'), (50, '加工工具'), (60, '辅助工装'))", verbose_name='物料类型')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='material_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('qitems', models.ManyToManyField(blank=True, to='system.Dictionary', verbose_name='质检项目')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='material_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'verbose_name': '物料表', + }, + ), + 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='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.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', help_text='section/other', 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='创建人')), + ('product', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='mtm.material', 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='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_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='创建人')), + ('goal_cate', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='system.dictionary', verbose_name='目标种类')), + ('mgroup', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mtm.mgroup', verbose_name='关联工段')), + ('product', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='关联产品')), + ('team', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mtm.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/mtm/migrations/__init__.py b/apps/mtm/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/mtm/models.py b/apps/mtm/models.py new file mode 100644 index 00000000..d5bed074 --- /dev/null +++ b/apps/mtm/models.py @@ -0,0 +1,78 @@ +from django.db import models +from apps.system.models import CommonAModel, Dictionary, CommonBModel, CommonADModel + +# Create your models here. +class Material(CommonAModel): + MA_TYPE_GOOD = 10 + MA_TYPE_HALFGOOD = 20 + MA_TYPE_MAINSO = 30 + MA_TYPE_HELPSO = 40 + MA_TYPE_TOOL = 50 + MA_TYPE_HELPTOOL = 60 + type_choices=( + (MA_TYPE_GOOD, '成品'), + (MA_TYPE_HALFGOOD, '半成品'), + (MA_TYPE_MAINSO, '主要原料'), + (MA_TYPE_HELPSO, '辅助材料'), + (MA_TYPE_TOOL, '加工工具'), + (MA_TYPE_HELPTOOL, '辅助工装') + ) + name = models.CharField('名称', max_length=50) + code = models.CharField('标识', max_length=50, null=True, blank=True) + type = models.PositiveSmallIntegerField('物料类型', choices= type_choices, default=1, help_text=str(type_choices)) + qitems = models.ManyToManyField(Dictionary, verbose_name='质检项目', blank=True) + + class Meta: + verbose_name = '物料表' + + +class Shift(CommonAModel): + """班次 + """ + name = models.CharField('名称', max_length=50) + start_time_o = models.TimeField('开始时间') + end_time_o = models.TimeField('结束时间') + + class Meta: + verbose_name = '班次' + + +class Team(CommonBModel): + """班组 + """ + name = models.CharField('名称', max_length=50) + leader = models.ForeignKey('system.user', verbose_name='班长', on_delete=models.CASCADE) + + +class Mgroup(CommonBModel): + """测点集 + """ + name = models.CharField('名称', max_length=50) + cate = models.CharField('分类', max_length=50, default='section', help_text='section/other') # section是工段 + product = models.ForeignKey(Material, verbose_name='主要产品', on_delete=models.SET_NULL, null=True, blank=True) + + class Meta: + verbose_name = '测点集' + + +class Goal(CommonADModel): + """目标 + """ + mgroup = models.ForeignKey(Mgroup, verbose_name='关联工段', on_delete=models.CASCADE, null=True, blank=True) + product = models.ForeignKey(Material, 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_cate = models.ForeignKey(Dictionary, verbose_name='目标种类', on_delete=models.CASCADE) + 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/mtm/serializers.py b/apps/mtm/serializers.py new file mode 100644 index 00000000..71e98018 --- /dev/null +++ b/apps/mtm/serializers.py @@ -0,0 +1,34 @@ +from apps.utils.serializers import CustomModelSerializer +from apps.mtm.models import Shift, Material, Mgroup, Team +from apps.utils.constants import EXCLUDE_FIELDS +from rest_framework import serializers +from apps.system.models import Dept + +class ShiftSerializer(CustomModelSerializer): + class Meta: + model = Shift + fields = '__all__' + read_only_fields = EXCLUDE_FIELDS + +class MaterialSerializer(CustomModelSerializer): + class Meta: + model = Material + fields = '__all__' + read_only_fields = EXCLUDE_FIELDS + +class MgroupSerializer(CustomModelSerializer): + belong_dept = serializers.PrimaryKeyRelatedField(label="所属部门", queryset=Dept.objects.all(), required=True) + belong_dept_name = serializers.CharField(source='belong_dept.name', read_only=True) + class Meta: + model = Mgroup + fields = '__all__' + read_only_fields = EXCLUDE_FIELDS + +class TeamSerializer(CustomModelSerializer): + belong_dept = serializers.PrimaryKeyRelatedField(label="所属部门", queryset=Dept.objects.all(), required=True) + leader_name = serializers.CharField(source='leader.name', read_only=True) + belong_dept_name = serializers.CharField(source='belong_dept.name', read_only=True) + class Meta: + model = Team + fields = '__all__' + read_only_fields = EXCLUDE_FIELDS \ No newline at end of file diff --git a/apps/mtm/tests.py b/apps/mtm/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/apps/mtm/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/apps/mtm/urls.py b/apps/mtm/urls.py new file mode 100644 index 00000000..2b87cb4f --- /dev/null +++ b/apps/mtm/urls.py @@ -0,0 +1,17 @@ +from django.urls import path, include +from rest_framework.routers import DefaultRouter + +from apps.mtm.views import MgroupViewSet, ShiftViewSet, TeamViewSet, MaterialViewSet + +API_BASE_URL = 'api/mtm/' +HTML_BASE_URL = 'mtm/' + +router = DefaultRouter() +router.register('mgroup', MgroupViewSet, basename='mgroup') +router.register('team', TeamViewSet, basename='team') +router.register('material', MaterialViewSet, basename='material') +router.register('shift', ShiftViewSet, basename='shift') + +urlpatterns = [ + path(API_BASE_URL, include(router.urls)), +] \ No newline at end of file diff --git a/apps/mtm/views.py b/apps/mtm/views.py new file mode 100644 index 00000000..0c6c4abd --- /dev/null +++ b/apps/mtm/views.py @@ -0,0 +1,57 @@ +from django.shortcuts import render +from rest_framework.mixins import ListModelMixin + +from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet +from apps.mtm.models import Material, Mgroup, Shift, Team +from apps.mtm.serializers import MaterialSerializer, MgroupSerializer, ShiftSerializer, TeamSerializer + +# Create your views here. +class MaterialViewSet(ListModelMixin, CustomGenericViewSet): + """ + list:产品 + + 产品 + """ + queryset = Material.objects.all() + serializer_class = MaterialSerializer + filterset_fields = ['code'] + search_fields = ['name', 'code'] + ordering = ['id'] + + +class ShiftViewSet(ListModelMixin, CustomGenericViewSet): + """ + list:班次 + + 班次 + """ + queryset = Shift.objects.all() + serializer_class = ShiftSerializer + search_fields = ['name'] + ordering = ['id'] + + +class MgroupViewSet(CustomModelViewSet): + """ + list:测点集 + + 测点集 + """ + queryset = Mgroup.objects.all() + serializer_class = MgroupSerializer + select_related_fields = ['create_by', 'belong_dept'] + filterset_fields = ['belong_dept'] + search_fields = ['number'] + + +class TeamViewSet(CustomModelViewSet): + """ + list:班组 + + 班组 + """ + queryset = Team.objects.all() + serializer_class = TeamSerializer + select_related_fields = ['belong_dept', 'leader'] + filterset_fields = ['belong_dept'] + search_fields = ['name'] \ No newline at end of file diff --git a/apps/qm/__init__.py b/apps/qm/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/qm/admin.py b/apps/qm/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/apps/qm/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/apps/qm/apps.py b/apps/qm/apps.py new file mode 100644 index 00000000..436bd4c9 --- /dev/null +++ b/apps/qm/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class QmConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'apps.qm' diff --git a/apps/qm/migrations/0001_initial.py b/apps/qm/migrations/0001_initial.py new file mode 100644 index 00000000..bffa5f65 --- /dev/null +++ b/apps/qm/migrations/0001_initial.py @@ -0,0 +1,60 @@ +# Generated by Django 3.2.12 on 2023-06-20 09:05 + +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 = [ + ('mtm', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('system', '0002_myschedule'), + ] + + operations = [ + migrations.CreateModel( + name='TestItem', + 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=100, verbose_name='名称')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='testitem_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='testitem_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='QuaStat', + 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.CharField(default='day', help_text='year/month/day', max_length=50, verbose_name='统计维度')), + ('year', models.PositiveSmallIntegerField(verbose_name='年')), + ('month', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='月')), + ('day', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='日')), + ('val_avg', models.FloatField(verbose_name='平均值')), + ('num_test', models.PositiveSmallIntegerField(verbose_name='检测次数')), + ('num_ok', models.PositiveSmallIntegerField(verbose_name='合格次数')), + ('rate_pass', models.FloatField(verbose_name='合格率')), + ('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='quastat_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='quastat_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='关联产物')), + ('testitem', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='qm.testitem', verbose_name='质检项目')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='quastat_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/apps/qm/migrations/__init__.py b/apps/qm/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/qm/models.py b/apps/qm/models.py new file mode 100644 index 00000000..32a4c174 --- /dev/null +++ b/apps/qm/models.py @@ -0,0 +1,26 @@ +from django.db import models +from apps.system.models import CommonAModel +from apps.utils.models import CommonBDModel +from apps.mtm.models import Material + +class TestItem(CommonAModel): + """ + 检验项目 + """ + name = models.CharField('名称', max_length=100) + +# Create your models here. +class QuaStat(CommonBDModel): + """ + 质量数据统计表 需要有belong_dept + """ + type = models.CharField('统计维度', max_length=50, default='day', help_text='year/month/day') + year = models.PositiveSmallIntegerField('年') + month = models.PositiveSmallIntegerField('月', null=True, blank=True) + day = models.PositiveSmallIntegerField('日', null=True, blank=True) + product = models.ForeignKey(Material, verbose_name='关联产物', on_delete=models.CASCADE) + testitem = models.ForeignKey(TestItem, verbose_name='质检项目', on_delete=models.CASCADE) + val_avg = models.FloatField('平均值') + num_test = models.PositiveSmallIntegerField('检测次数') + num_ok = models.PositiveSmallIntegerField('合格次数') + rate_pass = models.FloatField('合格率') \ No newline at end of file diff --git a/apps/qm/serializers.py b/apps/qm/serializers.py new file mode 100644 index 00000000..db3e1735 --- /dev/null +++ b/apps/qm/serializers.py @@ -0,0 +1,24 @@ +from apps.qm.models import QuaStat, TestItem +from apps.utils.constants import EXCLUDE_FIELDS +from apps.utils.serializers import CustomModelSerializer +from rest_framework import serializers +from apps.system.models import Dept, Dictionary + +class TestItemSerializer(CustomModelSerializer): + class Meta: + model = TestItem + fields = '__all__' + read_only_fields = EXCLUDE_FIELDS + +class QuaStatSerializer(CustomModelSerializer): + year = serializers.IntegerField(label='年', required=True) + month = serializers.IntegerField(label='月', required=True) + day = serializers.IntegerField(label='天', required=True) + belong_dept = serializers.PrimaryKeyRelatedField(label="所属部门", queryset=Dept.objects.all(), required=True) + belong_dept_name = serializers.CharField(source='belong_dept.name', read_only=True) + product_name = serializers.CharField(source='product.name', read_only=True) + qitem_name = serializers.CharField(source='qitem.name', read_only=True) + class Meta: + model = QuaStat + fields = '__all__' + read_only_fields = EXCLUDE_FIELDS + ['type', 'rate_pass'] \ No newline at end of file diff --git a/apps/qm/tasks.py b/apps/qm/tasks.py new file mode 100644 index 00000000..c4af463b --- /dev/null +++ b/apps/qm/tasks.py @@ -0,0 +1,73 @@ +from __future__ import absolute_import, unicode_literals +from celery import shared_task +from apps.qm.models import QuaStat +from apps.utils.tasks import CustomTask +from django.db.models import Sum, F, ExpressionWrapper, FloatField + + +@shared_task(base=CustomTask) +def cal_quastat(quastatId: str): + # 可以直接使用sql语言 + # query = """ + # SELECT field1, SUM(field2 * field3) AS field2_field3_sum, SUM(field1) AS field1_sum, + # SUM(field2 * field3) / SUM(field1) AS result + # FROM your_table_name + # GROUP BY field1 + # """ + ins = QuaStat.objects.get(id=quastatId) + # 月统计 + params = { + 'testitem': ins.testitem, + 'product': ins.product, + 'belong_dept': ins.belong_dept, + 'year': ins.year, + 'month': ins.month + } + results_month = QuaStat.objects.filter(**params).values('belong_dept', 'product', + 'testitem', 'year', 'month').annotate( + avg_val_total=Sum(F('avg_val')*F('num_test')), + num_test_1=Sum('num_test'), + num_ok_1=Sum('num_ok')).annotate( + avg_val_1=ExpressionWrapper(F('avg_val_total')/F('num_test_1'), output_field=FloatField()), + rate_pass_1=ExpressionWrapper(F('num_ok_1')/F('num_test_1'), output_field=FloatField()) + ) + for r1 in results_month: + stat_params = { + 'avg_val': r1['avg_val_1'], + 'num_test': r1['num_test_1'], + 'num_ok': r1['num_ok_1'], + 'rate_pass': r1['rate_pass_1'] + } + qua, is_created = QuaStat.objects.get_or_create( + **params, **{'type': 'month'}, defaults={**params, **{'type': 'month'}, **stat_params} + ) + if not is_created: + for k in stat_params: + setattr(qua, k, stat_params[k]) + qua.save() + + # 年统计 + params.pop('month') + + results_year = QuaStat.objects.filter(**params).values('belong_dept', 'product', + 'testitem', 'year').annotate( + avg_val_total=Sum(F('avg_val')*F('num_test')), + num_test_1=Sum('num_test'), + num_ok_1=Sum('num_ok')).annotate( + avg_val_1=ExpressionWrapper(F('avg_val_total')/F('num_test_1'), output_field=FloatField()), + rate_pass_1=ExpressionWrapper(F('num_ok_1')/F('num_test_1'), output_field=FloatField()) + ) + for r1 in results_year: + stat_params = { + 'avg_val': r1['avg_val_1'], + 'num_test': r1['num_test_1'], + 'num_ok': r1['num_ok_1'], + 'rate_pass': r1['rate_pass_1'] + } + qua, is_created = QuaStat.objects.get_or_create( + **params, **{'type': 'year'}, defaults={**params, **{'type': 'year'}, **stat_params} + ) + if not is_created: + for k in stat_params: + setattr(qua, k, stat_params[k]) + qua.save() \ No newline at end of file diff --git a/apps/qm/tests.py b/apps/qm/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/apps/qm/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/apps/qm/urls.py b/apps/qm/urls.py new file mode 100644 index 00000000..b986fab8 --- /dev/null +++ b/apps/qm/urls.py @@ -0,0 +1,14 @@ +from django.urls import path, include +from rest_framework.routers import DefaultRouter + +from apps.qm.views import QuaStatViewSet, TestItemViewSet + +API_BASE_URL = 'api/qm/' +HTML_BASE_URL = 'qm/' + +router = DefaultRouter() +router.register('quastat', QuaStatViewSet, basename='quastat') +router.register('testitem', TestItemViewSet, basename='testitem') +urlpatterns = [ + path(API_BASE_URL, include(router.urls)), +] \ No newline at end of file diff --git a/apps/qm/views.py b/apps/qm/views.py new file mode 100644 index 00000000..97267738 --- /dev/null +++ b/apps/qm/views.py @@ -0,0 +1,37 @@ +from django.shortcuts import render +from rest_framework.mixins import ListModelMixin, CreateModelMixin +from apps.qm.models import QuaStat, TestItem +from apps.qm.serializers import QuaStatSerializer, TestItemSerializer +from apps.qm.tasks import cal_quastat + +from apps.utils.viewsets import CustomGenericViewSet + +# Create your views here. +class TestItemViewSet(ListModelMixin, CustomGenericViewSet): + """ + list:质检项目 + + 质检项目 + """ + queryset = TestItem.objects.all() + serializer_class = TestItemSerializer + filterset_fields = [] + ordering = ['id'] + +class QuaStatViewSet(ListModelMixin, CreateModelMixin, CustomGenericViewSet): + """ + list:质量分析报告 + + 质量分析报告 + """ + queryset = QuaStat.objects.all() + serializer_class = QuaStatSerializer + filterset_fields = ['type', 'year', 'month', 'day', 'product', 'testitem', 'belong_dept'] + select_related_fields = ['belong_dept', 'product', 'testitem'] + + def perform_create(self, serializer): + ins = serializer.save() + ins.rate_pass = ins.num_ok/ ins.num_test + ins.save() + # 计算月和年的统计 + cal_quastat.delay(ins.id) \ No newline at end of file diff --git a/apps/wpm/__init__.py b/apps/wpm/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/wpm/admin.py b/apps/wpm/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/apps/wpm/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/apps/wpm/apps.py b/apps/wpm/apps.py new file mode 100644 index 00000000..e0fdeaaf --- /dev/null +++ b/apps/wpm/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class WpmConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'apps.wpm' diff --git a/apps/wpm/migrations/0001_initial.py b/apps/wpm/migrations/0001_initial.py new file mode 100644 index 00000000..8e9754c6 --- /dev/null +++ b/apps/wpm/migrations/0001_initial.py @@ -0,0 +1,88 @@ +# Generated by Django 3.2.12 on 2023-06-20 09:05 + +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 = [ + ('mtm', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + 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='其他备注')), + ('qua_data', models.JSONField(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='mtm.mgroup', verbose_name='关联工段')), + ('shift', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.shift', 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='mtm.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='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='wpm.sflog', verbose_name='关联值班记录')), + ('stlog', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wpm.stlog', verbose_name='关联停机记录')), + ], + options={ + 'ordering': ['sflog__start_time'], + }, + ), + migrations.AddField( + model_name='sflog', + name='stlogs', + field=models.ManyToManyField(through='wpm.StSfLog', to='wpm.StLog', verbose_name='关联停机记录'), + ), + migrations.AddField( + model_name='sflog', + name='team', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.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='最后编辑人'), + ), + ] diff --git a/apps/wpm/migrations/__init__.py b/apps/wpm/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/wpm/models.py b/apps/wpm/models.py new file mode 100644 index 00000000..0d950f51 --- /dev/null +++ b/apps/wpm/models.py @@ -0,0 +1,40 @@ +from django.db import models +from apps.system.models import CommonADModel, BaseModel +from apps.mtm.models import Mgroup, Team, Shift + +# 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): + """值班记录 + """ + mgroup = models.ForeignKey(Mgroup, verbose_name='关联工段', on_delete=models.CASCADE) + team = models.ForeignKey(Team, 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('值班结束') + note = models.TextField('其他备注', null=True, blank=True) + stlogs = models.ManyToManyField('wpm.stlog', verbose_name='关联停机记录', through='wpm.stsflog') + qua_data = models.JSONField('质检数据', null=True, blank=True) + + +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'] diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py new file mode 100644 index 00000000..6bfc5aa3 --- /dev/null +++ b/apps/wpm/serializers.py @@ -0,0 +1,52 @@ +from apps.utils.constants import EXCLUDE_FIELDS +from apps.utils.serializers import CustomModelSerializer +from rest_framework import serializers + +from apps.wpm.models import SfLog, StLog, StSfLog +from apps.system.models import Dictionary + +class StLogSerializer(CustomModelSerializer): + mgroup_name = serializers.CharField(source='mgroup.name', read_only=True) + class Meta: + model = StLog + fields = '__all__' + + +class SfLogSerializer(CustomModelSerializer): + mgroup_name = serializers.CharField(source='mgroup.name', read_only=True) + team_name = serializers.CharField(source='team.name', read_only=True) + shift_name = serializers.CharField(source='shift.name', read_only=True) + leader_name = serializers.CharField(source='leader.name', read_only=True) + class Meta: + model = SfLog + fields = '__all__' + read_only_fields = EXCLUDE_FIELDS + ['leader', 'qua_data'] + update_fields = ['start_time', 'end_time', 'note'] + + def validate(self, attrs): + attrs['leader'] = attrs['mgroup'].leader + return super().validate(attrs) + + 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) + + +class StSfLogSerializer(CustomModelSerializer): + stlog_ = StLogSerializer(source='stlog', read_only=True) + sflog_ = SfLogSerializer(source='sflog', read_only=True) + class Meta: + model = StSfLog + fields = '__all__' + read_only_fields = EXCLUDE_FIELDS + ['stlog', 'sflog', 'is_current_down'] + +class QItemDataSerializer(serializers.Serializer): + qitem = serializers.PrimaryKeyRelatedField(label='检测项目', queryset=Dictionary.objects.filter(type__code='qitem')) + val = serializers.FloatField(label='值') + + +class SfLogQuaSerializer(serializers.Serializer): + qua_data = QItemDataSerializer(many=True) \ No newline at end of file diff --git a/apps/wpm/tests.py b/apps/wpm/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/apps/wpm/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/apps/wpm/urls.py b/apps/wpm/urls.py new file mode 100644 index 00000000..3771d941 --- /dev/null +++ b/apps/wpm/urls.py @@ -0,0 +1,17 @@ +from django.urls import path, include +from rest_framework.routers import DefaultRouter + +from apps.wpm.views import SfLogViewSet, StLogViewSet, StSfLogViewSet + + +API_BASE_URL = 'api/wpm/' +HTML_BASE_URL = 'wpm/' + +router = DefaultRouter() +router.register('sflog', SfLogViewSet, basename='sflog') +router.register('stlog', StLogViewSet, basename='stlog') +router.register('stsflog', StSfLogViewSet, basename='stsflog') + +urlpatterns = [ + path(API_BASE_URL, include(router.urls)), +] \ No newline at end of file diff --git a/apps/wpm/views.py b/apps/wpm/views.py new file mode 100644 index 00000000..18d10881 --- /dev/null +++ b/apps/wpm/views.py @@ -0,0 +1,88 @@ +from django.shortcuts import render +from rest_framework.mixins import ListModelMixin, UpdateModelMixin +from rest_framework.decorators import action +from django.db import transaction +from rest_framework.response import Response +from rest_framework.exceptions import ParseError + +from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet +from apps.wpm.models import SfLog, StLog, StSfLog +from apps.wpm.serializers import SfLogQuaSerializer, SfLogSerializer, StLogSerializer, StSfLogSerializer + +# Create your views here. +class StLogViewSet(ListModelMixin, CustomGenericViewSet): + """ + list:停机记录 + + 停机记录 + """ + queryset = StLog.objects.all() + serializer_class = StLogSerializer + select_related_fields = ['mgroup'] + filterset_fields = ['mgroup'] + ordering = ['-start_time'] + + +class SfLogViewSet(CustomModelViewSet): + """ + list:值班记录 + + 值班记录 + """ + 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() + + @action(methods=['put'], detail=True, perms_map={'put': 'sflogqua.update'}, serializer_class=SfLogQuaSerializer) + def qua_data(self, request, pk=None): + """ + 质量数据录入 + + 质量数据录入 + """ + sflog = self.get_object() + sr = SfLogQuaSerializer(data=request.data) + sr.is_valid(raise_exception=True) + vdata = sr.validated_data + qua_data = vdata['qua_data'] + qua_data_new = [] + for i in qua_data: + qua_data_new.append({'qitem': i['qitem'].id, 'qitem_name': i['qitem'].name, 'val': i['val']}) + sflog.qua_data = qua_data_new + sflog.save() + return Response() + +class StSfLogViewSet(ListModelMixin, UpdateModelMixin, CustomGenericViewSet): + """ + list:值班停机关系 + + 值班停机关系 + """ + queryset = StSfLog.objects.all() + serializer_class = StSfLogSerializer + select_related_fields = ['stlog', 'sflog'] + filterset_fields = ['stlog', 'sflog'] + search_fields = ['reason'] + + def filter_queryset(self, queryset): + params = self.request.query_params + if 'stlog' not in params or 'sflog' not in params: + raise ParseError('请指定所属停机或值班记录') + return super().filter_queryset(queryset) \ No newline at end of file diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 00000000..6faf5485 --- /dev/null +++ b/ruff.toml @@ -0,0 +1,2 @@ +[tool.ruff] +line-length = 120 \ No newline at end of file diff --git a/server/settings.py b/server/settings.py index ef1f11c2..5eee73ff 100755 --- a/server/settings.py +++ b/server/settings.py @@ -98,6 +98,9 @@ INSTALLED_APPS = [ 'apps.opm', 'apps.bi', 'apps.em', + 'apps.mtm', + 'apps.wpm', + 'apps.qm', 'apps.enm' ] diff --git a/server/urls.py b/server/urls.py index e7250b4c..ff35098e 100755 --- a/server/urls.py +++ b/server/urls.py @@ -56,6 +56,9 @@ urlpatterns = [ path('', include('apps.vm.urls')), path('', include('apps.bi.urls')), path('', include('apps.em.urls')), + path('', include('apps.mtm.urls')), + path('', include('apps.wpm.urls')), + path('', include('apps.qm.urls')), path('', include('apps.enm.urls')),