This commit is contained in:
zty 2024-12-13 15:29:13 +08:00
commit e331002538
18 changed files with 201 additions and 28 deletions

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.12 on 2024-12-11 09:36
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('enm', '0049_enstat_ammonia_consume'),
]
operations = [
migrations.AddField(
model_name='mpoint',
name='is_rep_ep0_running_state',
field=models.BooleanField(default=False, verbose_name='是否表示所属设备运行状态'),
),
]

View File

@ -41,6 +41,7 @@ class Mpoint(CommonBModel):
third_info = models.JSONField("第三方信息", default=dict, blank=True) third_info = models.JSONField("第三方信息", default=dict, blank=True)
# {"from": "king", "n": "某名称","d": "某描述或备注","g": "某组", "t": "某类型", "id": 5001, "o": "其他信息"} # {"from": "king", "n": "某名称","d": "某描述或备注","g": "某组", "t": "某类型", "id": 5001, "o": "其他信息"}
enp_field = models.CharField("关联enp采集字段", max_length=50, null=True, blank=True) enp_field = models.CharField("关联enp采集字段", max_length=50, null=True, blank=True)
is_rep_ep0_running_state = models.BooleanField("是否表示所属设备运行状态", default=False)
is_rep_ep_running_state = models.BooleanField("是否表示所监测设备运行状态", default=False) is_rep_ep_running_state = models.BooleanField("是否表示所监测设备运行状态", default=False)
ep_monitored = models.ForeignKey("em.equipment", verbose_name="所监测设备", related_name="mp_ep_monitored", on_delete=models.SET_NULL, null=True, blank=True) ep_monitored = models.ForeignKey("em.equipment", verbose_name="所监测设备", related_name="mp_ep_monitored", on_delete=models.SET_NULL, null=True, blank=True)
ep_rs_val = models.FloatField("状态量基准值", null=True, blank=True) ep_rs_val = models.FloatField("状态量基准值", null=True, blank=True)

View File

@ -223,9 +223,10 @@ class MpointCache:
# 下面开始更新设备信号 # 下面开始更新设备信号
ep_belong_id = current_cache_val.get("ep_belong") ep_belong_id = current_cache_val.get("ep_belong")
ep_monitored_id = current_cache_val.get("ep_monitored") ep_monitored_id = current_cache_val.get("ep_monitored")
if ep_monitored_id and mpoint_is_rep_ep_running_state and ep_belong_id != ep_monitored_id: mpoint_is_rep_ep0_running_state = current_cache_val.get("is_rep_ep0_running_state", False)
if ep_monitored_id and mpoint_is_rep_ep_running_state:
set_eq_rs(ep_monitored_id, last_timex, last_mrs) set_eq_rs(ep_monitored_id, last_timex, last_mrs)
if ep_belong_id: if ep_belong_id and mpoint_is_rep_ep0_running_state and ep_belong_id != ep_monitored_id:
set_eq_rs(ep_belong_id, last_timex, Equipment.RUNING) set_eq_rs(ep_belong_id, last_timex, Equipment.RUNING)
mf_code = current_cache_val.get("mpoint_affect") mf_code = current_cache_val.get("mpoint_affect")

View File

@ -11,6 +11,7 @@ class MaterialFilter(filters.FilterSet):
fields = { fields = {
"id": ["exact", "in"], "id": ["exact", "in"],
"cate": ["exact", "in"], "cate": ["exact", "in"],
"code": ["exact", "in", "isnull"],
"type": ["exact", "in"], "type": ["exact", "in"],
"is_hidden": ["exact"], "is_hidden": ["exact"],
"is_assemb": ["exact"], "is_assemb": ["exact"],

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.12 on 2024-12-12 03:07
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mtm', '0043_srule'),
]
operations = [
migrations.AddField(
model_name='mgroup',
name='code',
field=models.CharField(blank=True, max_length=50, null=True, verbose_name='标识'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.12 on 2024-12-12 07:16
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mtm', '0044_mgroup_code'),
]
operations = [
migrations.AddField(
model_name='process',
name='type',
field=models.PositiveSmallIntegerField(choices=[(10, '生产工序'), (20, '检验工序')], default=10, verbose_name='工序类型'),
),
]

View File

@ -8,8 +8,10 @@ class Process(CommonBModel):
""" """
工序 工序
""" """
PRO_PROD = 10
RPO_TEST = 20
name = models.CharField('工序名称', max_length=100) name = models.CharField('工序名称', max_length=100)
type = models.PositiveSmallIntegerField("工序类型", default=PRO_PROD, choices=((PRO_PROD, '生产工序'), (RPO_TEST, '检验工序')))
cate = models.CharField('大类', max_length=10, default='') cate = models.CharField('大类', max_length=10, default='')
sort = models.PositiveSmallIntegerField('排序', default=1) sort = models.PositiveSmallIntegerField('排序', default=1)
instruction = models.ForeignKey( instruction = models.ForeignKey(
@ -118,6 +120,7 @@ class Mgroup(CommonBModel):
""" """
name = models.CharField('名称', max_length=50) name = models.CharField('名称', max_length=50)
code = models.CharField('标识', max_length=50, null=True, blank=True)
cate = models.CharField( cate = models.CharField(
'分类', max_length=50, default='section', help_text='section/other') # section是工段 '分类', max_length=50, default='section', help_text='section/other') # section是工段
shift_rule = models.CharField('班次规则', max_length=10, default='默认') shift_rule = models.CharField('班次规则', max_length=10, default='默认')

View File

@ -59,6 +59,7 @@ class MgroupSerializer(CustomModelSerializer):
belong_dept_name = serializers.CharField( belong_dept_name = serializers.CharField(
source='belong_dept.name', read_only=True) source='belong_dept.name', read_only=True)
process_name = serializers.CharField(source='process.name', read_only=True) process_name = serializers.CharField(source='process.name', read_only=True)
process_type = serializers.CharField(source='process.type', read_only=True)
process_cate = serializers.CharField(source='process.cate', read_only=True) process_cate = serializers.CharField(source='process.cate', read_only=True)
class Meta: class Meta:

View File

@ -102,7 +102,8 @@ class MgroupViewSet(CustomModelViewSet):
"process": ["exact"], "process": ["exact"],
"cate": ["exact"], "cate": ["exact"],
"belong_dept__name": ["exact", "contains"], "belong_dept__name": ["exact", "contains"],
"name": ["exact", "contains"] "name": ["exact", "contains"],
"code": ["exact", "in", "isnull"]
} }
search_fields = ['name'] search_fields = ['name']
ordering = ['sort', 'create_time'] ordering = ['sort', 'create_time']

View File

@ -0,0 +1,20 @@
# Generated by Django 3.2.12 on 2024-12-12 06:39
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('wf', '0002_alter_state_filter_dept'),
('qm', '0026_auto_20241121_1044'),
]
operations = [
migrations.AddField(
model_name='ftestwork',
name='ticket',
field=models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='ftestwork_ticket', to='wf.ticket', verbose_name='关联工单'),
),
]

View File

@ -152,6 +152,9 @@ class FtestWork(CommonBDModel):
submit_user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='提交人', null=True, blank=True) submit_user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='提交人', null=True, blank=True)
note = models.TextField('备注', null=True, blank=True) note = models.TextField('备注', null=True, blank=True)
equipment = models.ForeignKey(Equipment, verbose_name='所属检验设备', on_delete=models.SET_NULL, null=True, blank=True) equipment = models.ForeignKey(Equipment, verbose_name='所属检验设备', on_delete=models.SET_NULL, null=True, blank=True)
ticket = models.ForeignKey('wf.ticket', verbose_name='关联工单',
on_delete=models.SET_NULL, related_name='ftestwork_ticket', null=True, blank=True,
db_constraint=False)
@classmethod @classmethod
def count_fields(cls): def count_fields(cls):

View File

@ -6,6 +6,18 @@ from django.utils import timezone
from apps.wf.models import Ticket from apps.wf.models import Ticket
from apps.qm.models import NotOkOption from apps.qm.models import NotOkOption
def ftestwork_submit_validate(ins: FtestWork):
wm:WMaterial = ins.wm
if ins.need_update_wm:
if wm.state == WMaterial.WM_TEST:
xcount = wm.count - ins.count
if xcount < 0:
raise ParseError("超过待检数量")
else:
xcount = wm.count - ins.count_notok
if xcount < 0:
raise ParseError("不合格数不可大于批次数量")
def ftestwork_submit(ins:FtestWork, user: User): def ftestwork_submit(ins:FtestWork, user: User):
wm:WMaterial = ins.wm wm:WMaterial = ins.wm
@ -83,4 +95,22 @@ def ftestwork_submit(ins:FtestWork, user: User):
ins.save() ins.save()
def bind_ftestwork(ticket: Ticket, transition, new_ticket_data: dict): def bind_ftestwork(ticket: Ticket, transition, new_ticket_data: dict):
pass ins = FtestWork.objects.get(id=new_ticket_data['t_id'])
if ins.submit_time is not None:
raise ParseError('该检验工作不可提交审批')
ftestwork_submit_validate(ins)
ticket_data = ticket.ticket_data
ticket_data.update({
't_model': 'ftestwork',
't_id': ins.id,
})
ticket.ticket_data = ticket_data
ticket.create_by = ins.create_by
ticket.save()
if ins.ticket is None:
ins.ticket = ticket
ins.save()
def ftestwork_audit_end(ticket: Ticket):
ins = FtestWork.objects.get(id=ticket.ticket_data['t_id'])
ftestwork_submit(ins, ticket.create_by)

View File

@ -0,0 +1,43 @@
# Generated by Django 3.2.12 on 2024-12-13 04:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('system', '0005_alter_permission_type'),
]
operations = [
migrations.AddField(
model_name='permission',
name='component',
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='组件'),
),
migrations.AddField(
model_name='permission',
name='icon',
field=models.CharField(blank=True, max_length=30, null=True, verbose_name='图标'),
),
migrations.AddField(
model_name='permission',
name='is_fullpage',
field=models.BooleanField(default=False, verbose_name='是否全屏'),
),
migrations.AddField(
model_name='permission',
name='is_hidden',
field=models.BooleanField(default=False, verbose_name='是否隐藏'),
),
migrations.AddField(
model_name='permission',
name='path',
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='路由'),
),
migrations.AddField(
model_name='permission',
name='route_name',
field=models.CharField(blank=True, max_length=30, null=True, verbose_name='路由名称'),
),
]

View File

@ -31,6 +31,13 @@ class Permission(ParentModel, BaseModel):
sort = models.PositiveSmallIntegerField('排序标记', default=1) sort = models.PositiveSmallIntegerField('排序标记', default=1)
codes = models.JSONField('权限标识', default=list, null=True, blank=True) codes = models.JSONField('权限标识', default=list, null=True, blank=True)
route_name = models.CharField('路由名称', max_length=30, null=True, blank=True)
icon = models.CharField('图标', max_length=30, null=True, blank=True)
path = models.CharField('路由', max_length=100, null=True, blank=True)
component = models.CharField('组件', max_length=100, null=True, blank=True)
is_hidden = models.BooleanField('是否隐藏', default=False)
is_fullpage = models.BooleanField('是否全屏', default=False)
def __str__(self): def __str__(self):
return self.name return self.name

View File

@ -17,6 +17,7 @@ from apps.third.tapis import dhapis
from rest_framework.validators import UniqueValidator from rest_framework.validators import UniqueValidator
from django.conf import settings from django.conf import settings
from django.db.models import Q from django.db.models import Q
from apps.utils.permission import get_user_perms_map
# from django_q.models import Task as QTask, Schedule as QSchedule # from django_q.models import Task as QTask, Schedule as QSchedule
@ -334,6 +335,23 @@ class UserUpdateSerializer(CustomModelSerializer):
return super().update(instance, validated_data) return super().update(instance, validated_data)
class UserFullInfoSerializer(CustomModelSerializer):
"""
用户信息序列化
"""
perms = serializers.SerializerMethodField()
belong_dept_name = serializers.CharField(source="belong_dept.name", read_only=True)
post_name = serializers.CharField(source="post.name", read_only=True)
class Meta:
model = User
fields = ['id', 'username', 'type', 'name', 'avatar', 'belong_dept',
'belong_dept_name', 'post', 'post_name', 'perms',
'is_superuser', 'wxmp_openid', 'wx_openid']
def get_perms(self, obj):
return get_user_perms_map(obj, update_cache=True)
class UserCreateSerializer(CustomModelSerializer): class UserCreateSerializer(CustomModelSerializer):
""" """
创建用户序列化 创建用户序列化

View File

@ -22,7 +22,7 @@ from apps.system.filters import DeptFilterSet, UserFilterSet
# from django_q.models import Task as QTask, Schedule as QSchedule # from django_q.models import Task as QTask, Schedule as QSchedule
from apps.utils.mixins import (CustomCreateModelMixin, MyLoggingMixin) from apps.utils.mixins import (CustomCreateModelMixin, MyLoggingMixin)
from django.conf import settings from django.conf import settings
from apps.utils.permission import ALL_PERMS, get_user_perms_map from apps.utils.permission import ALL_PERMS
from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet
from server.celery import app as celery_app from server.celery import app as celery_app
from .models import (Dept, Dictionary, DictType, File, Permission, Post, PostRole, Role, User, from .models import (Dept, Dictionary, DictType, File, Permission, Post, PostRole, Role, User,
@ -35,7 +35,8 @@ from .serializers import (ApkSerializer, DeptCreateUpdateSerializer, DeptSeriali
PTaskSerializer, PTaskCreateUpdateSerializer, PTaskResultSerializer, PTaskSerializer, PTaskCreateUpdateSerializer, PTaskResultSerializer,
RoleCreateUpdateSerializer, RoleSerializer, TaskRunSerializer, RoleCreateUpdateSerializer, RoleSerializer, TaskRunSerializer,
UserCreateSerializer, UserListSerializer, UserPostCreateSerializer, UserCreateSerializer, UserListSerializer, UserPostCreateSerializer,
UserPostSerializer, UserUpdateSerializer, MyScheduleCreateSerializer, MyScheduleSerializer) UserPostSerializer, UserUpdateSerializer, UserFullInfoSerializer,
MyScheduleCreateSerializer, MyScheduleSerializer)
from rest_framework.viewsets import GenericViewSet from rest_framework.viewsets import GenericViewSet
from cron_descriptor import get_description from cron_descriptor import get_description
import locale import locale
@ -541,24 +542,7 @@ class UserViewSet(CustomModelViewSet):
获取登录用户信息 获取登录用户信息
""" """
user = request.user user = request.user
perms = get_user_perms_map(user, update_cache=True) return Response(UserFullInfoSerializer(user).data)
data = {
'id': user.id,
'username': user.username,
'type': user.type,
'name': user.name,
'roles': user.roles.values_list('name', flat=True),
'avatar': user.avatar,
'perms': perms,
'belong_dept': user.belong_dept.id if user.belong_dept else None,
'post': user.post.id if user.post else None,
'belong_dept_name': user.belong_dept.name if user.belong_dept else '',
'post_name': user.post.name if user.post else '',
'is_superuser': user.is_superuser,
'wxmp_openid': user.wxmp_openid,
'wx_openid': user.wx_openid
}
return Response(data)
@action(methods=['post'], detail=False, permission_classes=[IsAuthenticated]) @action(methods=['post'], detail=False, permission_classes=[IsAuthenticated])
def bind_wxmp(self, request, pk=None): def bind_wxmp(self, request, pk=None):

View File

@ -68,7 +68,7 @@ def get_team_x(sflog: SfLog):
teamId_list_len = len(teamId_list) teamId_list_len = len(teamId_list)
for i in range(len(rule_compare)-teamId_list_len+1): for i in range(len(rule_compare)-teamId_list_len+1):
if rule_compare[i:i+teamId_list_len] == teamId_list: if rule_compare[i:i+teamId_list_len] == teamId_list:
teamId = rule_compare[i+teamId_list_len+1] teamId = rule_compare[i+teamId_list_len]
team = Team.objects.filter(id=teamId).first() team = Team.objects.filter(id=teamId).first()
return team return team
return None return None
@ -86,7 +86,10 @@ def make_sflogs(mgroup: Mgroup, start_date: datetime.date, end_date: datetime.da
end_time = datetime.datetime.combine(current_date, end_time_o) end_time = datetime.datetime.combine(current_date, end_time_o)
# 以下代码是解决跨天排班时生成当天班次缺少的bug # 以下代码是解决跨天排班时生成当天班次缺少的bug
if start_time > end_time: if start_time > end_time:
end_time += datetime.timedelta(days=1) if end_time.hour == 0:
end_time += datetime.timedelta(days=1)
else:
start_time -= datetime.timedelta(days=1)
total_sec = (end_time - start_time).total_seconds() total_sec = (end_time - start_time).total_seconds()
# 创建SfLog记录 # 创建SfLog记录
@ -105,7 +108,7 @@ def make_sflogs(mgroup: Mgroup, start_date: datetime.date, end_date: datetime.da
if team: if team:
sflog.team = team sflog.team = team
sflog.leader = team.leader sflog.leader = team.leader
sflog.save(update_fields=['team']) sflog.save()
current_date = current_date + datetime.timedelta(days=1) current_date = current_date + datetime.timedelta(days=1)

View File

@ -94,6 +94,9 @@ def cal_exp_duration_sec(stlogId: str='', all=False, now: datetime=None):
end_time__lte=st_end) | sf_qs.filter(start_time__lte=st_start, end_time__gte=st_end)).order_by('start_time').distinct() end_time__lte=st_end) | sf_qs.filter(start_time__lte=st_start, end_time__gte=st_end)).order_by('start_time').distinct()
SfLogExp.objects.filter(stlog=stlog).exclude(sflog__in=sf_qs).delete() SfLogExp.objects.filter(stlog=stlog).exclude(sflog__in=sf_qs).delete()
for ind, sflog in enumerate(sf_qs): for ind, sflog in enumerate(sf_qs):
if ind == 0:
stlog.sflog = sflog
stlog.save()
sflogexp, _ = SfLogExp.objects.get_or_create(stlog=stlog, sflog=sflog, defaults={ sflogexp, _ = SfLogExp.objects.get_or_create(stlog=stlog, sflog=sflog, defaults={
'stlog': stlog, 'sflog': sflog}) 'stlog': stlog, 'sflog': sflog})
# 计算duration # 计算duration