同步一次数据库

This commit is contained in:
caoqianming 2022-06-17 15:20:27 +08:00
parent a5f19641b6
commit c192467d58
43 changed files with 1352 additions and 292 deletions

1
.gitignore vendored
View File

@ -13,5 +13,6 @@ celerybeat-schedule.dat
celerybeat-schedule.dir celerybeat-schedule.dir
db.sqlite3 db.sqlite3
server/conf.py server/conf.py
server/conf.json
sh/* sh/*
nohup.out nohup.out

View File

@ -0,0 +1,76 @@
# Generated by Django 3.2.12 on 2022-06-17 07:19
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', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Access',
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, '禁入')], verbose_name='准入类型')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='Area',
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=20, verbose_name='名称')),
('type', models.PositiveSmallIntegerField(choices=[(10, '固定'), (20, '临时')], default=10, verbose_name='区域类型')),
('level', models.PositiveSmallIntegerField(verbose_name='区域等级')),
('number', models.CharField(blank=True, max_length=20, null=True, verbose_name='编号')),
('visitor_yes', models.BooleanField(default=False, verbose_name='准许访客人员')),
('remployee_yes', models.BooleanField(default=False, verbose_name='准许相关方人员')),
('employee_yes', models.BooleanField(default=True, verbose_name='准许全部员工')),
('third_info', models.JSONField(blank=True, default=dict, verbose_name='三方信息')),
('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='area_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='area_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('posts_access', models.ManyToManyField(through='am.Access', to='system.Post')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='area_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
],
options={
'abstract': False,
},
),
migrations.AddField(
model_name='access',
name='area',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='am.area', verbose_name='关联区域'),
),
migrations.AddField(
model_name='access',
name='create_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='access_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人'),
),
migrations.AddField(
model_name='access',
name='post',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='system.post', verbose_name='关联岗位'),
),
migrations.AddField(
model_name='access',
name='update_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='access_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人'),
),
]

View File

View File

@ -12,15 +12,22 @@ class Area(CommonBModel):
AREA_LEVEL_2 = 20 AREA_LEVEL_2 = 20
AREA_LEVEL_3 = 30 AREA_LEVEL_3 = 30
AREA_LEVEL_4 = 40 AREA_LEVEL_4 = 40
AREA_LEVEL_HOICES = ( AREA_LEVEL_CHOICES = (
(AREA_LEVEL_1, '办公'), (AREA_LEVEL_1, '办公'),
(AREA_LEVEL_2, '生产一般'), (AREA_LEVEL_2, '生产一般'),
(AREA_LEVEL_3, '生产重点'), (AREA_LEVEL_3, '生产重点'),
(AREA_LEVEL_4, '四级') (AREA_LEVEL_4, '四级')
) )
AREA_TYPE_FIX = 10
AREA_TYPE_TEMP = 20
AREA_TYPE_CHOICES = (
(10, '固定'),
(20, '临时')
)
name = models.CharField('名称', max_length=20) name = models.CharField('名称', max_length=20)
type = models.PositiveSmallIntegerField('区域类型', default=10, choices=AREA_TYPE_CHOICES)
level = models.PositiveSmallIntegerField('区域等级') level = models.PositiveSmallIntegerField('区域等级')
sort_str = models.CharField('排序字符', max_length=12, default='1') number = models.CharField('编号', max_length=20, null=True, blank=True)
visitor_yes = models.BooleanField('准许访客人员', default=False) visitor_yes = models.BooleanField('准许访客人员', default=False)
remployee_yes = models.BooleanField('准许相关方人员', default=False) remployee_yes = models.BooleanField('准许相关方人员', default=False)
employee_yes = models.BooleanField('准许全部员工', default=True) employee_yes = models.BooleanField('准许全部员工', default=True)

View File

@ -11,7 +11,7 @@ class AreaSimpleSerializer(CustomModelSerializer):
class AreaCreateUpdateSerializer(CustomModelSerializer): class AreaCreateUpdateSerializer(CustomModelSerializer):
class Meta: class Meta:
model = Area model = Area
fields = ['name', 'level', 'sort_srt', 'visitor_yes', 'remployee_yes', 'employee_yes', 'belong_dept'] fields = ['name', 'level', 'number', 'visitor_yes', 'remployee_yes', 'employee_yes', 'belong_dept']
class AccessCreateSerializer(CustomModelSerializer): class AccessCreateSerializer(CustomModelSerializer):

View File

@ -0,0 +1,129 @@
# Generated by Django 3.2.12 on 2022-06-17 07:19
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 = [
('am', '0001_initial'),
('third', '0001_initial'),
('hrm', '0002_auto_20220617_1124'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('system', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Event',
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='删除标记')),
('imgs', models.JSONField(blank=True, default=list, verbose_name='事件图片')),
('location', models.JSONField(blank=True, default=dict, verbose_name='事件点位坐标')),
('peope_type', models.CharField(blank=True, choices=[('employee', '内部员工'), ('remployee', '相关方人员'), ('visitor', '访客')], max_length=20, null=True, verbose_name='当事人员类型')),
('handle_time', models.DateTimeField(blank=True, null=True, verbose_name='处理时间')),
('handle_desc', models.TextField(blank=True, null=True, verbose_name='处理描述')),
('is_pushed', models.BooleanField(default=False, verbose_name='是否已推送')),
('area', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='am.area', verbose_name='发生区域')),
('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='event_belong_dept', to='system.dept', verbose_name='所属部门')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='EventCate',
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='删除标记')),
('code', models.CharField(max_length=10, unique=True, verbose_name='标识')),
('name', models.CharField(max_length=20, unique=True, verbose_name='名称')),
('trigger', models.PositiveSmallIntegerField(choices=[(10, '监控'), (20, '定位')], default=10, verbose_name='触发方式')),
('speaker_on', models.BooleanField(default=True, verbose_name='开启音响报警')),
('filter_area_level', models.PositiveSmallIntegerField(choices=[(10, '办公'), (20, '生产一般'), (30, '生产重点'), (40, '四级')], default=10, verbose_name='固定音响区域级别过滤')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='eventcate_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('speakers', models.ManyToManyField(to='third.TDevice', verbose_name='固定音响')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='eventcate_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='NotifySetting',
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='删除标记')),
('filter_sender', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='提醒人员过滤')),
('filter_area_level', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='区域级别过滤')),
('sms_enable', models.BooleanField(default=False, verbose_name='短信通知')),
('wechat_enable', models.BooleanField(default=False, verbose_name='开启微信通知')),
('can_handle', models.BooleanField(default=False, verbose_name='是否可处理')),
('sort', models.PositiveIntegerField(default=1, verbose_name='排序')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='notifysetting_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('event_cate', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ecm.eventcate', to_field='code', verbose_name='关联事件种类')),
('post', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='system.post', verbose_name='提醒岗位')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='notifysetting_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='Remind',
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='删除标记')),
('msg', models.TextField(blank=True, null=True, verbose_name='推送文本')),
('is_read', models.BooleanField(default=False, verbose_name='站内信已读')),
('can_handle', models.BooleanField(default=False, verbose_name='是否可处理')),
('dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='system.dept', verbose_name='部门')),
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ecm.event', verbose_name='关联事件')),
('notify_setting', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='ecm.notifysetting', verbose_name='通过哪个配置')),
('post', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='system.post', verbose_name='岗位')),
('recipient', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='接收人')),
],
options={
'abstract': False,
},
),
migrations.AddField(
model_name='event',
name='cate',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ecm.eventcate', verbose_name='事件种类'),
),
migrations.AddField(
model_name='event',
name='create_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='event_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人'),
),
migrations.AddField(
model_name='event',
name='handle_user',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='处理人'),
),
migrations.AddField(
model_name='event',
name='people',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='hrm.employee', verbose_name='当事人'),
),
migrations.AddField(
model_name='event',
name='update_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='event_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人'),
),
]

View File

View File

@ -3,6 +3,7 @@ from apps.am.models import Area
from apps.hrm.models import Employee from apps.hrm.models import Employee
from apps.utils.models import BaseModel, CommonAModel, CommonBModel from apps.utils.models import BaseModel, CommonAModel, CommonBModel
from apps.system.models import Dept, Post, User from apps.system.models import Dept, Post, User
from apps.third.models import TDevice
from django.utils import timezone from django.utils import timezone
# Create your models here. # Create your models here.
@ -19,14 +20,14 @@ class EventCate(CommonAModel):
name = models.CharField('名称', max_length=20, unique=True) name = models.CharField('名称', max_length=20, unique=True)
trigger = models.PositiveSmallIntegerField('触发方式', default=10, choices=EVENT_TRIGGER_CHOICES) trigger = models.PositiveSmallIntegerField('触发方式', default=10, choices=EVENT_TRIGGER_CHOICES)
speaker_on = models.BooleanField('开启音响报警', default=True) speaker_on = models.BooleanField('开启音响报警', default=True)
speakers = models.ManyToManyField('third.tdevice', verbose_name='固定音响') speakers = models.ManyToManyField(TDevice, verbose_name='固定音响')
filter_area_level = models.PositiveSmallIntegerField('固定音响区域级别过滤', choices=Area.AREA_LEVEL_HOICES, filter_area_level = models.PositiveSmallIntegerField('固定音响区域级别过滤', choices=Area.AREA_LEVEL_CHOICES,
default=Area.AREA_LEVEL_1) default=Area.AREA_LEVEL_1)
class PushSetting(CommonAModel): class NotifySetting(CommonAModel):
""" """
推送配置 提醒配置
""" """
PUSH_FILTER1_CHOICES = ( PUSH_FILTER1_CHOICES = (
(10, '当事人部门'), (10, '当事人部门'),
@ -36,11 +37,12 @@ class PushSetting(CommonAModel):
) )
event_cate = models.ForeignKey(EventCate, verbose_name='关联事件种类', event_cate = models.ForeignKey(EventCate, verbose_name='关联事件种类',
to_field='code', on_delete=models.CASCADE) to_field='code', on_delete=models.CASCADE)
post = models.ForeignKey(Post, verbose_name='推送岗位', post = models.ForeignKey(Post, verbose_name='提醒岗位',
on_delete=models.CASCADE, null=True, blank=True) on_delete=models.CASCADE, null=True, blank=True)
filter_to_user = models.PositiveSmallIntegerField('推送人员过滤', null=True, blank=True) filter_sender = models.PositiveSmallIntegerField('提醒人员过滤', null=True, blank=True)
filter_area_level = models.PositiveSmallIntegerField('区域级别过滤', null=True, blank=True) filter_area_level = models.PositiveSmallIntegerField('区域级别过滤', null=True, blank=True)
sms_enable = models.BooleanField('短信通知', default=False) sms_enable = models.BooleanField('短信通知', default=False)
wechat_enable = models.BooleanField('开启微信通知', default=False)
can_handle = models.BooleanField('是否可处理', default=False) can_handle = models.BooleanField('是否可处理', default=False)
sort = models.PositiveIntegerField('排序', default=1) sort = models.PositiveIntegerField('排序', default=1)
@ -49,7 +51,7 @@ class Event(CommonBModel):
""" """
事件 事件
""" """
cate = models.ForeignKey(EventCate, verbose_name='事件种类') cate = models.ForeignKey(EventCate, verbose_name='事件种类', on_delete=models.CASCADE)
imgs = models.JSONField('事件图片', default=list, null=False, blank=True) imgs = models.JSONField('事件图片', default=list, null=False, blank=True)
area = models.ForeignKey(Area, verbose_name='发生区域', on_delete=models.CASCADE) area = models.ForeignKey(Area, verbose_name='发生区域', on_delete=models.CASCADE)
location = models.JSONField('事件点位坐标', default=dict, null=False, blank=True) location = models.JSONField('事件点位坐标', default=dict, null=False, blank=True)
@ -64,22 +66,20 @@ class Event(CommonBModel):
is_pushed = models.BooleanField('是否已推送', default=False) is_pushed = models.BooleanField('是否已推送', default=False)
class Push(BaseModel): class Remind(BaseModel):
""" """
推送情况 事件提醒表
""" """
event = models.ForeignKey(Event, verbose_name='关联事件', event = models.ForeignKey(Event, verbose_name='关联事件',
on_delete=models.CASCADE) on_delete=models.CASCADE)
pusher = models.ForeignKey(User, verbose_name='推送', recipient = models.ForeignKey(User, verbose_name='接收',
on_delete=models.CASCADE) on_delete=models.CASCADE)
push_setting = models.ForeignKey(PushSetting, verbose_name='通过哪个配置', notify_setting = models.ForeignKey(NotifySetting, verbose_name='通过哪个配置',
on_delete=models.CASCADE, null=True, blank=True) on_delete=models.CASCADE, null=True, blank=True)
post = models.ForeignKey(Post, verbose_name='岗位', post = models.ForeignKey(Post, verbose_name='岗位',
on_delete=models.CASCADE, null=True, blank=True) on_delete=models.CASCADE, null=True, blank=True)
dept = models.ForeignKey(Dept, verbose_name='部门', dept = models.ForeignKey(Dept, verbose_name='部门',
on_delete=models.CASCADE, null=True, blank=True) on_delete=models.CASCADE, null=True, blank=True)
msg = models.TextField('推送文本') msg = models.TextField('推送文本', null=True, blank=True)
is_read = models.BooleanField('站内信已读', default=False) is_read = models.BooleanField('站内信已读', default=False)
is_sms_send = models.BooleanField('短信已发送', default=False)
can_handle = models.BooleanField('是否可处理', default=False) can_handle = models.BooleanField('是否可处理', default=False)
last_push_time = models.DateTimeField('最后推送时间', default=timezone.now)

View File

@ -1,5 +1,5 @@
from apps.am.serializers import AreaSimpleSerializer from apps.am.serializers import AreaSimpleSerializer
from apps.ecm.models import EventCate, Push, PushSetting, Event from apps.ecm.models import EventCate, Remind, NotifySetting, Event
from apps.utils.serializers import CustomModelSerializer from apps.utils.serializers import CustomModelSerializer
from rest_framework import serializers from rest_framework import serializers
from apps.system.serializers import UserSimpleSerializer from apps.system.serializers import UserSimpleSerializer
@ -23,9 +23,9 @@ class EventCateUpdateSerializer(CustomModelSerializer):
fields = ['speaker_on', 'speakers', 'filter_area_level'] fields = ['speaker_on', 'speakers', 'filter_area_level']
class PushSettingsSerializer(CustomModelSerializer): class NotifySettingsSerializer(CustomModelSerializer):
class Meta: class Meta:
model = PushSetting model = NotifySetting
fields = '__all__' fields = '__all__'
@ -46,9 +46,9 @@ class EventHandleSerializer(CustomModelSerializer):
fields = ['handle_desc'] fields = ['handle_desc']
class PushSerializer(CustomModelSerializer): class RemindSerializer(CustomModelSerializer):
pusher_ = UserSimpleSerializer(source='pusher', read_only=True) recipient_ = UserSimpleSerializer(source='recipient', read_only=True)
class Meta: class Meta:
model = Push model = Remind
fields = '__all__' fields = '__all__'

View File

@ -1,4 +1,4 @@
from apps.ecm.views import EventCateViewSet, PushSettingViewSet, EventViewSet, PushViewSet from apps.ecm.views import EventCateViewSet, NotifySettingViewSet, EventViewSet, RemindViewSet
from django.urls import path, include from django.urls import path, include
from rest_framework.routers import DefaultRouter from rest_framework.routers import DefaultRouter
@ -8,8 +8,8 @@ HTML_BASE_URL = 'ecm/'
router = DefaultRouter() router = DefaultRouter()
router.register('event_cate', EventCateViewSet, basename='event_cate') router.register('event_cate', EventCateViewSet, basename='event_cate')
router.register('event', EventViewSet, basename='event') router.register('event', EventViewSet, basename='event')
router.register('push_setting', PushSettingViewSet, basename='push_setting') router.register('notify_setting', NotifySettingViewSet, basename='notify_setting')
router.register('push', PushViewSet, basename='push') router.register('remind', RemindViewSet, basename='remind')
urlpatterns = [ urlpatterns = [
path(API_BASE_URL, include(router.urls)), path(API_BASE_URL, include(router.urls)),
] ]

View File

@ -1,7 +1,7 @@
from apps.ecm.models import Event, EventCate, Push, PushSetting from apps.ecm.models import Event, EventCate, Remind, NotifySetting
from apps.ecm.serializers import (EventCateListSerializer, EventCateUpdateSerializer, EventHandleSerializer, from apps.ecm.serializers import (EventCateListSerializer, EventCateUpdateSerializer, EventHandleSerializer,
EventSerializer, PushSerializer, PushSettingsSerializer) EventSerializer, RemindSerializer, NotifySettingsSerializer)
from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet
from rest_framework.mixins import UpdateModelMixin, ListModelMixin, RetrieveModelMixin from rest_framework.mixins import UpdateModelMixin, ListModelMixin, RetrieveModelMixin
from django.db import transaction from django.db import transaction
@ -19,9 +19,9 @@ class EventCateViewSet(UpdateModelMixin, ListModelMixin, CustomGenericViewSet):
update_serializer_class = EventCateUpdateSerializer update_serializer_class = EventCateUpdateSerializer
class PushSettingViewSet(CustomModelViewSet): class NotifySettingViewSet(CustomModelViewSet):
queryset = PushSetting.objects.all() queryset = NotifySetting.objects.all()
serializer_class = PushSettingsSerializer serializer_class = NotifySettingsSerializer
class EventViewSet(ListModelMixin, RetrieveModelMixin, CustomGenericViewSet): class EventViewSet(ListModelMixin, RetrieveModelMixin, CustomGenericViewSet):
@ -45,10 +45,10 @@ class EventViewSet(ListModelMixin, RetrieveModelMixin, CustomGenericViewSet):
return Response() return Response()
class PushViewSet(ListModelMixin, CustomGenericViewSet): class RemindViewSet(ListModelMixin, CustomGenericViewSet):
perms_map = {'get': 'push:view'} perms_map = {'get': 'envent:view'}
queryset = Push.objects.all() queryset = Remind.objects.all()
serializer_class = PushSerializer serializer_class = RemindSerializer
@action(methods=['get'], detail=False, perms_map={'get': '*'}) @action(methods=['get'], detail=False, perms_map={'get': '*'})
def my(self, request, *args, **kwargs): def my(self, request, *args, **kwargs):
@ -56,7 +56,7 @@ class PushViewSet(ListModelMixin, CustomGenericViewSet):
推送给我的 推送给我的
""" """
user = self.request.user user = self.request.user
queryset = self.filter_queryset(self.get_queryset().filter(pusher=user)) queryset = self.filter_queryset(self.get_queryset().filter(recipient=user))
page = self.paginate_queryset(queryset) page = self.paginate_queryset(queryset)
if page is not None: if page is not None:

View File

@ -0,0 +1,108 @@
# Generated by Django 3.2.12 on 2022-06-14 05:00
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
initial = True
dependencies = [
('system', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='NotWorkRemark',
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='删除标记')),
('not_work_date', models.DateField(verbose_name='未打卡日期')),
('remark', models.CharField(blank=True, max_length=200, null=True, verbose_name='未打卡说明')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='notworkremark_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='notworkremark_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='用户')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='Employee',
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(choices=[('employee', '内部员工'), ('remployee', '相关方人员'), ('visitor', '访客')], default='employee', max_length=10, verbose_name='人员类型')),
('name', models.CharField(max_length=20, verbose_name='姓名')),
('phone', models.CharField(blank=True, max_length=11, null=True, unique=True, verbose_name='手机号')),
('email', models.EmailField(blank=True, max_length=254, null=True, verbose_name='邮箱号')),
('number', models.CharField(blank=True, max_length=50, null=True, verbose_name='人员编号')),
('photo', models.CharField(blank=True, max_length=1000, null=True, verbose_name='证件照')),
('id_number', models.CharField(blank=True, max_length=100, null=True, unique=True, verbose_name='身份证号')),
('gender', models.CharField(default='', max_length=10, verbose_name='性别')),
('signature', models.CharField(blank=True, max_length=200, null=True, verbose_name='签名图片')),
('birthday', models.DateField(blank=True, null=True, verbose_name='出生年月日')),
('qualification', models.CharField(blank=True, max_length=50, null=True, verbose_name='学历')),
('job_state', models.IntegerField(choices=[(10, '在职'), (20, '离职')], default=1, verbose_name='在职状态')),
('face_data', models.JSONField(blank=True, null=True, verbose_name='人脸识别数据')),
('is_atwork', models.BooleanField(default=False, verbose_name='当前在岗')),
('show_atwork', models.BooleanField(default=True, verbose_name='是否展示在岗状态')),
('last_check_time', models.DateTimeField(blank=True, null=True, verbose_name='打卡时间')),
('not_work_remark', models.CharField(blank=True, max_length=200, null=True, verbose_name='当前未打卡说明')),
('third_info', models.JSONField(blank=True, default=dict, verbose_name='三方信息')),
('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='employee_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='employee_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='employee_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
('user', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL, verbose_name='系统账号')),
],
options={
'verbose_name': '员工补充信息',
'verbose_name_plural': '员工补充信息',
},
),
migrations.CreateModel(
name='ClockRecord',
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, '上班打卡')], default=10, verbose_name='打卡类型')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='clockrecord_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='clockrecord_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='Certificate',
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=20, verbose_name='证书名称')),
('number', models.CharField(max_length=20, unique=True, verbose_name='证书编号')),
('type', models.PositiveSmallIntegerField(default=10, verbose_name='证书类型')),
('issue_date', models.DateField(verbose_name='发证日期')),
('expiration_date', models.DateField(verbose_name='有效期')),
('review_date', models.DateField(verbose_name='下一次复审日期')),
('file', 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='certificate_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('employee', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='hrm.employee', verbose_name='对应人员')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='certificate_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
],
options={
'abstract': False,
},
),
]

View File

@ -0,0 +1,22 @@
# Generated by Django 3.2.12 on 2022-06-17 03:24
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('hrm', '0001_initial'),
]
operations = [
migrations.RemoveField(
model_name='employee',
name='face_data',
),
migrations.AlterField(
model_name='employee',
name='job_state',
field=models.IntegerField(choices=[(10, '在职'), (20, '离职')], default=10, verbose_name='在职状态'),
),
]

View File

View File

@ -24,17 +24,16 @@ class Employee(CommonBModel):
verbose_name='系统账号', verbose_name='系统账号',
on_delete=models.PROTECT, null=True, blank=True) on_delete=models.PROTECT, null=True, blank=True)
name = models.CharField('姓名', max_length=20) name = models.CharField('姓名', max_length=20)
phone = models.CharField('手机号', max_length=11, null=True, blank=True) phone = models.CharField('手机号', max_length=11, null=True, blank=True, unique=True)
email = models.EmailField('邮箱号', null=True, blank=True) email = models.EmailField('邮箱号', null=True, blank=True)
number = models.CharField('人员编号', max_length=50, null=True, blank=True) number = models.CharField('人员编号', max_length=50, null=True, blank=True)
photo = models.CharField('证件照', max_length=1000, null=True, blank=True) photo = models.CharField('证件照', max_length=1000, null=True, blank=True)
id_number = models.CharField('身份证号', max_length=100, null=True, blank=True) id_number = models.CharField('身份证号', max_length=100, null=True, blank=True, unique=True)
gender = models.CharField('性别', max_length=10, default='') gender = models.CharField('性别', max_length=10, default='')
signature = models.CharField('签名图片', max_length=200, null=True, blank=True) signature = models.CharField('签名图片', max_length=200, null=True, blank=True)
birthday = models.DateField('出生年月日', null=True, blank=True) birthday = models.DateField('出生年月日', null=True, blank=True)
qualification = models.CharField('学历', max_length=50, null=True, blank=True) qualification = models.CharField('学历', max_length=50, null=True, blank=True)
job_state = models.IntegerField('在职状态', choices=jobstate_choices, default=1) job_state = models.IntegerField('在职状态', choices=jobstate_choices, default=10)
face_data = models.JSONField('人脸识别数据', null=True, blank=True)
is_atwork = models.BooleanField('当前在岗', default=False) is_atwork = models.BooleanField('当前在岗', default=False)
show_atwork = models.BooleanField('是否展示在岗状态', default=True) show_atwork = models.BooleanField('是否展示在岗状态', default=True)
last_check_time = models.DateTimeField('打卡时间', null=True, blank=True) last_check_time = models.DateTimeField('打卡时间', null=True, blank=True)
@ -88,9 +87,9 @@ class Certificate(CommonAModel):
) )
employee = models.ForeignKey(Employee, verbose_name='对应人员', on_delete=models.CASCADE) employee = models.ForeignKey(Employee, verbose_name='对应人员', on_delete=models.CASCADE)
name = models.CharField('证书名称', max_length=20) name = models.CharField('证书名称', max_length=20)
number = models.CharField('证书编号', max_length=20) number = models.CharField('证书编号', max_length=20, unique=True)
type = models.PositiveSmallIntegerField('证书类型', default=10) type = models.PositiveSmallIntegerField('证书类型', default=10)
issue_date = models.DateField('发证日期') issue_date = models.DateField('发证日期')
expiration_date = models.DateField('有效期') expiration_date = models.DateField('有效期')
review_date = models.DateField('下一次复审日期') review_date = models.DateField('下一次复审日期')
file = models.CharField('文件地址', max_length=1000, null=True, blank=True) file = models.TextField('文件地址', null=True, blank=True)

View File

@ -12,6 +12,7 @@ from apps.third.clients import dhClient
from apps.third.tapis import dhapis from apps.third.tapis import dhapis
import re import re
from datetime import datetime from datetime import datetime
from django.conf import settings
class EmployeeBaseSerializer(CustomModelSerializer): class EmployeeBaseSerializer(CustomModelSerializer):
@ -35,8 +36,7 @@ class EmployeeCreateUpdateSerializer(EmployeeBaseSerializer):
class Meta: class Meta:
model = Employee model = Employee
exclude = EXCLUDE_FIELDS + ['face_data', exclude = EXCLUDE_FIELDS + ['is_atwork', 'last_check_time',
'is_atwork', 'last_check_time',
'not_work_remark', 'third_info', 'type'] 'not_work_remark', 'third_info', 'type']
extra_kwargs = { extra_kwargs = {
'phone': {'required': True}, 'phone': {'required': True},
@ -48,7 +48,7 @@ class EmployeeCreateUpdateSerializer(EmployeeBaseSerializer):
@transaction.atomic @transaction.atomic
def create(self, validated_data): def create(self, validated_data):
instance = super().create(validated_data) instance = super().create(validated_data)
if dhClient: if settings.DAHUA_ENABLED and dhClient:
# 创建人员 # 创建人员
_, res = dhClient.request(**dhapis['person_gen_id']) _, res = dhClient.request(**dhapis['person_gen_id'])
personId = res['id'] personId = res['id']
@ -118,7 +118,7 @@ class EmployeeCreateUpdateSerializer(EmployeeBaseSerializer):
departmentId = instance.belong_dept.third_info['dh_id'] departmentId = instance.belong_dept.third_info['dh_id']
except Exception: except Exception:
pass pass
if dhClient: if settings.DAHUA_ENABLED and dhClient:
third_info = instance.third_info third_info = instance.third_info
dh_id = instance.third_info['dh_id'] dh_id = instance.third_info['dh_id']
dh_photo = third_info['dh_photo'] dh_photo = third_info['dh_photo']
@ -192,7 +192,7 @@ class EmployeeSerializer(EmployeeBaseSerializer):
class Meta: class Meta:
model = Employee model = Employee
exclude = ['face_data'] fields = '__all__'
read_only_fields = ['is_atwork', 'last_check_time', 'not_work_remark'] read_only_fields = ['is_atwork', 'last_check_time', 'not_work_remark']

View File

@ -8,9 +8,17 @@ from apps.hrm.models import Employee
def updateEmployee(sender, instance, created, **kwargs): def updateEmployee(sender, instance, created, **kwargs):
# if created: # if created:
# 如果账号所属部门有变动, 更新关联人员的所属部门, 只限内部人员 # 如果账号所属部门有变动, 更新关联人员的所属部门, 只限内部人员
if not instance.is_superuser: if not instance.is_superuser and instance.type == 'employee':
ep = Employee.objects.filter(user=instance).first() ep = Employee.objects.filter(user=instance).first()
if ep and ep.type == 'employee': if ep:
if ep.belong_dept and ep.belong_dept != instance.belong_dept: if ep.belong_dept and ep.belong_dept != instance.belong_dept:
ep.belong_dept = instance.belong_dept ep.belong_dept = instance.belong_dept
ep.save() ep.save()
else:
Employee.objects.get_or_create(user=instance,
defaults={
"user": instance,
"name": instance.name,
"phone": instance.phone,
"belong_dept": instance.belong_dept
})

View File

@ -30,7 +30,7 @@ class EmployeeViewSet(CustomModelViewSet):
""" """
人员管理 人员管理
""" """
queryset = Employee.objects.all() queryset = Employee.objects.filter(type='employee')
select_related_fields = ['user'] select_related_fields = ['user']
filterset_class = EmployeeFilterSet filterset_class = EmployeeFilterSet
serializer_class = EmployeeSerializer serializer_class = EmployeeSerializer

View File

@ -1,34 +1,38 @@
from django.db import models from django.db import models
from apps.system.models import Dept, Dictionary, User from apps.hrm.models import Certificate
from apps.utils.models import BaseModel, CommonAModel, CommonBModel from apps.system.models import Dept, Dictionary, File, User
from apps.utils.models import BaseModel, CommonADModel, CommonAModel, CommonBDModel, CommonBModel
from apps.am.models import Area from apps.am.models import Area
from apps.wf.models import Ticket, Workflow from apps.wf.models import Ticket, Workflow
# Create your models here. # Create your models here.
class OptCate(CommonAModel): class OplCate(CommonAModel):
""" """
作业种类 作业许可种类
""" """
code = models.CharField('标识', max_length=10, unique=True) code = models.CharField('标识', max_length=10, unique=True)
name = models.CharField('名称', max_length=20, unique=True) name = models.CharField('名称', max_length=20, unique=True)
description = models.TextField('描述', null=True, blank=True)
workflow = models.ForeignKey(Workflow, verbose_name='使用的工作流')
template_export = models.TextField('导出word模板', null=True, blank=True) template_export = models.TextField('导出word模板', null=True, blank=True)
workflow = models.ForeignKey(Workflow, verbose_name='所用工作流', risk_options = models.ManyToManyField(Dictionary, verbose_name='风险分析')
on_delete=models.CASCADE, null=True, blank=True) measure_options = models.ManyToManyField(Dictionary, verbose_name='控制措施')
close_options = models.ManyToManyField(Dictionary, verbose_name='关闭工作')
class Operation(CommonBModel): class Operation(CommonBDModel):
OP_CREATE = 10
OP_AUDIT = 20
OP_WAIT = 30
OP_WORK = 40
OP_CLOSE = 50
OP_STATE_CHOICES = ( OP_STATE_CHOICES = (
(10, '创建中'), (OP_CREATE, '创建中'),
(20, '审批中'), (OP_AUDIT, '审批中'),
(30, '待作业'), (OP_WAIT, '待作业'),
(40, '待关闭'), (OP_WORK, '作业中'),
(50, '已关闭') (OP_CLOSE, '已关闭')
)
OP_WORK_CHOICES = (
('work', '运行'),
('stop', '停机'),
('repair', '检修')
) )
number = models.CharField('作业编号', max_length=20, null=True, blank=True) number = models.CharField('作业编号', max_length=20, null=True, blank=True)
name = models.CharField('作业简述', max_length=200) name = models.CharField('作业简述', max_length=200)
@ -37,33 +41,109 @@ class Operation(CommonBModel):
place = models.TextField('具体地点', null=True, blank=True) place = models.TextField('具体地点', null=True, blank=True)
start_time = models.DateTimeField('作业开始时间') start_time = models.DateTimeField('作业开始时间')
end_time = models.DateTimeField('作业结束时间') end_time = models.DateTimeField('作业结束时间')
dept_sd = models.ForeignKey(Dept, verbose_name='属地部门', dept_ter = models.ForeignKey(Dept, verbose_name='属地部门',
on_delete=models.CASCADE) on_delete=models.CASCADE)
dept_yw = models.ForeignKey(Dept, verbose_name='业务部门', dept_bus = models.ForeignKey(Dept, verbose_name='业务部门',
on_delete=models.CASCADE) on_delete=models.CASCADE)
user_xt = models.ForeignKey(User, verbose_name='业务部门协调员', coordinator = models.ForeignKey(User, verbose_name='业务部门协调员',
on_delete=models.CASCADE) on_delete=models.CASCADE)
user_fz = models.ForeignKey(User, verbose_name='作业负责人', state_work = models.CharField('生产状态', max_length=20, help_text='运行/停机/检修')
on_delete=models.CASCADE)
user_jh = models.ForeignKey(User, verbose_name='作业监护人',
)
state_work = models.CharField('生产状态', choices=OP_WORK_CHOICES)
class Opt(CommonBModel): class Opl(CommonBDModel):
""" """
作业 作业许可证
""" """
CLOSE_CHOICES1 = (
(10, '作业正常结束'),
(20, '因计划改变停止作业'),
(30, '因发生异常终止作业'),
(40, '其他')
)
operation = models.ForeignKey(Operation, verbose_name='关联作业', operation = models.ForeignKey(Operation, verbose_name='关联作业',
on_delete=models.CASCADE) on_delete=models.CASCADE, related_name='opl_operation')
number = models.CharField('作业票编号', max_length=20, null=True, blank=True) number = models.CharField('作业许可编号', max_length=20, null=True, blank=True)
cate = models.ForeignKey(OptCate, verbose_name='作业票种类', level = models.CharField('作业级别', max_length=20,
help_text='特技/三级/二级/主干道/次干道', null=True, blank=True)
cate = models.ForeignKey(OplCate, verbose_name='作业许可种类',
on_delete=models.CASCADE) on_delete=models.CASCADE)
dept_zy = models.ForeignKey(Dept, verbose_name='作业部门', start_time = models.DateTimeField('作业开始时间', null=True, blank=True)
end_time = models.DateTimeField('作业结束时间', null=True, blank=True)
dept_do = models.ForeignKey(Dept, verbose_name='作业部门',
on_delete=models.CASCADE) on_delete=models.CASCADE)
user_fz = models.ForeignKey(User, verbose_name='作业负责人', charger = models.ForeignKey(User, verbose_name='作业负责人',
on_delete=models.CASCADE) on_delete=models.CASCADE, related_name='opl_charger')
user_jh = models.ForeignKey(User, verbose_name='作业监护人', monitor = models.ForeignKey(User, verbose_name='作业监护人',
) on_delete=models.CASCADE, related_name='opl_monitor')
ticket = models.ForeignKey(Ticket, verbose_name='关联工单', # electrician = models.ForeignKey(User, verbose_name='电工',
on_delete=models.CASCADE, null=True, blank=True) # on_delete=models.CASCADE,
# related_name='opl_electrician', null=True, blank=True)
work_time = models.DateTimeField('安装/拆除时间', null=True, blank=True)
accept_time = models.DateTimeField('验收时间', null=True, blank=True)
work_type = models.CharField('安装/拆除', max_length=20, null=True, blank=True)
power = models.PositiveIntegerField('用电功率', null=True, blank=True)
power_to = models.CharField('用电地点', max_length=20, null=True, blank=True)
power_from = models.CharField('电源接入点', max_length=20, null=True, blank=True)
power_end_time = models.DateTimeField('用电截至', null=True, blank=True)
power_start_time = models.DateTimeField('用电开始', null=True, blank=True)
power_days = models.PositiveSmallIntegerField('计划用电天数', null=True, blank=True)
other_risk = models.TextField('其他风险', null=True, blank=True)
other_emr = models.TextField('其他应急处置', null=True, blank=True)
escape_route = models.TextField('逃生路径', null=True, blank=True)
risks_checked = models.JSONField('风险选择', default=list, null=False, blank=True)
measures_checked = models.JSONField('措施选择', default=list, null=False, blank=True)
workers = models.ManyToManyField(User, verbose_name='作业人员', through='opm.oplworker')
create_imgs = models.ManyToManyField(File, verbose_name='作业审批照片')
close_imgs = models.ManyToManyField(File, verbose_name='作业关闭照片')
close_note = models.PositiveSmallIntegerField('作业关闭情况',
choices=CLOSE_CHOICES1,
help_text='正常结束/计划改变停止/发生异常停止/其他',
null=True, blank=True)
close_dos = models.JSONField('关闭工作', default=list, null=False, blank=True)
close_desc = models.TextField('作业关闭描述', null=True, blank=True)
ticket = models.OneToOneField(Ticket, verbose_name='关联工单',
on_delete=models.CASCADE,
null=True, blank=True)
class OplWorker(BaseModel):
"""
作业许可人员
"""
worker = models.ForeignKey(User, verbose_name='作业人员',
on_delete=models.CASCADE)
opl = models.ForeignKey(Opl, verbose_name='作业许可',
on_delete=models.CASCADE)
duty = models.CharField('工作职责', null=True, blank=True, help_text='作业人员/起重司机/司索人员/起重指挥/电工')
certificates = models.ManyToManyField(Certificate, verbose_name='关联证书', through='opt.optcert')
class OplCert(BaseModel):
"""
作业许可人员证书
"""
opl_worker = models.ForeignKey(OplWorker, verbose_name='关联作业人员',
on_delete=models.CASCADE)
certificate = models.ForeignKey(Certificate, verbose_name='关联证书',
on_delete=models.CASCADE)
name = models.CharField('证书名称', max_length=20)
number = models.CharField('证书编号', max_length=20)
type = models.PositiveSmallIntegerField('证书类型', default=10)
issue_date = models.DateField('发证日期')
expiration_date = models.DateField('有效期')
review_date = models.DateField('下一次复审日期')
file = models.TextField('文件地址', null=True, blank=True)
class GasCheck(CommonADModel):
"""
气体检测记录
"""
check_time = models.DateTimeField('检测时间')
check_place = models.CharField('检测部位')
o2 = models.DecimalField(decimal_places=1, max_digits=3)
co = models.PositiveSmallIntegerField()
lel = models.DecimalField(decimal_places=1, max_digits=3)
is_ok = models.BooleanField('是否正常', default=True)
checker = models.ForeignKey(User, verbose_name='检测人')
opl = models.ForeignKey(Opl, verbose_name='关联作业许可')

View File

@ -1,30 +1,118 @@
from apps.opm.models import Operation, OptCate from apps.hrm.models import Certificate
from apps.opm.models import GasCheck, Operation, Opl, OplCate, OplCert, OplWorker
from apps.utils.serializers import CustomModelSerializer from apps.utils.serializers import CustomModelSerializer
from apps.wf.serializers import WorkflowSimpleSerializer
from apps.utils.constants import EXCLUDE_FIELDS from apps.utils.constants import EXCLUDE_FIELDS
from rest_framework import serializers
from django.db import transaction
from rest_framework.exceptions import ParseError
class OptCateCreateUpdateSerializer(CustomModelSerializer): class OplCateCreateUpdateSerializer(CustomModelSerializer):
class Meta: class Meta:
model = OptCate model = OplCate
fields = ['code', 'name', 'template_export', 'workflow'] fields = ['code', 'name', 'template_export', 'workflow']
class OptCateSerializer(CustomModelSerializer): class OplCateSerializer(CustomModelSerializer):
workflow_ = WorkflowSimpleSerializer(source='workflow', read_only=True)
class Meta: class Meta:
model = OptCate model = OplCate
fields = '__all__' fields = '__all__'
class OperationCreateUpdateSerializer(CustomModelSerializer): class OperationCreateUpdateSerializer(CustomModelSerializer):
class Meta: class Meta:
model = Operation model = Operation
fields = EXCLUDE_FIELDS + ['number'] exclude = EXCLUDE_FIELDS + ['number']
class OperationSerializer(CustomModelSerializer): class OperationSerializer(CustomModelSerializer):
class Meta: class Meta:
model = Operation model = Operation
fields = "__all__" fields = "__all__"
class OplWorkerCreateSerializer(CustomModelSerializer):
certificates = serializers.PrimaryKeyRelatedField(label='证书ID', many=True)
class Meta:
model = OplWorker
fields = ['worker', 'duty', 'certificates', 'opl']
def create(self, validated_data):
certificates = validated_data.pop('certificates')
if OplWorker.objects.filter(worker=validated_data['worker'], opl=validated_data['opl']).exists():
raise ParseError('该成员已加入')
with transaction.atomic():
oplw = super().create(validated_data)
for x in certificates:
oplc, _ = OplCert.objects.get_or_create(opl_worker=oplw, certificate=x,
defaults={'opl_worker': oplw, 'certificate': x})
for f in Certificate._meta.fields:
if f.name not in ['id']:
setattr(oplc, f.name, getattr(x, f.name, None))
oplc.save()
return oplw
class OplWorkerUpdateSerializer(CustomModelSerializer):
certificates = serializers.PrimaryKeyRelatedField(label='证书ID', many=True)
class Meta:
model = OplWorker
fields = ['duty', 'certificates']
def update(self, instance, validated_data):
certificates = validated_data.pop('certificates')
with transaction.atomic():
oplw = super().update(instance, validated_data)
for x in certificates:
oplc, _ = OplCert.objects.get_or_create(opl_worker=oplw, certificate=x,
defaults={'opl_worker': oplw, 'certificate': x})
for f in Certificate._meta.fields:
if f.name not in ['id']:
setattr(oplc, f.name, getattr(x, f.name, None))
oplc.save()
return oplw
class OplWorkerSerializer():
class Meta:
model = OplWorker
fields = '__all__'
class GasCheckCreateUpdateSerializer(CustomModelSerializer):
class Meta:
model = GasCheck
exclude = EXCLUDE_FIELDS
class GasCheckSerializer(CustomModelSerializer):
class Meta:
model = GasCheck
fields = '__all__'
class OplCreateUpdateSerializer(CustomModelSerializer):
class Meta:
model = Opl
fields = ['operation', 'level', 'cate', 'start_time', 'end_time',
'dept_do', 'charger', 'monitor', 'work_time', 'work_type',
'accept_time', 'power', 'power_to', 'power_from',
'power_end_time', 'power_start_time', 'power_days',
'other_risk', 'other_emr', 'escape_route',
'risks_checked', 'measures_checked', 'create_imgs']
class OplSerializer(CustomModelSerializer):
class Meta:
model = Opl
fields = '__all__'
class OplCloseSerializer(CustomModelSerializer):
class Meta:
model = Opl
fields = ['close_imgs', 'close_note', 'close_dos', 'close_desc']

View File

@ -1,5 +1,28 @@
from apps.wf.models import Ticket from apps.opm.models import Operation, Opl
from apps.opm.serializers import OplCloseSerializer
from apps.wf.models import Ticket, Transition
def create_opt(ticket: Ticket): def bind_opl(ticket: Ticket, transition: Transition, new_ticket_data: dict):
pass opl = Opl.objects.get(id=new_ticket_data['opl'])
ticket_data = ticket.ticket_data
ticket_data.update({'level': opl.level})
ticket.ticket_data = ticket_data
ticket.save()
opl.ticket = opl
opl.number = ticket.sn
opl.save()
def close_opl_submit(ticket: Ticket, transition: Transition, new_ticket_data: dict):
opl = Opl.objects.get(ticket=ticket)
serializer = OplCloseSerializer(instance=opl, data=new_ticket_data, partial=True)
serializer.is_valid(raise_exception=True)
serializer.save()
def give_perm_by_opl():
"""
根据许可证授予区域进入权限
"""
pass

44
apps/opm/tasks.py Normal file
View File

@ -0,0 +1,44 @@
# Create your tasks here
from __future__ import absolute_import, unicode_literals
from apps.opm.models import Operation, Opl
from apps.opm.services import give_perm_by_opl
from apps.utils.task import CustomTask
from celery import shared_task
from apps.wf.models import State, Ticket
@shared_task(base=CustomTask)
def opl_end(ticket_id):
"""
作业关闭时执行
"""
ticket = Ticket.objects.get(id=ticket_id)
operation = ticket.opl.operation
opls = Opl.objects.filter(operation=operation)
opls.filter(ticket=None).delete() # 删除无用许可证
states = opls.values_list('ticket__state__type', flat=True)
if 0 in states or 1 in states:
pass
else:
operation.state = Operation.OP_CLOSE
operation.save()
@shared_task(base=CustomTask)
def opl_audit_start(ticket_id):
operation = Opl.objects.get(ticket__id=ticket_id).operation
if operation.state == Operation.OP_CREATE:
operation.state = Operation.OP_AUDIT
operation.save()
@shared_task(base=CustomTask)
def opl_audit_end(ticket_id):
opl = Opl.objects.get(ticket__id=ticket_id)
operation = opl.operation
if operation.state == Operation.OP_AUDIT:
operation.state = Operation.OP_WORK
operation.save()
# 授予区域或围栏权限
give_perm_by_opl(opl)

View File

@ -1,19 +1,108 @@
from django.shortcuts import render from django.shortcuts import render
from apps.opm.models import Operation, OptCate from rest_framework.response import Response
from apps.opm.serializers import OperationCreateUpdateSerializer, OptCateCreateUpdateSerializer, OptCateSerializer from apps.opm.models import GasCheck, Operation, Opl, OplCate, OplWorker
from apps.utils.viewsets import CustomModelViewSet from apps.opm.serializers import GasCheckCreateUpdateSerializer, GasCheckSerializer, OperationCreateUpdateSerializer, OperationSerializer, OplCateCreateUpdateSerializer, OplCateSerializer, OplSerializer, OplWorkerCreateSerializer, OplWorkerUpdateSerializer
from apps.opm.services import create_opl_ticket
from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet
from rest_framework.exceptions import ParseError
from rest_framework.mixins import CreateModelMixin, ListModelMixin, DestroyModelMixin
from rest_framework.decorators import action
from rest_framework import serializers
from django.db import transaction
# Create your views here. # Create your views here.
class OptCateViewSet(CustomModelViewSet): class OplCateViewSet(CustomModelViewSet):
queryset = OptCate.objects.all() queryset = OplCate.objects.all()
create_serializer_class = OptCateCreateUpdateSerializer create_serializer_class = OplCateCreateUpdateSerializer
update_serializer_class = OptCateCreateUpdateSerializer update_serializer_class = OplCateCreateUpdateSerializer
serializer_class = OptCateSerializer serializer_class = OplCateSerializer
class OperationViewSet(CustomModelViewSet): class OperationViewSet(CustomModelViewSet):
queryset = Operation.objects.all() queryset = Operation.objects.all()
create_serializer_class = OperationCreateUpdateSerializer create_serializer_class = OperationCreateUpdateSerializer
update_serializer_class = OperationCreateUpdateSerializer update_serializer_class = OperationCreateUpdateSerializer
serializer_class = OperationSerializer
def update(self, request, *args, **kwargs):
obj = self.get_object()
if obj.state != Operation.OP_CREATE:
raise ParseError('非创建状态不可修改')
return super().update(request, *args, **kwargs)
def destroy(self, request, *args, **kwargs):
obj = self.get_object()
if obj.state != Operation.OP_CREATE:
raise ParseError('非创建状态不可删除')
obj.delete(soft=False)
return Response(status=204)
class OplViewSet(CustomModelViewSet):
queryset = Opl.objects.all()
create_serializer_class = OplCateCreateUpdateSerializer
update_serializer_class = OplCateCreateUpdateSerializer
serializer_class = OplSerializer
def destroy(self, request, *args, **kwargs):
obj = self.get_object()
if obj.ticket:
raise ParseError('许可证已处理不可删除')
return super().destroy(request, *args, **kwargs)
def create(self, request, *args, **kwargs):
obj = self.get_object()
if obj.operation.state == Operation.OP_CLOSE:
raise ParseError('作业已关闭不可创建许可')
return super().create(request, *args, **kwargs)
def update(self, request, *args, **kwargs):
obj = self.get_object()
if obj.ticket:
raise ParseError('许可证已处理不可编辑')
return super().update(request, *args, **kwargs)
class OplWorkerViewSet(CustomModelViewSet):
perms_map = {'get': '*', 'post': 'opl:update', 'put': 'opl:update', 'delete': 'opl:update'}
queryset = OplWorker.objects.all()
create_serializer_class = OplWorkerCreateSerializer
update_serializer_class = OplWorkerUpdateSerializer
serializer_class = OplSerializer
def create(self, request, *args, **kwargs):
obj = self.get_object()
if obj.opl.ticket:
raise ParseError('许可证已处理不可新增')
return super().create(request, *args, **kwargs)
def destroy(self, request, *args, **kwargs):
obj = self.get_object()
if obj.opl.ticket:
raise ParseError('许可证已处理不可删除')
return super().destroy(request, *args, **kwargs)
def update(self, request, *args, **kwargs):
obj = self.get_object()
if obj.opl.ticket:
raise ParseError('许可证已处理不可编辑')
return super().update(request, *args, **kwargs)
class GasCheckViewSet(CreateModelMixin, ListModelMixin, DestroyModelMixin, CustomGenericViewSet):
perms_map = {'get': '*', 'post': 'opl:update', 'delete': 'opl:update'}
queryset = GasCheck.objects.all()
create_serializer_class = GasCheckCreateUpdateSerializer
serializer_class = GasCheckSerializer
def create(self, request, *args, **kwargs):
obj = self.get_object()
if obj.opl.ticket:
raise ParseError('许可证已处理不可新增')
return super().create(request, *args, **kwargs)
def destroy(self, request, *args, **kwargs):
obj = self.get_object()
if obj.opl.ticket:
raise ParseError('许可证已处理不可删除')
return super().destroy(request, *args, **kwargs)

View File

@ -1,7 +1,8 @@
from django.db import models from django.db import models
from apps.hrm.models import Certificate, Employee from apps.hrm.models import Certificate, Employee
from apps.system.models import Dept, Dictionary, File, User from apps.system.models import Dept, Dictionary, File, User
from apps.utils.models import CommonBModel, BaseModel from apps.utils.models import CommonAModel, CommonBDModel, CommonBModel, BaseModel
from apps.wf.models import Ticket
# Create your models here. # Create your models here.
@ -20,7 +21,6 @@ class Rparty(CommonBModel):
email = models.EmailField('邮箱', null=True, blank=True) email = models.EmailField('邮箱', null=True, blank=True)
addresss = models.CharField('企业地址', max_length=200, null=True, blank=True) addresss = models.CharField('企业地址', max_length=200, null=True, blank=True)
description = models.TextField('概述', null=True, blank=True) description = models.TextField('概述', null=True, blank=True)
# belong_dept是归属部门
class RpartyFile(BaseModel): class RpartyFile(BaseModel):
@ -33,15 +33,15 @@ class RpartyFile(BaseModel):
rparty = models.ForeignKey(Rparty, verbose_name='关联相关方', on_delete=models.CASCADE) rparty = models.ForeignKey(Rparty, verbose_name='关联相关方', on_delete=models.CASCADE)
class Rproject(CommonBModel): class Rpj(CommonBDModel):
""" """
相关方项目 相关方项目
""" """
RP_START = 10 RPJ_CREATE = 10
RP_APPROVAL = 20 RPJ_AUDIT = 20
RP_ENTER = 30 RPJ_ENTER = 30
RP_WORKING = 40 RPJ_WORKING = 40
RP_DONE = 50 RPJ_DONE = 50
RP_STATE_CHOICES = ( RP_STATE_CHOICES = (
(10, '创建中'), (10, '创建中'),
(20, '审批中'), (20, '审批中'),
@ -63,45 +63,72 @@ class Rproject(CommonBModel):
state = models.PositiveSmallIntegerField('状态', default=10) state = models.PositiveSmallIntegerField('状态', default=10)
rparty = models.ForeignKey(Rparty, verbose_name='关联相关方', on_delete=models.CASCADE) rparty = models.ForeignKey(Rparty, verbose_name='关联相关方', on_delete=models.CASCADE)
# belong_dept是业务部门可以带过来 # belong_dept是业务部门可以带过来
ticket = models.ForeignKey(Ticket, verbose_name='关联工单',
on_delete=models.CASCADE, null=True, blank=True)
class RprojectFile(BaseModel): class RpjFile(BaseModel):
""" """
相关方项目文件库 相关方项目文件库
""" """
file_cate = models.ForeignKey(Dictionary, verbose_name='文件种类', file_cate = models.ForeignKey(Dictionary, verbose_name='文件种类',
on_delete=models.CASCADE, null=True, blank=True) on_delete=models.CASCADE, null=True, blank=True)
files = models.ManyToManyField(File, verbose_name='文件') files = models.ManyToManyField(File, verbose_name='文件')
rproject = models.ForeignKey(Rproject, verbose_name='关联相关方项目', on_delete=models.CASCADE) rpj = models.ForeignKey(Rpj, verbose_name='关联相关方项目', on_delete=models.CASCADE)
class Remployee(CommonBModel): class Remployee(CommonAModel):
""" """
相关方成员 相关方成员
""" """
employee = models.OneToOneField(Employee, verbose_name='成员信息', on_delete=models.CASCADE) employee = models.ForeignKey(Employee, verbose_name='成员信息',
rparty = models.ForeignKey(Rparty, verbose_name='所属相关方', on_delete=models.CASCADE)
rproject = models.ForeignKey(Rproject, verbose_name='当前所属相关方项目', on_delete=models.CASCADE,
null=True, blank=True)
class Rpeople(BaseModel):
"""
相关方项目人员
"""
rproject = models.ForeignKey(Rproject, verbose_name='关联项目', on_delete=models.CASCADE)
employee = models.ForeignKey(Employee, verbose_name='关联人员',
on_delete=models.CASCADE, null=True, blank=True) on_delete=models.CASCADE, null=True, blank=True)
name = models.CharField('姓名', max_length=20)
phone = models.CharField('手机号', max_length=11)
photo = models.CharField('证件照', max_length=1000)
id_number = models.CharField('身份证号', max_length=100)
rparty = models.ForeignKey(Rparty, verbose_name='所属相关方', on_delete=models.CASCADE)
rpj = models.ForeignKey(Rpj, verbose_name='最近所属相关方项目', on_delete=models.CASCADE,
null=True, blank=True)
class Rcertificate(CommonAModel):
"""
相关方证书
"""
certificate = models.ForeignKey(Certificate, verbose_name='关联认可证书',
on_delete=models.CASCADE,
null=True, blank=True)
remployee = models.ForeignKey(Remployee, verbose_name='关联相关方成员',
on_delete=models.CASCADE)
name = models.CharField('证书名称', max_length=20)
number = models.CharField('证书编号', max_length=20, unique=True)
type = models.PositiveSmallIntegerField('证书类型', default=10, choices=Certificate.CERTIFICATE_TYPE_CHOICES)
issue_date = models.DateField('发证日期')
expiration_date = models.DateField('有效期')
review_date = models.DateField('下一次复审日期')
file = models.CharField('文件地址', max_length=1000, null=True, blank=True)
class Rpjmember(BaseModel):
"""
相关方项目成员
"""
rpj = models.ForeignKey(Rpj, verbose_name='关联项目', on_delete=models.CASCADE)
remployee = models.ForeignKey(Remployee, verbose_name='关联人员',
on_delete=models.CASCADE, null=True, blank=True)
duty = models.CharField('职责', max_length=20, null=True, blank=True)
is_manager = models.BooleanField('是否项目负责人', default=False) is_manager = models.BooleanField('是否项目负责人', default=False)
rcertificates = models.ManyToManyField(Rcertificate, through='rpm.rpjcertificate')
class Rcertificate(BaseModel): class Rpjcertificate(BaseModel):
""" """
相关方项目人员证书 相关方项目人员证书
""" """
rproject = models.ForeignKey(Rproject, verbose_name='关联项目', on_delete=models.CASCADE) rpj_member = models.ForeignKey(Rpjmember, verbose_name='关联项目成员', on_delete=models.CASCADE)
employee = models.ForeignKey(Employee, verbose_name='关联人员', rcertificate = models.ForeignKey(Rcertificate, verbose_name='关联相关方证书', on_delete=models.CASCADE,
on_delete=models.CASCADE, null=True, blank=True) null=True, blank=True)
name = models.CharField('证书名称', max_length=20) name = models.CharField('证书名称', max_length=20)
number = models.CharField('证书编号', max_length=20) number = models.CharField('证书编号', max_length=20)
type = models.PositiveSmallIntegerField('证书类型', default=10, choices=Certificate.CERTIFICATE_TYPE_CHOICES) type = models.PositiveSmallIntegerField('证书类型', default=10, choices=Certificate.CERTIFICATE_TYPE_CHOICES)

View File

@ -1,11 +1,13 @@
from apps.hrm.models import Employee from apps.hrm.models import Certificate, Employee
from apps.hrm.serializers import phone_check from apps.hrm.serializers import phone_check
from apps.rpm.models import Rparty, Rpeople, Rproject from apps.rpm.models import Rcertificate, Remployee, Rparty, Rpjcertificate, Rpjmember, Rpj
from apps.system.models import Dept from apps.system.models import Dept
from apps.utils.constants import EXCLUDE_FIELDS from apps.utils.constants import EXCLUDE_FIELDS
from apps.utils.serializers import CustomModelSerializer from apps.utils.serializers import CustomModelSerializer
from apps.system.serializers import DictSerializer, FileSerializer from apps.system.serializers import DictSerializer, FileSerializer
from rest_framework import serializers from rest_framework import serializers
from rest_framework.exceptions import ParseError
from django.db import transaction
class RpartyCreateUpdateSerializer(CustomModelSerializer): class RpartyCreateUpdateSerializer(CustomModelSerializer):
@ -16,7 +18,7 @@ class RpartyCreateUpdateSerializer(CustomModelSerializer):
extra_kwargs = { extra_kwargs = {
'belong_dept': {'required': True} 'belong_dept': {'required': True}
} }
def create(self, validated_data): def create(self, validated_data):
instance = super().create(validated_data) instance = super().create(validated_data)
dept = Dept.objects.create(name=instance.name, dept = Dept.objects.create(name=instance.name,
@ -56,41 +58,118 @@ class RpartyFileListSerializer(CustomModelSerializer):
files_ = FileSerializer(source='files', many=True, read_only=True) files_ = FileSerializer(source='files', many=True, read_only=True)
class RprojectCreateUpdateSerializer(CustomModelSerializer): class RpjCreateUpdateSerializer(CustomModelSerializer):
class Meta: class Meta:
model = Rproject model = Rpj
fields = ['name', 'contract_number', 'type', 'come_time', 'leave_time', 'belong_dept'] fields = ['name', 'contract_number', 'type', 'come_time', 'leave_time', 'belong_dept', 'rparty']
class RprojectListSerializer(CustomModelSerializer): class RpjListSerializer(CustomModelSerializer):
class Meta: class Meta:
model = Rproject model = Rpj
fields = '__all__' fields = '__all__'
class RemployeeCreateUpdateSerializer(CustomModelSerializer): class RemployeeCreateSerializer(CustomModelSerializer):
phone = serializers.CharField(label="手机号", validators=[phone_check]) phone = serializers.CharField(label="手机号", validators=[phone_check])
rparty = serializers.PrimaryKeyRelatedField(queryset=Rparty.objects.all(), label='相关方ID', required=False) rparty = serializers.PrimaryKeyRelatedField(queryset=Rparty.objects.all(), label='相关方ID', required=False)
class Meta: class Meta:
model = Employee model = Remployee
exclude = EXCLUDE_FIELDS + ['face_data', fields = ['name', 'phone', 'photo', 'id_number']
'is_atwork', 'last_check_time', # model = Employee
'not_work_remark', 'third_info', 'type'] # exclude = EXCLUDE_FIELDS + ['is_atwork', 'last_check_time',
extra_kwargs = { # 'not_work_remark', 'third_info', 'type']
'phone': {'required': True}, # extra_kwargs = {
'number': {'required': True}, # 'phone': {'required': True},
'photo': {'required': True}, # 'number': {'required': True},
'id_number': {'required': True}, # 'photo': {'required': True},
} # 'id_number': {'required': True},
# }
class RpeopleCreatesSerializer(CustomModelSerializer): class RemployeeSerializer(CustomModelSerializer):
class Meta:
model = Remployee
fields = '__all__'
class RcertificateCreateUpdateSerializer(CustomModelSerializer):
class Meta:
model = Rcertificate
exclude = EXCLUDE_FIELDS + ['certificate']
class RcertificateSerializer(CustomModelSerializer):
class Meta:
model = Rcertificate
fields = '__all__'
class RpjmemberCreatesSerializer(CustomModelSerializer):
employees = serializers.PrimaryKeyRelatedField( employees = serializers.PrimaryKeyRelatedField(
queryset=Employee.objects.filter(type='remployee'), queryset=Employee.objects.filter(type='remployee'),
many=True, label='员工ID列表' many=True, label='员工ID列表'
) )
class Meta: class Meta:
model = Rpeople model = Rpjmember
fields = ['employees', 'rproject'] fields = ['employees', 'Rpj']
class RpjmemberCreateSerializer(CustomModelSerializer):
rcertificates = serializers.PrimaryKeyRelatedField(label='证书ID', many=True)
class Meta:
model = Rpjmember
fields = ['employee', 'rpj', 'duty', 'is_manager']
def create(self, validated_data):
rpj = validated_data['rpj']
if rpj.state != Rpj.RPJ_CREATE:
raise ParseError('成员非创建状态不可新增')
rcertificates = validated_data.pop('rcertificates')
if Rpjmember.objects.filter(remployee=validated_data['remployee'], rpj=validated_data['rpj']).exists():
raise ParseError('该成员已选择')
with transaction.atomic():
ins = super().create(validated_data)
for x in rcertificates:
rpjc, _ = Rpjcertificate.objects.get_or_create(rpj_member=ins, rcertificate=x,
defaults={'rpj_member': ins, 'rcertificate': x})
for f in Rcertificate._meta.fields:
if f.name not in ['id']:
setattr(rpjc, f.name, getattr(x, f.name, None))
rpjc.save()
if ins.is_manager:
Rpjmember.objects.exclude(id__in=ins.id).update(is_manager=False)
return ins
class RpjmemberUpdateSerializer(CustomModelSerializer):
rcertificates = serializers.PrimaryKeyRelatedField(label='证书ID', many=True)
class Meta:
model = Rpjmember
fields = ['duty', 'is_manager', 'rcertificates']
def update(self, instance, validated_data):
rpj = validated_data['rpj']
if rpj.state != Rpj.RPJ_CREATE:
raise ParseError('成员非创建状态不可修改')
rcertificates = validated_data.pop('rcertificates')
with transaction.atomic():
instance = super().update(instance, validated_data)
for x in rcertificates:
rpjc, _ = Rpjcertificate.objects.get_or_create(rpj_member=instance, rcertificate=x,
defaults={'rpj_member': instance, 'rcertificate': x})
for f in Rcertificate._meta.fields:
if f.name not in ['id']:
setattr(rpjc, f.name, getattr(x, f.name, None))
rpjc.save()
return instance
class RpjmemberSerializer(CustomModelSerializer):
class Meta:
model = Rpjmember
fields = '__all__'

13
apps/rpm/services.py Normal file
View File

@ -0,0 +1,13 @@
from apps.wf.models import Ticket, Transition
from apps.rpm.models import Rpj
def bind_opl(ticket: Ticket, transition: Transition, new_ticket_data: dict):
rpj = Rpj.objects.get(id=new_ticket_data['rpj'])
# ticket_data = ticket.ticket_data
# ticket_data.update({'level': opl.level})
# ticket.ticket_data = ticket_data
# ticket.save()
rpj.ticket = rpj
rpj.save()

54
apps/rpm/tasks.py Normal file
View File

@ -0,0 +1,54 @@
# Create your tasks here
from __future__ import absolute_import, unicode_literals
from apps.hrm.models import Certificate, Employee
from apps.rpm.models import Rcertificate, Remployee, Rpj, Rpjcertificate, Rpjmember
from apps.utils.task import CustomTask
from celery import shared_task
@shared_task(base=CustomTask)
def rpj_audit_start(ticket_id):
rpj = Rpj.objects.get(ticket__id=ticket_id)
if rpj.state == Rpj.RPJ_CREATE:
rpj.state = Rpj.RPJ_AUDIT
rpj.save()
@shared_task(base=CustomTask)
def rpj_audit_end(ticket_id):
rpj = Rpj.objects.get(ticket__id=ticket_id)
if rpj.state == Rpj.RPJ_AUDIT:
rpj.state = Rpj.RPJ_ENTER
rpj.save()
# 更新企业相关方人员库和证书库
for i in Rpjmember.objects.filter(rpj=rpj):
remployee = i.remployee
ep = Employee.objects.filter(id_number=remployee.id_number).first()
if ep:
pass
else:
ep = Employee()
ep.name = remployee.name
ep.phone = remployee.phone
ep.photo = remployee.photo
ep.id_number = remployee.id_number
ep.type = 'remployee'
ep.save()
remployee.employee = ep
remployee.save()
for i in Rpjcertificate.objects.filter(rpj_member__rpj=rpj):
ct = Certificate.objects.filter(number=i.number).first()
if ct:
pass
else:
ct = Certificate()
ct.name = i.name
ct.number = i.number
ct.type = i.type
ct.issue_date = i.issue_date
ct.expiration_date = i.expiration_date
ct.review_date = i.review_date
ct.file = i.file
ct.employee = i.rpj_member.remployee.employee
ct.save()

View File

@ -0,0 +1,18 @@
from apps.rpm.models import RpjFile
from apps.rpm.views import RpartyViewSet, RemployeeViewSet, RpartyFileViewSet, RpjViewSet, RpjmemberViewSet
from django.urls import path, include
from rest_framework.routers import DefaultRouter
API_BASE_URL = 'api/rpm/'
HTML_BASE_URL = 'rpm/'
router = DefaultRouter()
router.register('rparty', RpartyViewSet, basename='rparty')
router.register('remployee', RemployeeViewSet, basename='remployee')
router.register('rparty_file', RpartyFileViewSet, basename='rparty_file')
router.register('rpj', RpjViewSet, basename='rpj')
router.register('rpj_member', RpjmemberViewSet, basename='rpj_member')
router.register('rpj_file', RpjFile, basename='rpj_file')
urlpatterns = [
path(API_BASE_URL, include(router.urls)),
]

View File

@ -1,11 +1,12 @@
from django.shortcuts import render from django.shortcuts import render
from apps.hrm.models import Certificate, Employee from apps.hrm.models import Certificate, Employee
from apps.hrm.serializers import CertificateCreateUpdateSerializer, CertificateSerializer from apps.hrm.serializers import CertificateCreateUpdateSerializer, CertificateSerializer, EmployeeSerializer
from apps.rpm.models import Remployee, Rparty, RpartyFile, Rpeople, Rproject from apps.rpm.models import Rcertificate, Remployee, Rparty, RpartyFile, Rpjmember, Rpj
from apps.rpm.serializers import RemployeeCreateUpdateSerializer, RpartyAssignSerializer, RpartyCreateUpdateSerializer, RpartyFileListSerializer, RpartySerializer, RpeopleCreatesSerializer, RprojectCreateUpdateSerializer from apps.rpm.serializers import RcertificateCreateUpdateSerializer, RcertificateSerializer, RemployeeCreateSerializer, RemployeeSerializer, RpartyAssignSerializer, RpartyCreateUpdateSerializer, RpartyFileListSerializer, RpartySerializer, RpjListSerializer, RpjmemberCreateSerializer, RpjmemberCreatesSerializer, RpjCreateUpdateSerializer, RpjmemberSerializer, RpjmemberUpdateSerializer
from apps.system.models import Post, User, UserPost from apps.system.models import Post, User, UserPost
from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet
from rest_framework.mixins import CreateModelMixin, ListModelMixin from rest_framework.mixins import CreateModelMixin, ListModelMixin, RetrieveModelMixin
from apps.utils.mixins import CustomDestoryModelMixin
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.response import Response from rest_framework.response import Response
from django.contrib.auth.hashers import check_password, make_password from django.contrib.auth.hashers import check_password, make_password
@ -59,59 +60,61 @@ class RpartyFileViewSet(ListModelMixin, CustomGenericViewSet):
return queryset return queryset
class RemployeeViewSet(CustomModelViewSet): class RemployeeViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, CustomDestoryModelMixin,
queryset = Employee.objects.filter(type='remployee') CustomGenericViewSet):
create_serializer_class = RemployeeCreateUpdateSerializer queryset = Remployee.objects.all()
update_serializer_class = RemployeeCreateUpdateSerializer create_serializer_class = RemployeeCreateSerializer
serializer_class = RemployeeSerializer
def get_queryset(self): def get_queryset(self):
user = self.request.user user = self.request.user
queryset = super().get_queryset() queryset = super().get_queryset()
if user.type == 'remployee': if user.type == 'remployee':
queryset = queryset.filter(belong_dept=user.belong_dept) queryset = queryset.filter(rparty=self.request.user.belong_dept)
return queryset return queryset
@transaction.atomic # @transaction.atomic
def create(self, request, *args, **kwargs): # def create(self, request, *args, **kwargs):
""" # """
添加人员 # 添加人员
""" # """
user = self.request.user # user = self.request.user
serializer = self.get_serializer(data=request.data) # serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True) # serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data # vdata = serializer.validated_data
if user.type == 'remployee': # 如果是相关方账号 # if user.type == 'remployee': # 如果是相关方账号
ep = serializer.save() # ep = serializer.save()
Remployee.objects.get_or_create(employee=ep, rparty=user.belong_dept.rparty, # Remployee.objects.get_or_create(employee=ep, rparty=user.belong_dept.rparty,
defaults={ # defaults={
"employee": ep, # "employee": ep,
"rparty": user.belong_dept.rparty # "rparty": user.belong_dept.rparty
}) # })
else: # else:
if 'rparty' not in vdata: # if 'rparty' not in vdata:
raise ParseError('未指定相关方') # raise ParseError('未指定相关方')
serializer.save() # serializer.save()
return Response(serializer.data, status=201) # return Response(serializer.data, status=201)
class Rcertificate(CustomModelViewSet): class RcertificateViewSet(CustomModelViewSet):
queryset = Certificate.objects.filter(employee__type='remployee') queryset = Rcertificate.objects.all()
create_serializer_class = CertificateCreateUpdateSerializer create_serializer_class = RcertificateCreateUpdateSerializer
update_serializer_class = CertificateCreateUpdateSerializer update_serializer_class = RcertificateCreateUpdateSerializer
serializer_class = CertificateSerializer serializer_class = RcertificateSerializer
def get_queryset(self): def get_queryset(self):
user = self.request.user user = self.request.user
queryset = super().get_queryset() queryset = super().get_queryset()
if user.type == 'remployee': if user.type == 'remployee':
queryset = queryset.filter(belong_dept=user.belong_dept) queryset = queryset.filter(remployee__rparty=user.belong_dept)
return queryset return queryset
class RprojectViewSet(CustomModelViewSet): class RpjViewSet(CustomModelViewSet):
queryset = Rproject.objects.all() queryset = Rpj.objects.all()
create_serializer_class = RprojectCreateUpdateSerializer create_serializer_class = RpjCreateUpdateSerializer
update_serializer_class = RprojectCreateUpdateSerializer update_serializer_class = RpjCreateUpdateSerializer
serializer_class = RpjListSerializer
def get_queryset(self): def get_queryset(self):
user = self.request.user user = self.request.user
@ -135,42 +138,26 @@ class RprojectViewSet(CustomModelViewSet):
def update(self, request, *args, **kwargs): def update(self, request, *args, **kwargs):
obj = self.get_object() obj = self.get_object()
if obj.state == Rproject.RP_START: if obj.state != Rpj.RPJ_CREATE:
return super().update(request, *args, **kwargs)
raise ParseError('项目非创建状态不可更改')
class RpeopleViewSet(CustomGenericViewSet):
perms_map = {'get': '*'}
queryset = Rpeople.objects.all()
@action(methods=['post'], detail=False,
perms_map={'post': 'rproject:update'}, serializer_class=RpeopleCreatesSerializer)
@transaction.atomic
def creates(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data
rp = vdata['rproject']
if rp.state != Rproject.RP_START:
raise ParseError('项目非创建状态不可更改') raise ParseError('项目非创建状态不可更改')
for i in vdata['employees']: return super().update(request, *args, **kwargs)
Rpeople.objects.create(employee=i, rproject=rp)
# 有证书的添加人员证书
return Response() def destroy(self, request, *args, **kwargs):
@action(methods=['put'], detail=True,
perms_map={'put': 'rproject:update'}, serializer_class=serializers.Serializer)
@transaction.atomic
def make_manager(self, request):
"""
设为项目负责人
"""
obj = self.get_object() obj = self.get_object()
if obj.rproject.state != Rproject.RP_START: if obj.state != Rpj.RPJ_CREATE:
raise ParseError('项目非创建状态不可更改') raise ParseError('项目非创建状态不可删除')
Rpeople.objects.filter(rproject=obj.rproject).update(is_manager=False) return super().destroy(request, *args, **kwargs)
obj.is_manager = True
obj.save()
return Response() class RpjmemberViewSet(CustomModelViewSet):
perms_map = {'get': '*', 'post': 'rpj:update', 'put': 'rpj:update', 'delete': 'rpj:update'}
queryset = Rpjmember.objects.all()
create_serializer_class = RpjmemberCreateSerializer
update_serializer_class = RpjmemberUpdateSerializer
serializer_class = RpjmemberSerializer
def destroy(self, request, *args, **kwargs):
obj = self.get_object()
if obj.rpj.state == Rpj.RPJ_CREATE:
raise ParseError('项目非创建状态不可删除')
return super().destroy(request, *args, **kwargs)

View File

@ -11,6 +11,7 @@ from rest_framework.exceptions import ParseError
from django.db import transaction from django.db import transaction
from apps.third.tapis import dhapis 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_q.models import Task as QTask, Schedule as QSchedule # from django_q.models import Task as QTask, Schedule as QSchedule
@ -242,7 +243,7 @@ class DeptCreateUpdateSerializer(CustomModelSerializer):
@transaction.atomic @transaction.atomic
def create(self, validated_data): def create(self, validated_data):
from apps.third.clients import dhClient from apps.third.clients import dhClient
if dhClient: if settings.DAHUA_ENABLED:
data = { data = {
"parentId": 1, "parentId": 1,
"name": validated_data['name'], "name": validated_data['name'],
@ -257,7 +258,7 @@ class DeptCreateUpdateSerializer(CustomModelSerializer):
def update(self, instance, validated_data): def update(self, instance, validated_data):
from apps.third.clients import dhClient from apps.third.clients import dhClient
third_info = instance.third_info third_info = instance.third_info
if dhClient and not third_info.get('dh_id', False): if settings.DAHUA_ENABLED and not third_info.get('dh_id', False):
# 如果dh_id 不存在 # 如果dh_id 不存在
data = { data = {
"parentId": 1, "parentId": 1,
@ -269,7 +270,7 @@ class DeptCreateUpdateSerializer(CustomModelSerializer):
instance.third_info = third_info instance.third_info = third_info
instance.save() instance.save()
elif instance.name != validated_data.get('name', ''): elif instance.name != validated_data.get('name', ''):
if dhClient and instance.third_info.get('dh_id', False): if settings.DAHUA_ENABLED and instance.third_info.get('dh_id', False):
data = { data = {
"id": instance.third_info['dh_id'], "id": instance.third_info['dh_id'],
"parentId": 1, "parentId": 1,

View File

@ -0,0 +1,35 @@
# Generated by Django 3.2.12 on 2022-06-17 07:19
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
initial = True
dependencies = [
('am', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='TDevice',
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, '定位信标'), (30, '定位标签'), (40, 'aoa引擎'), (50, '音响'), (60, '视频通道'), (70, '闸机通道'), (80, '面板机')], verbose_name='设备类型')),
('code', models.CharField(max_length=20, verbose_name='设备唯一标识')),
('location', models.JSONField(blank=True, default=dict, verbose_name='位置信息')),
('third_info', models.JSONField(blank=True, default=dict, verbose_name='三方信息')),
('area', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='am.area', verbose_name='所在区')),
('areas', models.ManyToManyField(related_name='tareas', to='am.Area', verbose_name='覆盖区')),
],
options={
'abstract': False,
},
),
]

View File

View File

@ -18,15 +18,14 @@ class DhClient:
def __init__(self, client_id=settings.DAHUA_CLIENTID, def __init__(self, client_id=settings.DAHUA_CLIENTID,
client_secret=settings.DAHUA_SECRET) -> None: client_secret=settings.DAHUA_SECRET) -> None:
if not settings.DAHUA_ENABLED: if settings.DAHUA_ENABLED:
return None self.client_id = client_id
self.client_id = client_id self.client_secret = client_secret
self.client_secret = client_secret self.headers = {}
self.headers = {} self.isGetingToken = False
self.isGetingToken = False self.isRuning = True
self.isRuning = True self.t = None # 线程
self.t = None # 线程 self.setup()
self.setup()
def _get_token_loop(self): def _get_token_loop(self):
while self.isRuning: while self.isRuning:
@ -70,7 +69,7 @@ class DhClient:
def request(self, url: str, method: str, params=dict(), json=dict(), timeout=10, def request(self, url: str, method: str, params=dict(), json=dict(), timeout=10,
file_path_rela=None, raise_exception=True): file_path_rela=None, raise_exception=True):
if self is None: if not settings.DAHUA_ENABLED:
raise ParseError('大华对接未启用') raise ParseError('大华对接未启用')
if self.isGetingToken: if self.isGetingToken:
req_num = 0 req_num = 0

View File

@ -152,7 +152,7 @@ class CommonBDModel(BaseModel):
'system.user', null=True, blank=True, on_delete=models.SET_NULL, 'system.user', null=True, blank=True, on_delete=models.SET_NULL,
verbose_name='最后编辑人', related_name='%(class)s_update_by') verbose_name='最后编辑人', related_name='%(class)s_update_by')
belong_dept = models.ForeignKey( belong_dept = models.ForeignKey(
'system.organzation', null=True, blank=True, on_delete=models.SET_NULL, 'system.dept', null=True, blank=True, on_delete=models.SET_NULL,
verbose_name='所属部门', related_name='%(class)s_belong_dept') verbose_name='所属部门', related_name='%(class)s_belong_dept')
class Meta: class Meta:

View File

@ -3,14 +3,14 @@ from django.core.cache import cache
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError from rest_framework.exceptions import ValidationError
from rest_framework.mixins import (CreateModelMixin, ListModelMixin, from rest_framework.mixins import (CreateModelMixin, ListModelMixin,
RetrieveModelMixin, UpdateModelMixin) RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin)
from rest_framework.permissions import IsAuthenticated from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet from rest_framework.viewsets import GenericViewSet
from apps.system.models import DataFilter, Dept from apps.system.models import DataFilter, Dept
from apps.utils.errors import PKS_ERROR from apps.utils.errors import PKS_ERROR
from apps.utils.mixins import CustomDestoryModelMixin, MyLoggingMixin from apps.utils.mixins import MyLoggingMixin
from apps.utils.permission import ALL_PERMS, RbacPermission, get_user_perms_map from apps.utils.permission import ALL_PERMS, RbacPermission, get_user_perms_map
from apps.utils.queryset import get_child_queryset2 from apps.utils.queryset import get_child_queryset2
from apps.utils.serializers import PkSerializer from apps.utils.serializers import PkSerializer
@ -101,7 +101,7 @@ class CustomGenericViewSet(MyLoggingMixin, GenericViewSet):
class CustomModelViewSet(CreateModelMixin, UpdateModelMixin, ListModelMixin, class CustomModelViewSet(CreateModelMixin, UpdateModelMixin, ListModelMixin,
RetrieveModelMixin, CustomDestoryModelMixin, CustomGenericViewSet): RetrieveModelMixin, DestroyModelMixin, CustomGenericViewSet):
""" """
增强的ModelViewSet 增强的ModelViewSet
""" """
@ -126,6 +126,12 @@ class CustomModelViewSet(CreateModelMixin, UpdateModelMixin, ListModelMixin,
pks = request_data.get('pks', None) pks = request_data.get('pks', None)
if pks: if pks:
self.get_queryset().filter(id__in=pks).delete(update_by=request.user) self.get_queryset().filter(id__in=pks).delete(update_by=request.user)
return Response() return Response(status=204)
else: else:
raise ValidationError(**PKS_ERROR) raise ValidationError(**PKS_ERROR)
def perform_destroy(self, instance):
if self.delete_soft:
instance.delete(update_by=self.request.user)
else:
instance.delete(soft=False)

View File

@ -17,15 +17,14 @@ class XxClient:
""" """
def __init__(self, licence=settings.XX_LICENCE, username=settings.XX_USERNAME) -> None: def __init__(self, licence=settings.XX_LICENCE, username=settings.XX_USERNAME) -> None:
if not settings.XX_ENABLED: if settings.XX_ENABLED:
return None self.licence = licence
self.licence = licence self.username = username
self.username = username self.isGetingToken = False
self.isGetingToken = False self.isRuning = True
self.isRuning = True self.token = ''
self.token = '' self.t = None
self.t = None self.setup()
self.setup()
def _get_token_loop(self): def _get_token_loop(self):
while self.isRuning: while self.isRuning:
@ -58,10 +57,10 @@ class XxClient:
自定义销毁 自定义销毁
""" """
self.isRuning = False self.isRuning = False
self.t.join() # self.t.join()
def request(self, url: str, method: str = 'post', params=dict(), json=dict(), timeout=4, raise_exception=True): def request(self, url: str, method: str = 'post', params=dict(), json=dict(), timeout=4, raise_exception=True):
if self is None: if not settings.XX_ENABLED:
raise ParseError('寻息对接未启用') raise ParseError('寻息对接未启用')
params['accessToken'] = self.token params['accessToken'] = self.token
json['username'] = self.username json['username'] = self.username

View File

@ -15,17 +15,44 @@ class Visit(CommonBModel):
(30, '面试'), (30, '面试'),
(40, '开会') (40, '开会')
) )
V_CREATE = 10
V_AUDIT = 20
V_ENTER = 30
V_WORKING = 40
V_DONE = 50
V_STATE_CHOICES = (
(10, '创建中'),
(20, '审批中'),
(30, '待入厂'),
(40, '进行中'),
(50, '已完成')
)
purpose = models.PositiveSmallIntegerField('来访事由') purpose = models.PositiveSmallIntegerField('来访事由')
description = models.CharField('来访详述', max_length=200) state = models.PositiveSmallIntegerField(choices=V_STATE_CHOICES, default=10)
name = models.CharField('来访概述', max_length=50)
description = models.TextField('来访详述', null=True, blank=True)
visit_time = models.DateTimeField('来访时间') visit_time = models.DateTimeField('来访时间')
leave_time = models.DateTimeField('离开时间') leave_time = models.DateTimeField('离开时间')
receptionist = models.ForeignKey(User, verbose_name='接待人', on_delete=models.CASCADE) receptionist = models.ForeignKey(User, verbose_name='接待人', on_delete=models.CASCADE)
class VisitPeople(BaseModel): class Visitor(CommonAModel):
"""
访客信息
"""
employee = models.ForeignKey(Employee, verbose_name='成员信息', on_delete=models.CASCADE, null=True, blank=True)
name = models.CharField('姓名', max_length=20)
phone = models.CharField('手机号', max_length=11)
photo = models.CharField('证件照', max_length=1000)
id_number = models.CharField('身份证号', max_length=100)
visit = models.ForeignKey(Visit, verbose_name='最近所属访问项目', on_delete=models.CASCADE,
null=True, blank=True)
class Vpeople(BaseModel):
""" """
访客项目人员 访客项目人员
""" """
visit = models.ForeignKey(Visit, verbose_name='关联访问项目', on_delete=models.CASCADE) visit = models.ForeignKey(Visit, verbose_name='关联访问项目', on_delete=models.CASCADE)
visitor = models.ForeignKey(Employee, verbose_name='访客', on_delete=models.CASCADE) visitor = models.ForeignKey(Visitor, verbose_name='访客', on_delete=models.CASCADE)
is_manager = models.BooleanField('是否主访人', default=False) is_main = models.BooleanField('是否主访人', default=False)

50
apps/vm/serializers.py Normal file
View File

@ -0,0 +1,50 @@
from apps.hrm.models import Employee
from apps.utils.constants import EXCLUDE_FIELDS
from apps.utils.serializers import CustomModelSerializer
from apps.vm.models import Visit, Visitor, Vpeople
from apps.hrm.serializers import phone_check
from rest_framework import serializers
class VisitCreateUpdateSerializer(CustomModelSerializer):
class Meta:
model = Visit
fields = ['purpose', 'name', 'description', 'visit_time', 'leave_time', 'receptionist']
class VisitSerializer(CustomModelSerializer):
class Meta:
model = Visit
fields = '__all__'
class VisitorCreateSerializer(CustomModelSerializer):
phone = serializers.CharField(label="手机号", validators=[phone_check])
class Meta:
model = Visitor
exclude = ['name', 'phone', 'photo', 'id_number']
class VisitorSerializer(CustomModelSerializer):
class Meta:
model = Visitor
fields = '__all__'
class VpeopleCreateSerializer(CustomModelSerializer):
class Meta:
model = Vpeople
fields = ['visitor', 'visitor', 'is_main']
def create(self, validated_data):
ins = super().create(validated_data)
if ins.is_main:
Vpeople.objects.filter(visit=validated_data['visit']).exclude(id__in=ins.id).update(is_main=False)
return ins
class VpeopleSerializer(CustomModelSerializer):
class Meta:
model = Vpeople
fields = '__all__'

30
apps/vm/tasks.py Normal file
View File

@ -0,0 +1,30 @@
# Create your tasks here
from __future__ import absolute_import, unicode_literals
from apps.hrm.models import Employee
from apps.utils.task import CustomTask
from apps.vm.models import Visit, Vpeople
from celery import shared_task
@shared_task(base=CustomTask)
def visit_audit_end(ticket_id):
visit = Visit.objects.get(ticket__id=ticket_id)
if visit.state == Visit.V_AUDIT:
visit.state = Visit.V_ENTER
visit.save()
# 更新企业访客人员库
for i in Vpeople.objects.filter(visit=visit):
visitor = i.visitor
ep = Employee.objects.filter(id_number=visitor.id_number).first()
if ep:
pass
else:
ep = Employee()
ep.name = visitor.name
ep.phone = visitor.phone
ep.photo = visitor.photo
ep.id_number = visitor.id_number
ep.type = 'visitor'
ep.save()
visitor.employee = ep
visitor.save()

View File

@ -1,3 +1,62 @@
from django.shortcuts import render from django.shortcuts import render
from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet, GenericViewSet
from apps.vm.models import Visit, Visitor, Vpeople
from apps.vm.serializers import VisitCreateUpdateSerializer, VisitSerializer, VisitorCreateSerializer, VisitorSerializer, VpeopleCreateSerializer, VpeopleSerializer
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.exceptions import ParseError
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin, CreateModelMixin, DestroyModelMixin
from apps.utils.mixins import CustomDestoryModelMixin
# Create your views here. # Create your views here.
class VisitViewSet(CustomModelViewSet):
queryset = Visit.objects.all()
create_serializer_class = VisitCreateUpdateSerializer
update_serializer_class = VisitCreateUpdateSerializer
serializer_class = VisitSerializer
def get_queryset(self):
user = self.request.user
queryset = super().get_queryset()
if user.type == 'visitor':
queryset = queryset.filter(create_by=user)
return queryset
def update(self, request, *args, **kwargs):
obj = self.get_object()
if obj.state != Visit.V_CREATE:
raise ParseError('项目非创建状态不可更改')
return super().update(request, *args, **kwargs)
def destroy(self, request, *args, **kwargs):
obj = self.get_object()
if obj.state != Visit.V_CREATE:
raise ParseError('项目非创建状态不可删除')
return super().destroy(request, *args, **kwargs)
class VisitorViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, CustomDestoryModelMixin,
CustomGenericViewSet):
queryset = Visitor.objects.all()
create_serializer_class = VisitorCreateSerializer
serializer_class = VisitorSerializer
class VpeopleView(ListModelMixin, RetrieveModelMixin, CreateModelMixin, DestroyModelMixin, CustomGenericViewSet):
perms_map = {'get': '*', 'post': 'visit:update', 'put': 'visit:update', 'delete': 'visit:update'}
queryset = Vpeople.objects.all()
create_serializer_class = VpeopleCreateSerializer
serializer_class = VpeopleSerializer
def create(self, request, *args, **kwargs):
obj = self.get_object()
if obj.visit.state != Visit.V_CREATE:
raise ParseError('项目非创建状态不可新增成员')
return super().create(request, *args, **kwargs)
def destroy(self, request, *args, **kwargs):
obj = self.get_object()
if obj.visit.state != Visit.V_CREATE:
raise ParseError('项目非创建状态不可新增成员')
return super().destroy(request, *args, **kwargs)

View File

@ -12,6 +12,7 @@ pillow==9.0.1
opencv-python==4.5.5.62 opencv-python==4.5.5.62
daphne==3.0.2 daphne==3.0.2
redis==4.1.4 redis==4.1.4
django-redis==5.2.0
user-agents==2.2.0 user-agents==2.2.0
daphne==3.0.2 daphne==3.0.2
channels==3.0.4 channels==3.0.4

View File

@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/3.0/ref/settings/
""" """
from datetime import datetime, timedelta from datetime import datetime, timedelta
import json
import os import os
from . import conf from . import conf
import logging import logging
@ -54,6 +55,7 @@ INSTALLED_APPS = [
'apps.auth1', 'apps.auth1',
'apps.monitor', 'apps.monitor',
'apps.wf', 'apps.wf',
'apps.ecm',
'apps.hrm', 'apps.hrm',
'apps.am', 'apps.am',
'apps.vm', 'apps.vm',
@ -194,8 +196,8 @@ REST_FRAMEWORK = {
# 'UNAUTHENTICATED_TOKEN': None, # 'UNAUTHENTICATED_TOKEN': None,
'EXCEPTION_HANDLER': 'apps.utils.exceptions.custom_exception_hander', 'EXCEPTION_HANDLER': 'apps.utils.exceptions.custom_exception_hander',
'DEFAULT_THROTTLE_RATES': { 'DEFAULT_THROTTLE_RATES': {
'anon': '1/second', 'anon': '100/second',
'user': '2/second' 'user': '200/second'
} }
} }
# simplejwt配置 # simplejwt配置
@ -214,16 +216,15 @@ AUTHENTICATION_BACKENDS = (
) )
# 缓存配置,有需要可更改为redis # 缓存配置,有需要可更改为redis
# CACHES = { CACHES = {
# "default": { "default": {
# "BACKEND": "django_redis.cache.RedisCache", "BACKEND": "django_redis.cache.RedisCache",
# "LOCATION": "redis://redis:6379/1", "LOCATION": "redis://localhost:6379/2",
# "OPTIONS": { "OPTIONS": {
# "CLIENT_CLASS": "django_redis.client.DefaultClient", "CLIENT_CLASS": "django_redis.client.DefaultClient",
# "PICKLE_VERSION": -1 }
# } }
# } }
# }
# celery配置,celery正常运行必须安装redis # celery配置,celery正常运行必须安装redis
CELERY_BROKER_URL = "redis://localhost:6379/2" # 任务存储 CELERY_BROKER_URL = "redis://localhost:6379/2" # 任务存储
@ -257,8 +258,8 @@ CELERY_TASK_TRACK_STARTED = True
# swagger配置 # swagger配置
SWAGGER_SETTINGS = { SWAGGER_SETTINGS = {
'LOGIN_URL': '/django/login/', 'LOGIN_URL': '/django/admin/login/',
'LOGOUT_URL': '/django/logout/', 'LOGOUT_URL': '/django/admin/logout/',
} }
# 日志配置 # 日志配置

View File

@ -36,8 +36,8 @@ schema_view = get_schema_view(
urlpatterns = [ urlpatterns = [
# django后台 # django后台
path('django/doc/', include('django.contrib.admindocs.urls')), path('django/admin/doc/', include('django.contrib.admindocs.urls')),
path('django/', admin.site.urls), path('django/admin/', admin.site.urls),
path('django/api-auth/', include('rest_framework.urls')), path('django/api-auth/', include('rest_framework.urls')),
# api # api