diff --git a/apps/bi/migrations/0002_auto_20230522_1505.py b/apps/bi/migrations/0002_auto_20230522_1505.py new file mode 100644 index 00000000..5bee1c41 --- /dev/null +++ b/apps/bi/migrations/0002_auto_20230522_1505.py @@ -0,0 +1,33 @@ +# Generated by Django 3.2.12 on 2023-05-22 07:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('bi', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='dataset', + name='description', + field=models.TextField(blank=True, default='', verbose_name='描述说明'), + ), + migrations.AlterField( + model_name='dataset', + name='sql_query', + field=models.TextField(blank=True, default='', verbose_name='sql查询语句'), + ), + migrations.AlterField( + model_name='report', + name='code', + field=models.CharField(blank=True, default='', max_length=100, verbose_name='标识'), + ), + migrations.AlterField( + model_name='report', + name='js_function', + field=models.TextField(blank=True, default='', verbose_name='数据转化函数'), + ), + ] diff --git a/apps/em/__init__.py b/apps/em/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/em/admin.py b/apps/em/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/apps/em/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/apps/em/apps.py b/apps/em/apps.py new file mode 100644 index 00000000..5c41d5e1 --- /dev/null +++ b/apps/em/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class EmConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'apps.em' diff --git a/apps/em/filters.py b/apps/em/filters.py new file mode 100644 index 00000000..2d78cdb0 --- /dev/null +++ b/apps/em/filters.py @@ -0,0 +1,20 @@ +from django_filters import rest_framework as filters +from apps.em.models import Equipment +from datetime import datetime, timedelta + +class EquipFilterSet(filters.FilterSet): + tag = filters.CharFilter(method='filter_tag') + class Meta: + model = Equipment + fields = ['keeper', 'type', 'tag'] + + def filter_tag(self, queryset, name, value): + now = datetime.now() + day7_after = now + timedelta(days=7) + if value == 'near_check': + queryset = queryset.filter( + next_check_date__lte = datetime.date(day7_after)) + elif value == 'out_check': + queryset = queryset.filter( + next_check_date__gt = datetime.date(now)) + return queryset \ No newline at end of file diff --git a/apps/em/migrations/0001_initial.py b/apps/em/migrations/0001_initial.py new file mode 100644 index 00000000..5069dca3 --- /dev/null +++ b/apps/em/migrations/0001_initial.py @@ -0,0 +1,69 @@ +# Generated by Django 3.2.12 on 2023-05-22 07:53 + +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='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': '设备信息', + }, + ), + 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, verbose_name='测点编号')), + ('unit', models.CharField(max_length=50, 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='创建人')), + ('equipment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='em.equipment', 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, + }, + ), + ] 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/em/models.py b/apps/em/models.py new file mode 100644 index 00000000..22312fec --- /dev/null +++ b/apps/em/models.py @@ -0,0 +1,90 @@ +from django.db import models +from apps.utils.models import CommonBModel, CommonADModel, CommonAModel +from apps.system.models import User + +# Create your models here. +class Equipment(CommonBModel): + """ + 设备台账信息 + 其中belong_dept是责任部门 + """ + EQUIP_STATE_OK = 10 + EQUIP_STATE_LIMIT = 20 + EQUIP_STATE_FIX = 30 + EQUIP_STATE_DISABLE = 40 + EQUIP_STATE_SCRAP = 50 + state_choices = ( + (EQUIP_STATE_OK, '完好'), + (EQUIP_STATE_LIMIT, '限用'), + (EQUIP_STATE_FIX, '在修'), + (EQUIP_STATE_DISABLE, '禁用'), + (EQUIP_STATE_SCRAP, '报废') + + ) + EQUIP_TYPE_PRO = 10 + EQUIP_TYPE_MEA = 20 + type_choices = ( + (10, '生产设备'), + (20, '计量检测工具') + ) + # mgmtype_choices = ( + # (1, 'A'), + # (2, 'B'), + # (3, 'C') + # ) + # way_choices = ( + # (1, '外检'), + # (2, '自检'), + + # ) + # usetype_choices = ( + # (1, '专用'), + # (2, '公用'), + # ) + type = models.PositiveSmallIntegerField('类型', choices=type_choices, default=10) + name = models.CharField('设备名称', max_length=50) + number = models.CharField('设备编号', max_length=50, unique=True) + model = models.CharField('规格型号', max_length=60, default='', blank=True) + factory = models.CharField('生产厂', max_length=50, default='', blank=True) + production_date = models.DateField('生产日期', null=True, blank=True) + buy_date = models.DateField('购置日期', null=True, blank=True) + state = models.PositiveIntegerField('设备状态', choices=state_choices, default=EQUIP_STATE_OK) + parameter = models.TextField('技术参数', default='', blank=True) + place = models.CharField('安装/存放位置', max_length=50, default='', blank=True) + count = models.PositiveIntegerField('数量', default=1) + keeper = models.ForeignKey(User, verbose_name='责任人', on_delete=models.CASCADE, null=True, blank=True) + description = models.CharField('描述', max_length=200, default='', null=True) + + # 以下是计量检测设备单独字段 + # mgmtype = models.IntegerField('管理类别', choices=mgmtype_choices, default=1) + # usetype = models.IntegerField('使用类别', choices=usetype_choices, default=1) + # way = models.IntegerField('校准或检定方式', choices=way_choices, default=1) + # standard = models.CharField('溯源标准或依据', max_length=200, default='', blank=True) + cycle = models.PositiveSmallIntegerField('校准或检定周期(月)', null=True, blank=True) + check_date = models.DateField('最近校准检查日期', blank=True, null=True) + next_check_date = models.DateField('预计下次校准检查日期',blank=True, null=True) + + class Meta: + verbose_name = '设备信息' + verbose_name_plural = verbose_name + + def __str__(self): + return self.number + '-' + self.name + + +# class EcheckRecord(CommonADModel): +# """ +# 校准鉴定记录 +# """ +# equipment = models.ForeignKey(Equipment, verbose_name='关联设备', on_delete=models.CASCADE) +# check_date = models.DateField('校准检查日期') +# result = models.CharField('结果', max_length=200, blank=True, null=True) + + +class Mpoint(CommonAModel): + """测点 + """ + equipment = models.ForeignKey(Equipment, verbose_name='关联设备', on_delete=models.CASCADE) + name = models.CharField('测点名称', max_length=50) + code = models.CharField('测点编号', max_length=50) + unit = models.CharField('单位', max_length=50) \ No newline at end of file diff --git a/apps/em/serializers.py b/apps/em/serializers.py new file mode 100644 index 00000000..4a5a242b --- /dev/null +++ b/apps/em/serializers.py @@ -0,0 +1,19 @@ +from apps.utils.serializers import CustomModelSerializer +from apps.em.models import Equipment, Mpoint +from apps.utils.constants import EXCLUDE_FIELDS, EXCLUDE_FIELDS_BASE +from rest_framework import serializers + +class EquipmentSerializer(CustomModelSerializer): + keeper_name = serializers.CharField(source='keeper.name') + belong_dept_name = serializers.CharField(source='belong_dept.name') + class Meta: + model = Equipment + fields = '__all__' + read_only_fields = EXCLUDE_FIELDS + ['check_date', 'next_check_date', 'keeper_name', 'belong_dept_name'] + + +class MpointSerializer(CustomModelSerializer): + class Meta: + model = Mpoint + fields = '__all__' + read_only_fields = EXCLUDE_FIELDS \ No newline at end of file diff --git a/apps/em/tests.py b/apps/em/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/apps/em/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/apps/em/urls.py b/apps/em/urls.py new file mode 100644 index 00000000..86176f48 --- /dev/null +++ b/apps/em/urls.py @@ -0,0 +1,13 @@ +from django.urls import path, include +from rest_framework.routers import DefaultRouter +from apps.em.views import EquipmentViewSet, MpointViewSet + +API_BASE_URL = 'api/em/' +HTML_BASE_URL = 'em/' + +router = DefaultRouter() +router.register('equipment', EquipmentViewSet, basename='equipment') +router.register('mpoint', MpointViewSet, basename='mpoint') +urlpatterns = [ + path(API_BASE_URL, include(router.urls)), +] \ No newline at end of file diff --git a/apps/em/views.py b/apps/em/views.py new file mode 100644 index 00000000..08923bc1 --- /dev/null +++ b/apps/em/views.py @@ -0,0 +1,27 @@ +from django.shortcuts import render +from apps.em.models import Equipment, Mpoint +from apps.utils.viewsets import CustomModelViewSet +from apps.em.serializers import EquipmentSerializer, MpointSerializer +from apps.em.filters import EquipFilterSet +from rest_framework.exceptions import ParseError + +# Create your views here. +class EquipmentViewSet(CustomModelViewSet): + queryset = Equipment.objects.all() + serializer_class = EquipmentSerializer + select_related_fields = ['create_by', 'belong_dept', 'keeper'] + search_fields = ['number', 'name'] + filterset_class = EquipFilterSet + + def filter_queryset(self, queryset): + if not self.detail and not self.request.query_params.get('type', None): + raise ParseError('请指定设备类型') + return super().filter_queryset(queryset) + + +class MpointViewSet(CustomModelViewSet): + queryset = Mpoint.objects.all() + serializer_class = MpointSerializer + select_related_fields = ['create_by'] + filterset_fields = ['equipment'] + search_fields = ['number', 'code'] \ No newline at end of file diff --git a/docs/nengguan.md b/docs/nengguan.md new file mode 100644 index 00000000..f99787f7 --- /dev/null +++ b/docs/nengguan.md @@ -0,0 +1,32 @@ +# 能管系统设计说明书 + +## 设备管理 + +### 用能设备 +编号、名称、设备类别、责任部门、设备重要性、设备描述、基本技术参数、原始采购信息(制造和安装)、重要技术参数、设备逻辑和物理位置。 + +设备信息变更记录-具体信息待定 + +设备档案查询-根据查询人岗位及权限不同,查询功能不同-待定 **意义是?** + +用能设备可关联计量器具,用于监测设备状态 +**计量器具与测点的关系?** + +### 计量器具 +基本技术参数、原始采购信息(制造和安装)、重要技术参数、**库存信息?** + +检验校准记录-记录结果-是否需要上传相关文件 + + +### 设备监测 + +重点设备状态监测 + +设备名称、设备当前状态、与设备启停等关联的测点名称、测点值、测点单位 + +形成状态变动记录,可提示或报警 **何时?** + + +## 实时监控 + +### 综合看板 \ No newline at end of file diff --git a/server/settings.py b/server/settings.py index 4f6396d3..bc4cce7f 100755 --- a/server/settings.py +++ b/server/settings.py @@ -63,7 +63,8 @@ INSTALLED_APPS = [ 'apps.vm', 'apps.rpm', 'apps.opm', - 'apps.bi' + 'apps.bi', + 'apps.em' ] MIDDLEWARE = [ diff --git a/server/urls.py b/server/urls.py index 6c209e83..8d4b3c35 100755 --- a/server/urls.py +++ b/server/urls.py @@ -55,6 +55,7 @@ urlpatterns = [ path('', include('apps.opm.urls')), path('', include('apps.vm.urls')), path('', include('apps.bi.urls')), + path('', include('apps.em.urls')),