同步一次数据库
This commit is contained in:
parent
a5f19641b6
commit
c192467d58
|
@ -13,5 +13,6 @@ celerybeat-schedule.dat
|
|||
celerybeat-schedule.dir
|
||||
db.sqlite3
|
||||
server/conf.py
|
||||
server/conf.json
|
||||
sh/*
|
||||
nohup.out
|
|
@ -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='最后编辑人'),
|
||||
),
|
||||
]
|
|
@ -12,15 +12,22 @@ class Area(CommonBModel):
|
|||
AREA_LEVEL_2 = 20
|
||||
AREA_LEVEL_3 = 30
|
||||
AREA_LEVEL_4 = 40
|
||||
AREA_LEVEL_HOICES = (
|
||||
AREA_LEVEL_CHOICES = (
|
||||
(AREA_LEVEL_1, '办公'),
|
||||
(AREA_LEVEL_2, '生产一般'),
|
||||
(AREA_LEVEL_3, '生产重点'),
|
||||
(AREA_LEVEL_4, '四级')
|
||||
)
|
||||
AREA_TYPE_FIX = 10
|
||||
AREA_TYPE_TEMP = 20
|
||||
AREA_TYPE_CHOICES = (
|
||||
(10, '固定'),
|
||||
(20, '临时')
|
||||
)
|
||||
name = models.CharField('名称', max_length=20)
|
||||
type = models.PositiveSmallIntegerField('区域类型', default=10, choices=AREA_TYPE_CHOICES)
|
||||
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)
|
||||
remployee_yes = models.BooleanField('准许相关方人员', default=False)
|
||||
employee_yes = models.BooleanField('准许全部员工', default=True)
|
||||
|
|
|
@ -11,7 +11,7 @@ class AreaSimpleSerializer(CustomModelSerializer):
|
|||
class AreaCreateUpdateSerializer(CustomModelSerializer):
|
||||
class Meta:
|
||||
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):
|
||||
|
|
|
@ -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='最后编辑人'),
|
||||
),
|
||||
]
|
|
@ -3,6 +3,7 @@ from apps.am.models import Area
|
|||
from apps.hrm.models import Employee
|
||||
from apps.utils.models import BaseModel, CommonAModel, CommonBModel
|
||||
from apps.system.models import Dept, Post, User
|
||||
from apps.third.models import TDevice
|
||||
from django.utils import timezone
|
||||
# Create your models here.
|
||||
|
||||
|
@ -19,14 +20,14 @@ class EventCate(CommonAModel):
|
|||
name = models.CharField('名称', max_length=20, unique=True)
|
||||
trigger = models.PositiveSmallIntegerField('触发方式', default=10, choices=EVENT_TRIGGER_CHOICES)
|
||||
speaker_on = models.BooleanField('开启音响报警', default=True)
|
||||
speakers = models.ManyToManyField('third.tdevice', verbose_name='固定音响')
|
||||
filter_area_level = models.PositiveSmallIntegerField('固定音响区域级别过滤', choices=Area.AREA_LEVEL_HOICES,
|
||||
speakers = models.ManyToManyField(TDevice, verbose_name='固定音响')
|
||||
filter_area_level = models.PositiveSmallIntegerField('固定音响区域级别过滤', choices=Area.AREA_LEVEL_CHOICES,
|
||||
default=Area.AREA_LEVEL_1)
|
||||
|
||||
|
||||
class PushSetting(CommonAModel):
|
||||
class NotifySetting(CommonAModel):
|
||||
"""
|
||||
推送配置
|
||||
提醒配置
|
||||
"""
|
||||
PUSH_FILTER1_CHOICES = (
|
||||
(10, '当事人部门'),
|
||||
|
@ -36,11 +37,12 @@ class PushSetting(CommonAModel):
|
|||
)
|
||||
event_cate = models.ForeignKey(EventCate, verbose_name='关联事件种类',
|
||||
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)
|
||||
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)
|
||||
sms_enable = models.BooleanField('短信通知', default=False)
|
||||
wechat_enable = models.BooleanField('开启微信通知', default=False)
|
||||
can_handle = models.BooleanField('是否可处理', default=False)
|
||||
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)
|
||||
area = models.ForeignKey(Area, verbose_name='发生区域', on_delete=models.CASCADE)
|
||||
location = models.JSONField('事件点位坐标', default=dict, null=False, blank=True)
|
||||
|
@ -64,22 +66,20 @@ class Event(CommonBModel):
|
|||
is_pushed = models.BooleanField('是否已推送', default=False)
|
||||
|
||||
|
||||
class Push(BaseModel):
|
||||
class Remind(BaseModel):
|
||||
"""
|
||||
推送情况
|
||||
事件提醒表
|
||||
"""
|
||||
event = models.ForeignKey(Event, verbose_name='关联事件',
|
||||
on_delete=models.CASCADE)
|
||||
pusher = models.ForeignKey(User, verbose_name='推送人',
|
||||
on_delete=models.CASCADE)
|
||||
push_setting = models.ForeignKey(PushSetting, verbose_name='通过哪个配置',
|
||||
on_delete=models.CASCADE, null=True, blank=True)
|
||||
recipient = models.ForeignKey(User, verbose_name='接收人',
|
||||
on_delete=models.CASCADE)
|
||||
notify_setting = models.ForeignKey(NotifySetting, verbose_name='通过哪个配置',
|
||||
on_delete=models.CASCADE, null=True, blank=True)
|
||||
post = models.ForeignKey(Post, verbose_name='岗位',
|
||||
on_delete=models.CASCADE, null=True, blank=True)
|
||||
dept = models.ForeignKey(Dept, verbose_name='部门',
|
||||
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_sms_send = models.BooleanField('短信已发送', default=False)
|
||||
can_handle = models.BooleanField('是否可处理', default=False)
|
||||
last_push_time = models.DateTimeField('最后推送时间', default=timezone.now)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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 rest_framework import serializers
|
||||
from apps.system.serializers import UserSimpleSerializer
|
||||
|
@ -23,9 +23,9 @@ class EventCateUpdateSerializer(CustomModelSerializer):
|
|||
fields = ['speaker_on', 'speakers', 'filter_area_level']
|
||||
|
||||
|
||||
class PushSettingsSerializer(CustomModelSerializer):
|
||||
class NotifySettingsSerializer(CustomModelSerializer):
|
||||
class Meta:
|
||||
model = PushSetting
|
||||
model = NotifySetting
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
|
@ -46,9 +46,9 @@ class EventHandleSerializer(CustomModelSerializer):
|
|||
fields = ['handle_desc']
|
||||
|
||||
|
||||
class PushSerializer(CustomModelSerializer):
|
||||
pusher_ = UserSimpleSerializer(source='pusher', read_only=True)
|
||||
class RemindSerializer(CustomModelSerializer):
|
||||
recipient_ = UserSimpleSerializer(source='recipient', read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Push
|
||||
model = Remind
|
||||
fields = '__all__'
|
||||
|
|
|
@ -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 rest_framework.routers import DefaultRouter
|
||||
|
||||
|
@ -8,8 +8,8 @@ HTML_BASE_URL = 'ecm/'
|
|||
router = DefaultRouter()
|
||||
router.register('event_cate', EventCateViewSet, basename='event_cate')
|
||||
router.register('event', EventViewSet, basename='event')
|
||||
router.register('push_setting', PushSettingViewSet, basename='push_setting')
|
||||
router.register('push', PushViewSet, basename='push')
|
||||
router.register('notify_setting', NotifySettingViewSet, basename='notify_setting')
|
||||
router.register('remind', RemindViewSet, basename='remind')
|
||||
urlpatterns = [
|
||||
path(API_BASE_URL, include(router.urls)),
|
||||
]
|
||||
|
|
|
@ -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,
|
||||
EventSerializer, PushSerializer, PushSettingsSerializer)
|
||||
EventSerializer, RemindSerializer, NotifySettingsSerializer)
|
||||
from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet
|
||||
from rest_framework.mixins import UpdateModelMixin, ListModelMixin, RetrieveModelMixin
|
||||
from django.db import transaction
|
||||
|
@ -19,9 +19,9 @@ class EventCateViewSet(UpdateModelMixin, ListModelMixin, CustomGenericViewSet):
|
|||
update_serializer_class = EventCateUpdateSerializer
|
||||
|
||||
|
||||
class PushSettingViewSet(CustomModelViewSet):
|
||||
queryset = PushSetting.objects.all()
|
||||
serializer_class = PushSettingsSerializer
|
||||
class NotifySettingViewSet(CustomModelViewSet):
|
||||
queryset = NotifySetting.objects.all()
|
||||
serializer_class = NotifySettingsSerializer
|
||||
|
||||
|
||||
class EventViewSet(ListModelMixin, RetrieveModelMixin, CustomGenericViewSet):
|
||||
|
@ -45,10 +45,10 @@ class EventViewSet(ListModelMixin, RetrieveModelMixin, CustomGenericViewSet):
|
|||
return Response()
|
||||
|
||||
|
||||
class PushViewSet(ListModelMixin, CustomGenericViewSet):
|
||||
perms_map = {'get': 'push:view'}
|
||||
queryset = Push.objects.all()
|
||||
serializer_class = PushSerializer
|
||||
class RemindViewSet(ListModelMixin, CustomGenericViewSet):
|
||||
perms_map = {'get': 'envent:view'}
|
||||
queryset = Remind.objects.all()
|
||||
serializer_class = RemindSerializer
|
||||
|
||||
@action(methods=['get'], detail=False, perms_map={'get': '*'})
|
||||
def my(self, request, *args, **kwargs):
|
||||
|
@ -56,7 +56,7 @@ class PushViewSet(ListModelMixin, CustomGenericViewSet):
|
|||
推送给我的
|
||||
"""
|
||||
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)
|
||||
if page is not None:
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
),
|
||||
]
|
|
@ -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='在职状态'),
|
||||
),
|
||||
]
|
|
@ -24,17 +24,16 @@ class Employee(CommonBModel):
|
|||
verbose_name='系统账号',
|
||||
on_delete=models.PROTECT, null=True, blank=True)
|
||||
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)
|
||||
number = models.CharField('人员编号', max_length=50, 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='男')
|
||||
signature = models.CharField('签名图片', max_length=200, null=True, blank=True)
|
||||
birthday = models.DateField('出生年月日', null=True, blank=True)
|
||||
qualification = models.CharField('学历', max_length=50, null=True, blank=True)
|
||||
job_state = models.IntegerField('在职状态', choices=jobstate_choices, default=1)
|
||||
face_data = models.JSONField('人脸识别数据', null=True, blank=True)
|
||||
job_state = models.IntegerField('在职状态', choices=jobstate_choices, default=10)
|
||||
is_atwork = models.BooleanField('当前在岗', default=False)
|
||||
show_atwork = models.BooleanField('是否展示在岗状态', default=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)
|
||||
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)
|
||||
issue_date = models.DateField('发证日期')
|
||||
expiration_date = models.DateField('有效期')
|
||||
review_date = models.DateField('下一次复审日期')
|
||||
file = models.CharField('文件地址', max_length=1000, null=True, blank=True)
|
||||
file = models.TextField('文件地址', null=True, blank=True)
|
||||
|
|
|
@ -12,6 +12,7 @@ from apps.third.clients import dhClient
|
|||
from apps.third.tapis import dhapis
|
||||
import re
|
||||
from datetime import datetime
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class EmployeeBaseSerializer(CustomModelSerializer):
|
||||
|
@ -35,8 +36,7 @@ class EmployeeCreateUpdateSerializer(EmployeeBaseSerializer):
|
|||
|
||||
class Meta:
|
||||
model = Employee
|
||||
exclude = EXCLUDE_FIELDS + ['face_data',
|
||||
'is_atwork', 'last_check_time',
|
||||
exclude = EXCLUDE_FIELDS + ['is_atwork', 'last_check_time',
|
||||
'not_work_remark', 'third_info', 'type']
|
||||
extra_kwargs = {
|
||||
'phone': {'required': True},
|
||||
|
@ -48,7 +48,7 @@ class EmployeeCreateUpdateSerializer(EmployeeBaseSerializer):
|
|||
@transaction.atomic
|
||||
def create(self, validated_data):
|
||||
instance = super().create(validated_data)
|
||||
if dhClient:
|
||||
if settings.DAHUA_ENABLED and dhClient:
|
||||
# 创建人员
|
||||
_, res = dhClient.request(**dhapis['person_gen_id'])
|
||||
personId = res['id']
|
||||
|
@ -118,7 +118,7 @@ class EmployeeCreateUpdateSerializer(EmployeeBaseSerializer):
|
|||
departmentId = instance.belong_dept.third_info['dh_id']
|
||||
except Exception:
|
||||
pass
|
||||
if dhClient:
|
||||
if settings.DAHUA_ENABLED and dhClient:
|
||||
third_info = instance.third_info
|
||||
dh_id = instance.third_info['dh_id']
|
||||
dh_photo = third_info['dh_photo']
|
||||
|
@ -192,7 +192,7 @@ class EmployeeSerializer(EmployeeBaseSerializer):
|
|||
|
||||
class Meta:
|
||||
model = Employee
|
||||
exclude = ['face_data']
|
||||
fields = '__all__'
|
||||
read_only_fields = ['is_atwork', 'last_check_time', 'not_work_remark']
|
||||
|
||||
|
||||
|
|
|
@ -8,9 +8,17 @@ from apps.hrm.models import Employee
|
|||
def updateEmployee(sender, instance, created, **kwargs):
|
||||
# if created:
|
||||
# 如果账号所属部门有变动, 更新关联人员的所属部门, 只限内部人员
|
||||
if not instance.is_superuser:
|
||||
if not instance.is_superuser and instance.type == 'employee':
|
||||
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:
|
||||
ep.belong_dept = instance.belong_dept
|
||||
ep.save()
|
||||
else:
|
||||
Employee.objects.get_or_create(user=instance,
|
||||
defaults={
|
||||
"user": instance,
|
||||
"name": instance.name,
|
||||
"phone": instance.phone,
|
||||
"belong_dept": instance.belong_dept
|
||||
})
|
||||
|
|
|
@ -30,7 +30,7 @@ class EmployeeViewSet(CustomModelViewSet):
|
|||
"""
|
||||
人员管理
|
||||
"""
|
||||
queryset = Employee.objects.all()
|
||||
queryset = Employee.objects.filter(type='employee')
|
||||
select_related_fields = ['user']
|
||||
filterset_class = EmployeeFilterSet
|
||||
serializer_class = EmployeeSerializer
|
||||
|
|
|
@ -1,34 +1,38 @@
|
|||
from django.db import models
|
||||
from apps.system.models import Dept, Dictionary, User
|
||||
from apps.utils.models import BaseModel, CommonAModel, CommonBModel
|
||||
from apps.hrm.models import Certificate
|
||||
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.wf.models import Ticket, Workflow
|
||||
|
||||
|
||||
# Create your models here.
|
||||
class OptCate(CommonAModel):
|
||||
class OplCate(CommonAModel):
|
||||
"""
|
||||
作业票种类
|
||||
作业许可种类
|
||||
"""
|
||||
code = models.CharField('标识', max_length=10, 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)
|
||||
workflow = models.ForeignKey(Workflow, verbose_name='所用工作流',
|
||||
on_delete=models.CASCADE, null=True, blank=True)
|
||||
risk_options = models.ManyToManyField(Dictionary, verbose_name='风险分析')
|
||||
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 = (
|
||||
(10, '创建中'),
|
||||
(20, '审批中'),
|
||||
(30, '待作业'),
|
||||
(40, '待关闭'),
|
||||
(50, '已关闭')
|
||||
)
|
||||
OP_WORK_CHOICES = (
|
||||
('work', '运行'),
|
||||
('stop', '停机'),
|
||||
('repair', '检修')
|
||||
(OP_CREATE, '创建中'),
|
||||
(OP_AUDIT, '审批中'),
|
||||
(OP_WAIT, '待作业'),
|
||||
(OP_WORK, '作业中'),
|
||||
(OP_CLOSE, '已关闭')
|
||||
)
|
||||
number = models.CharField('作业编号', max_length=20, null=True, blank=True)
|
||||
name = models.CharField('作业简述', max_length=200)
|
||||
|
@ -37,33 +41,109 @@ class Operation(CommonBModel):
|
|||
place = models.TextField('具体地点', null=True, blank=True)
|
||||
start_time = models.DateTimeField('作业开始时间')
|
||||
end_time = models.DateTimeField('作业结束时间')
|
||||
dept_sd = models.ForeignKey(Dept, verbose_name='属地部门',
|
||||
on_delete=models.CASCADE)
|
||||
dept_yw = models.ForeignKey(Dept, verbose_name='业务部门',
|
||||
on_delete=models.CASCADE)
|
||||
user_xt = models.ForeignKey(User, verbose_name='业务部门协调员',
|
||||
on_delete=models.CASCADE)
|
||||
user_fz = models.ForeignKey(User, verbose_name='作业负责人',
|
||||
on_delete=models.CASCADE)
|
||||
user_jh = models.ForeignKey(User, verbose_name='作业监护人',
|
||||
)
|
||||
state_work = models.CharField('生产状态', choices=OP_WORK_CHOICES)
|
||||
dept_ter = models.ForeignKey(Dept, verbose_name='属地部门',
|
||||
on_delete=models.CASCADE)
|
||||
dept_bus = models.ForeignKey(Dept, verbose_name='业务部门',
|
||||
on_delete=models.CASCADE)
|
||||
coordinator = models.ForeignKey(User, verbose_name='业务部门协调员',
|
||||
on_delete=models.CASCADE)
|
||||
state_work = models.CharField('生产状态', max_length=20, help_text='运行/停机/检修')
|
||||
|
||||
|
||||
class Opt(CommonBModel):
|
||||
class Opl(CommonBDModel):
|
||||
"""
|
||||
作业票
|
||||
作业许可证
|
||||
"""
|
||||
CLOSE_CHOICES1 = (
|
||||
(10, '作业正常结束'),
|
||||
(20, '因计划改变停止作业'),
|
||||
(30, '因发生异常终止作业'),
|
||||
(40, '其他')
|
||||
)
|
||||
operation = models.ForeignKey(Operation, verbose_name='关联作业',
|
||||
on_delete=models.CASCADE)
|
||||
number = models.CharField('作业票编号', max_length=20, null=True, blank=True)
|
||||
cate = models.ForeignKey(OptCate, verbose_name='作业票种类',
|
||||
on_delete=models.CASCADE, related_name='opl_operation')
|
||||
number = models.CharField('作业许可编号', max_length=20, null=True, blank=True)
|
||||
level = models.CharField('作业级别', max_length=20,
|
||||
help_text='特技/三级/二级/主干道/次干道', null=True, blank=True)
|
||||
cate = models.ForeignKey(OplCate, verbose_name='作业许可种类',
|
||||
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)
|
||||
user_fz = models.ForeignKey(User, verbose_name='作业负责人',
|
||||
on_delete=models.CASCADE)
|
||||
user_jh = models.ForeignKey(User, verbose_name='作业监护人',
|
||||
)
|
||||
ticket = models.ForeignKey(Ticket, verbose_name='关联工单',
|
||||
on_delete=models.CASCADE, null=True, blank=True)
|
||||
charger = models.ForeignKey(User, verbose_name='作业负责人',
|
||||
on_delete=models.CASCADE, related_name='opl_charger')
|
||||
monitor = models.ForeignKey(User, verbose_name='作业监护人',
|
||||
on_delete=models.CASCADE, related_name='opl_monitor')
|
||||
# electrician = models.ForeignKey(User, verbose_name='电工',
|
||||
# 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='关联作业许可')
|
||||
|
|
|
@ -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.wf.serializers import WorkflowSimpleSerializer
|
||||
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:
|
||||
model = OptCate
|
||||
model = OplCate
|
||||
fields = ['code', 'name', 'template_export', 'workflow']
|
||||
|
||||
|
||||
class OptCateSerializer(CustomModelSerializer):
|
||||
workflow_ = WorkflowSimpleSerializer(source='workflow', read_only=True)
|
||||
class OplCateSerializer(CustomModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = OptCate
|
||||
model = OplCate
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class OperationCreateUpdateSerializer(CustomModelSerializer):
|
||||
class Meta:
|
||||
model = Operation
|
||||
fields = EXCLUDE_FIELDS + ['number']
|
||||
exclude = EXCLUDE_FIELDS + ['number']
|
||||
|
||||
|
||||
class OperationSerializer(CustomModelSerializer):
|
||||
class Meta:
|
||||
model = Operation
|
||||
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']
|
||||
|
|
|
@ -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):
|
||||
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
|
|
@ -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)
|
|
@ -1,19 +1,108 @@
|
|||
from django.shortcuts import render
|
||||
from apps.opm.models import Operation, OptCate
|
||||
from apps.opm.serializers import OperationCreateUpdateSerializer, OptCateCreateUpdateSerializer, OptCateSerializer
|
||||
from apps.utils.viewsets import CustomModelViewSet
|
||||
|
||||
from rest_framework.response import Response
|
||||
from apps.opm.models import GasCheck, Operation, Opl, OplCate, OplWorker
|
||||
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.
|
||||
class OptCateViewSet(CustomModelViewSet):
|
||||
queryset = OptCate.objects.all()
|
||||
create_serializer_class = OptCateCreateUpdateSerializer
|
||||
update_serializer_class = OptCateCreateUpdateSerializer
|
||||
serializer_class = OptCateSerializer
|
||||
class OplCateViewSet(CustomModelViewSet):
|
||||
queryset = OplCate.objects.all()
|
||||
create_serializer_class = OplCateCreateUpdateSerializer
|
||||
update_serializer_class = OplCateCreateUpdateSerializer
|
||||
serializer_class = OplCateSerializer
|
||||
|
||||
|
||||
class OperationViewSet(CustomModelViewSet):
|
||||
queryset = Operation.objects.all()
|
||||
create_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)
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
from django.db import models
|
||||
from apps.hrm.models import Certificate, Employee
|
||||
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.
|
||||
|
@ -20,7 +21,6 @@ class Rparty(CommonBModel):
|
|||
email = models.EmailField('邮箱', null=True, blank=True)
|
||||
addresss = models.CharField('企业地址', max_length=200, null=True, blank=True)
|
||||
description = models.TextField('概述', null=True, blank=True)
|
||||
# belong_dept是归属部门
|
||||
|
||||
|
||||
class RpartyFile(BaseModel):
|
||||
|
@ -33,15 +33,15 @@ class RpartyFile(BaseModel):
|
|||
rparty = models.ForeignKey(Rparty, verbose_name='关联相关方', on_delete=models.CASCADE)
|
||||
|
||||
|
||||
class Rproject(CommonBModel):
|
||||
class Rpj(CommonBDModel):
|
||||
"""
|
||||
相关方项目
|
||||
"""
|
||||
RP_START = 10
|
||||
RP_APPROVAL = 20
|
||||
RP_ENTER = 30
|
||||
RP_WORKING = 40
|
||||
RP_DONE = 50
|
||||
RPJ_CREATE = 10
|
||||
RPJ_AUDIT = 20
|
||||
RPJ_ENTER = 30
|
||||
RPJ_WORKING = 40
|
||||
RPJ_DONE = 50
|
||||
RP_STATE_CHOICES = (
|
||||
(10, '创建中'),
|
||||
(20, '审批中'),
|
||||
|
@ -63,45 +63,72 @@ class Rproject(CommonBModel):
|
|||
state = models.PositiveSmallIntegerField('状态', default=10)
|
||||
rparty = models.ForeignKey(Rparty, verbose_name='关联相关方', on_delete=models.CASCADE)
|
||||
# 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='文件种类',
|
||||
on_delete=models.CASCADE, null=True, blank=True)
|
||||
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)
|
||||
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='关联人员',
|
||||
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)
|
||||
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)
|
||||
rcertificates = models.ManyToManyField(Rcertificate, through='rpm.rpjcertificate')
|
||||
|
||||
|
||||
class Rcertificate(BaseModel):
|
||||
class Rpjcertificate(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)
|
||||
rpj_member = models.ForeignKey(Rpjmember, verbose_name='关联项目成员', on_delete=models.CASCADE)
|
||||
rcertificate = models.ForeignKey(Rcertificate, verbose_name='关联相关方证书', on_delete=models.CASCADE,
|
||||
null=True, blank=True)
|
||||
name = models.CharField('证书名称', max_length=20)
|
||||
number = models.CharField('证书编号', max_length=20)
|
||||
type = models.PositiveSmallIntegerField('证书类型', default=10, choices=Certificate.CERTIFICATE_TYPE_CHOICES)
|
||||
|
|
|
@ -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.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.utils.constants import EXCLUDE_FIELDS
|
||||
from apps.utils.serializers import CustomModelSerializer
|
||||
from apps.system.serializers import DictSerializer, FileSerializer
|
||||
from rest_framework import serializers
|
||||
from rest_framework.exceptions import ParseError
|
||||
from django.db import transaction
|
||||
|
||||
|
||||
class RpartyCreateUpdateSerializer(CustomModelSerializer):
|
||||
|
@ -56,41 +58,118 @@ class RpartyFileListSerializer(CustomModelSerializer):
|
|||
files_ = FileSerializer(source='files', many=True, read_only=True)
|
||||
|
||||
|
||||
class RprojectCreateUpdateSerializer(CustomModelSerializer):
|
||||
class RpjCreateUpdateSerializer(CustomModelSerializer):
|
||||
class Meta:
|
||||
model = Rproject
|
||||
fields = ['name', 'contract_number', 'type', 'come_time', 'leave_time', 'belong_dept']
|
||||
model = Rpj
|
||||
fields = ['name', 'contract_number', 'type', 'come_time', 'leave_time', 'belong_dept', 'rparty']
|
||||
|
||||
|
||||
class RprojectListSerializer(CustomModelSerializer):
|
||||
class RpjListSerializer(CustomModelSerializer):
|
||||
class Meta:
|
||||
model = Rproject
|
||||
model = Rpj
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class RemployeeCreateUpdateSerializer(CustomModelSerializer):
|
||||
class RemployeeCreateSerializer(CustomModelSerializer):
|
||||
phone = serializers.CharField(label="手机号", validators=[phone_check])
|
||||
rparty = serializers.PrimaryKeyRelatedField(queryset=Rparty.objects.all(), label='相关方ID', required=False)
|
||||
|
||||
class Meta:
|
||||
model = Employee
|
||||
exclude = EXCLUDE_FIELDS + ['face_data',
|
||||
'is_atwork', 'last_check_time',
|
||||
'not_work_remark', 'third_info', 'type']
|
||||
extra_kwargs = {
|
||||
'phone': {'required': True},
|
||||
'number': {'required': True},
|
||||
'photo': {'required': True},
|
||||
'id_number': {'required': True},
|
||||
}
|
||||
model = Remployee
|
||||
fields = ['name', 'phone', 'photo', 'id_number']
|
||||
# model = Employee
|
||||
# exclude = EXCLUDE_FIELDS + ['is_atwork', 'last_check_time',
|
||||
# 'not_work_remark', 'third_info', 'type']
|
||||
# extra_kwargs = {
|
||||
# 'phone': {'required': True},
|
||||
# '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(
|
||||
queryset=Employee.objects.filter(type='remployee'),
|
||||
many=True, label='员工ID列表'
|
||||
)
|
||||
queryset=Employee.objects.filter(type='remployee'),
|
||||
many=True, label='员工ID列表'
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Rpeople
|
||||
fields = ['employees', 'rproject']
|
||||
model = Rpjmember
|
||||
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__'
|
||||
|
|
|
@ -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()
|
||||
|
|
@ -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()
|
|
@ -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)),
|
||||
]
|
|
@ -1,11 +1,12 @@
|
|||
from django.shortcuts import render
|
||||
from apps.hrm.models import Certificate, Employee
|
||||
from apps.hrm.serializers import CertificateCreateUpdateSerializer, CertificateSerializer
|
||||
from apps.rpm.models import Remployee, Rparty, RpartyFile, Rpeople, Rproject
|
||||
from apps.rpm.serializers import RemployeeCreateUpdateSerializer, RpartyAssignSerializer, RpartyCreateUpdateSerializer, RpartyFileListSerializer, RpartySerializer, RpeopleCreatesSerializer, RprojectCreateUpdateSerializer
|
||||
from apps.hrm.serializers import CertificateCreateUpdateSerializer, CertificateSerializer, EmployeeSerializer
|
||||
from apps.rpm.models import Rcertificate, Remployee, Rparty, RpartyFile, Rpjmember, Rpj
|
||||
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.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.response import Response
|
||||
from django.contrib.auth.hashers import check_password, make_password
|
||||
|
@ -59,59 +60,61 @@ class RpartyFileViewSet(ListModelMixin, CustomGenericViewSet):
|
|||
return queryset
|
||||
|
||||
|
||||
class RemployeeViewSet(CustomModelViewSet):
|
||||
queryset = Employee.objects.filter(type='remployee')
|
||||
create_serializer_class = RemployeeCreateUpdateSerializer
|
||||
update_serializer_class = RemployeeCreateUpdateSerializer
|
||||
class RemployeeViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, CustomDestoryModelMixin,
|
||||
CustomGenericViewSet):
|
||||
queryset = Remployee.objects.all()
|
||||
create_serializer_class = RemployeeCreateSerializer
|
||||
serializer_class = RemployeeSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user
|
||||
queryset = super().get_queryset()
|
||||
if user.type == 'remployee':
|
||||
queryset = queryset.filter(belong_dept=user.belong_dept)
|
||||
queryset = queryset.filter(rparty=self.request.user.belong_dept)
|
||||
return queryset
|
||||
|
||||
@transaction.atomic
|
||||
def create(self, request, *args, **kwargs):
|
||||
"""
|
||||
添加人员
|
||||
"""
|
||||
user = self.request.user
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
vdata = serializer.validated_data
|
||||
if user.type == 'remployee': # 如果是相关方账号
|
||||
ep = serializer.save()
|
||||
Remployee.objects.get_or_create(employee=ep, rparty=user.belong_dept.rparty,
|
||||
defaults={
|
||||
"employee": ep,
|
||||
"rparty": user.belong_dept.rparty
|
||||
})
|
||||
else:
|
||||
if 'rparty' not in vdata:
|
||||
raise ParseError('未指定相关方')
|
||||
serializer.save()
|
||||
return Response(serializer.data, status=201)
|
||||
# @transaction.atomic
|
||||
# def create(self, request, *args, **kwargs):
|
||||
# """
|
||||
# 添加人员
|
||||
# """
|
||||
# user = self.request.user
|
||||
# serializer = self.get_serializer(data=request.data)
|
||||
# serializer.is_valid(raise_exception=True)
|
||||
# vdata = serializer.validated_data
|
||||
# if user.type == 'remployee': # 如果是相关方账号
|
||||
# ep = serializer.save()
|
||||
# Remployee.objects.get_or_create(employee=ep, rparty=user.belong_dept.rparty,
|
||||
# defaults={
|
||||
# "employee": ep,
|
||||
# "rparty": user.belong_dept.rparty
|
||||
# })
|
||||
# else:
|
||||
# if 'rparty' not in vdata:
|
||||
# raise ParseError('未指定相关方')
|
||||
# serializer.save()
|
||||
# return Response(serializer.data, status=201)
|
||||
|
||||
|
||||
class Rcertificate(CustomModelViewSet):
|
||||
queryset = Certificate.objects.filter(employee__type='remployee')
|
||||
create_serializer_class = CertificateCreateUpdateSerializer
|
||||
update_serializer_class = CertificateCreateUpdateSerializer
|
||||
serializer_class = CertificateSerializer
|
||||
class RcertificateViewSet(CustomModelViewSet):
|
||||
queryset = Rcertificate.objects.all()
|
||||
create_serializer_class = RcertificateCreateUpdateSerializer
|
||||
update_serializer_class = RcertificateCreateUpdateSerializer
|
||||
serializer_class = RcertificateSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user
|
||||
queryset = super().get_queryset()
|
||||
if user.type == 'remployee':
|
||||
queryset = queryset.filter(belong_dept=user.belong_dept)
|
||||
queryset = queryset.filter(remployee__rparty=user.belong_dept)
|
||||
return queryset
|
||||
|
||||
|
||||
class RprojectViewSet(CustomModelViewSet):
|
||||
queryset = Rproject.objects.all()
|
||||
create_serializer_class = RprojectCreateUpdateSerializer
|
||||
update_serializer_class = RprojectCreateUpdateSerializer
|
||||
class RpjViewSet(CustomModelViewSet):
|
||||
queryset = Rpj.objects.all()
|
||||
create_serializer_class = RpjCreateUpdateSerializer
|
||||
update_serializer_class = RpjCreateUpdateSerializer
|
||||
serializer_class = RpjListSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user
|
||||
|
@ -135,42 +138,26 @@ class RprojectViewSet(CustomModelViewSet):
|
|||
|
||||
def update(self, request, *args, **kwargs):
|
||||
obj = self.get_object()
|
||||
if obj.state == Rproject.RP_START:
|
||||
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:
|
||||
if obj.state != Rpj.RPJ_CREATE:
|
||||
raise ParseError('项目非创建状态不可更改')
|
||||
for i in vdata['employees']:
|
||||
Rpeople.objects.create(employee=i, rproject=rp)
|
||||
# 有证书的添加人员证书
|
||||
return super().update(request, *args, **kwargs)
|
||||
|
||||
return Response()
|
||||
|
||||
@action(methods=['put'], detail=True,
|
||||
perms_map={'put': 'rproject:update'}, serializer_class=serializers.Serializer)
|
||||
@transaction.atomic
|
||||
def make_manager(self, request):
|
||||
"""
|
||||
设为项目负责人
|
||||
"""
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
obj = self.get_object()
|
||||
if obj.rproject.state != Rproject.RP_START:
|
||||
raise ParseError('项目非创建状态不可更改')
|
||||
Rpeople.objects.filter(rproject=obj.rproject).update(is_manager=False)
|
||||
obj.is_manager = True
|
||||
obj.save()
|
||||
return Response()
|
||||
if obj.state != Rpj.RPJ_CREATE:
|
||||
raise ParseError('项目非创建状态不可删除')
|
||||
return super().destroy(request, *args, **kwargs)
|
||||
|
||||
|
||||
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)
|
||||
|
|
|
@ -11,6 +11,7 @@ from rest_framework.exceptions import ParseError
|
|||
from django.db import transaction
|
||||
from apps.third.tapis import dhapis
|
||||
from rest_framework.validators import UniqueValidator
|
||||
from django.conf import settings
|
||||
# from django_q.models import Task as QTask, Schedule as QSchedule
|
||||
|
||||
|
||||
|
@ -242,7 +243,7 @@ class DeptCreateUpdateSerializer(CustomModelSerializer):
|
|||
@transaction.atomic
|
||||
def create(self, validated_data):
|
||||
from apps.third.clients import dhClient
|
||||
if dhClient:
|
||||
if settings.DAHUA_ENABLED:
|
||||
data = {
|
||||
"parentId": 1,
|
||||
"name": validated_data['name'],
|
||||
|
@ -257,7 +258,7 @@ class DeptCreateUpdateSerializer(CustomModelSerializer):
|
|||
def update(self, instance, validated_data):
|
||||
from apps.third.clients import dhClient
|
||||
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 不存在
|
||||
data = {
|
||||
"parentId": 1,
|
||||
|
@ -269,7 +270,7 @@ class DeptCreateUpdateSerializer(CustomModelSerializer):
|
|||
instance.third_info = third_info
|
||||
instance.save()
|
||||
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 = {
|
||||
"id": instance.third_info['dh_id'],
|
||||
"parentId": 1,
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
),
|
||||
]
|
|
@ -18,15 +18,14 @@ class DhClient:
|
|||
|
||||
def __init__(self, client_id=settings.DAHUA_CLIENTID,
|
||||
client_secret=settings.DAHUA_SECRET) -> None:
|
||||
if not settings.DAHUA_ENABLED:
|
||||
return None
|
||||
self.client_id = client_id
|
||||
self.client_secret = client_secret
|
||||
self.headers = {}
|
||||
self.isGetingToken = False
|
||||
self.isRuning = True
|
||||
self.t = None # 线程
|
||||
self.setup()
|
||||
if settings.DAHUA_ENABLED:
|
||||
self.client_id = client_id
|
||||
self.client_secret = client_secret
|
||||
self.headers = {}
|
||||
self.isGetingToken = False
|
||||
self.isRuning = True
|
||||
self.t = None # 线程
|
||||
self.setup()
|
||||
|
||||
def _get_token_loop(self):
|
||||
while self.isRuning:
|
||||
|
@ -70,7 +69,7 @@ class DhClient:
|
|||
|
||||
def request(self, url: str, method: str, params=dict(), json=dict(), timeout=10,
|
||||
file_path_rela=None, raise_exception=True):
|
||||
if self is None:
|
||||
if not settings.DAHUA_ENABLED:
|
||||
raise ParseError('大华对接未启用')
|
||||
if self.isGetingToken:
|
||||
req_num = 0
|
||||
|
|
|
@ -152,7 +152,7 @@ class CommonBDModel(BaseModel):
|
|||
'system.user', null=True, blank=True, on_delete=models.SET_NULL,
|
||||
verbose_name='最后编辑人', related_name='%(class)s_update_by')
|
||||
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')
|
||||
|
||||
class Meta:
|
||||
|
|
|
@ -3,14 +3,14 @@ from django.core.cache import cache
|
|||
from rest_framework.decorators import action
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from rest_framework.mixins import (CreateModelMixin, ListModelMixin,
|
||||
RetrieveModelMixin, UpdateModelMixin)
|
||||
RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin)
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.viewsets import GenericViewSet
|
||||
|
||||
from apps.system.models import DataFilter, Dept
|
||||
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.queryset import get_child_queryset2
|
||||
from apps.utils.serializers import PkSerializer
|
||||
|
@ -101,7 +101,7 @@ class CustomGenericViewSet(MyLoggingMixin, GenericViewSet):
|
|||
|
||||
|
||||
class CustomModelViewSet(CreateModelMixin, UpdateModelMixin, ListModelMixin,
|
||||
RetrieveModelMixin, CustomDestoryModelMixin, CustomGenericViewSet):
|
||||
RetrieveModelMixin, DestroyModelMixin, CustomGenericViewSet):
|
||||
"""
|
||||
增强的ModelViewSet
|
||||
"""
|
||||
|
@ -126,6 +126,12 @@ class CustomModelViewSet(CreateModelMixin, UpdateModelMixin, ListModelMixin,
|
|||
pks = request_data.get('pks', None)
|
||||
if pks:
|
||||
self.get_queryset().filter(id__in=pks).delete(update_by=request.user)
|
||||
return Response()
|
||||
return Response(status=204)
|
||||
else:
|
||||
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)
|
||||
|
|
|
@ -17,15 +17,14 @@ class XxClient:
|
|||
"""
|
||||
|
||||
def __init__(self, licence=settings.XX_LICENCE, username=settings.XX_USERNAME) -> None:
|
||||
if not settings.XX_ENABLED:
|
||||
return None
|
||||
self.licence = licence
|
||||
self.username = username
|
||||
self.isGetingToken = False
|
||||
self.isRuning = True
|
||||
self.token = ''
|
||||
self.t = None
|
||||
self.setup()
|
||||
if settings.XX_ENABLED:
|
||||
self.licence = licence
|
||||
self.username = username
|
||||
self.isGetingToken = False
|
||||
self.isRuning = True
|
||||
self.token = ''
|
||||
self.t = None
|
||||
self.setup()
|
||||
|
||||
def _get_token_loop(self):
|
||||
while self.isRuning:
|
||||
|
@ -58,10 +57,10 @@ class XxClient:
|
|||
自定义销毁
|
||||
"""
|
||||
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):
|
||||
if self is None:
|
||||
if not settings.XX_ENABLED:
|
||||
raise ParseError('寻息对接未启用')
|
||||
params['accessToken'] = self.token
|
||||
json['username'] = self.username
|
||||
|
|
|
@ -15,17 +15,44 @@ class Visit(CommonBModel):
|
|||
(30, '面试'),
|
||||
(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('来访事由')
|
||||
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('来访时间')
|
||||
leave_time = models.DateTimeField('离开时间')
|
||||
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)
|
||||
visitor = models.ForeignKey(Employee, verbose_name='访客', on_delete=models.CASCADE)
|
||||
is_manager = models.BooleanField('是否主访人', default=False)
|
||||
visitor = models.ForeignKey(Visitor, verbose_name='访客', on_delete=models.CASCADE)
|
||||
is_main = models.BooleanField('是否主访人', default=False)
|
||||
|
|
|
@ -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__'
|
|
@ -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()
|
|
@ -1,3 +1,62 @@
|
|||
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.
|
||||
|
||||
|
||||
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)
|
||||
|
|
|
@ -12,6 +12,7 @@ pillow==9.0.1
|
|||
opencv-python==4.5.5.62
|
||||
daphne==3.0.2
|
||||
redis==4.1.4
|
||||
django-redis==5.2.0
|
||||
user-agents==2.2.0
|
||||
daphne==3.0.2
|
||||
channels==3.0.4
|
||||
|
|
|
@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/3.0/ref/settings/
|
|||
"""
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
import json
|
||||
import os
|
||||
from . import conf
|
||||
import logging
|
||||
|
@ -54,6 +55,7 @@ INSTALLED_APPS = [
|
|||
'apps.auth1',
|
||||
'apps.monitor',
|
||||
'apps.wf',
|
||||
'apps.ecm',
|
||||
'apps.hrm',
|
||||
'apps.am',
|
||||
'apps.vm',
|
||||
|
@ -194,8 +196,8 @@ REST_FRAMEWORK = {
|
|||
# 'UNAUTHENTICATED_TOKEN': None,
|
||||
'EXCEPTION_HANDLER': 'apps.utils.exceptions.custom_exception_hander',
|
||||
'DEFAULT_THROTTLE_RATES': {
|
||||
'anon': '1/second',
|
||||
'user': '2/second'
|
||||
'anon': '100/second',
|
||||
'user': '200/second'
|
||||
}
|
||||
}
|
||||
# simplejwt配置
|
||||
|
@ -214,16 +216,15 @@ AUTHENTICATION_BACKENDS = (
|
|||
)
|
||||
|
||||
# 缓存配置,有需要可更改为redis
|
||||
# CACHES = {
|
||||
# "default": {
|
||||
# "BACKEND": "django_redis.cache.RedisCache",
|
||||
# "LOCATION": "redis://redis:6379/1",
|
||||
# "OPTIONS": {
|
||||
# "CLIENT_CLASS": "django_redis.client.DefaultClient",
|
||||
# "PICKLE_VERSION": -1
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
CACHES = {
|
||||
"default": {
|
||||
"BACKEND": "django_redis.cache.RedisCache",
|
||||
"LOCATION": "redis://localhost:6379/2",
|
||||
"OPTIONS": {
|
||||
"CLIENT_CLASS": "django_redis.client.DefaultClient",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# celery配置,celery正常运行必须安装redis
|
||||
CELERY_BROKER_URL = "redis://localhost:6379/2" # 任务存储
|
||||
|
@ -257,8 +258,8 @@ CELERY_TASK_TRACK_STARTED = True
|
|||
|
||||
# swagger配置
|
||||
SWAGGER_SETTINGS = {
|
||||
'LOGIN_URL': '/django/login/',
|
||||
'LOGOUT_URL': '/django/logout/',
|
||||
'LOGIN_URL': '/django/admin/login/',
|
||||
'LOGOUT_URL': '/django/admin/logout/',
|
||||
}
|
||||
|
||||
# 日志配置
|
||||
|
|
|
@ -36,8 +36,8 @@ schema_view = get_schema_view(
|
|||
|
||||
urlpatterns = [
|
||||
# django后台
|
||||
path('django/doc/', include('django.contrib.admindocs.urls')),
|
||||
path('django/', admin.site.urls),
|
||||
path('django/admin/doc/', include('django.contrib.admindocs.urls')),
|
||||
path('django/admin/', admin.site.urls),
|
||||
path('django/api-auth/', include('rest_framework.urls')),
|
||||
|
||||
# api
|
||||
|
|
Loading…
Reference in New Issue