-
取消
+
+ 取消
确认
@@ -75,120 +121,130 @@
diff --git a/server/apps/supervision/migrations/0011_auto_20210330_1020.py b/server/apps/supervision/migrations/0011_auto_20210330_1020.py
new file mode 100644
index 0000000..1443eac
--- /dev/null
+++ b/server/apps/supervision/migrations/0011_auto_20210330_1020.py
@@ -0,0 +1,35 @@
+# Generated by Django 3.0.5 on 2021-03-30 02:20
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('supervision', '0010_auto_20210323_1425'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='record',
+ name='content_desc',
+ field=models.TextField(blank=True, null=True, verbose_name='材料详情'),
+ ),
+ migrations.AddField(
+ model_name='record',
+ name='content_name',
+ field=models.CharField(default='', max_length=100, verbose_name='材料名称'),
+ preserve_default=False,
+ ),
+ migrations.AlterField(
+ model_name='record',
+ name='content',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='record_content', to='supervision.Content', verbose_name='材料内容ID'),
+ ),
+ migrations.AlterField(
+ model_name='record',
+ name='note',
+ field=models.TextField(blank=True, null=True, verbose_name='上报要求'),
+ ),
+ ]
diff --git a/server/apps/supervision/migrations/0012_taskdept.py b/server/apps/supervision/migrations/0012_taskdept.py
new file mode 100644
index 0000000..974e215
--- /dev/null
+++ b/server/apps/supervision/migrations/0012_taskdept.py
@@ -0,0 +1,29 @@
+# Generated by Django 3.0.5 on 2021-03-30 03:46
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('system', '0008_auto_20210311_0919'),
+ ('supervision', '0011_auto_20210330_1020'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='TaskDept',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('up_rate', models.IntegerField(default=0, verbose_name='上报率')),
+ ('confirm_rate', models.IntegerField(default=0, verbose_name='确认率')),
+ ('dept', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='taskdept_dept', to='system.Organization', verbose_name='关联公司')),
+ ('task', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='taskdept_task', to='supervision.Task', verbose_name='关联任务')),
+ ],
+ options={
+ 'verbose_name': '任务部门视图',
+ 'verbose_name_plural': '任务部门视图',
+ },
+ ),
+ ]
diff --git a/server/apps/supervision/migrations/0013_auto_20210330_1200.py b/server/apps/supervision/migrations/0013_auto_20210330_1200.py
new file mode 100644
index 0000000..4027415
--- /dev/null
+++ b/server/apps/supervision/migrations/0013_auto_20210330_1200.py
@@ -0,0 +1,29 @@
+# Generated by Django 3.0.5 on 2021-03-30 04:00
+
+from django.db import migrations, models
+import django.utils.timezone
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('supervision', '0012_taskdept'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='taskdept',
+ name='create_time',
+ field=models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间'),
+ ),
+ migrations.AddField(
+ model_name='taskdept',
+ name='is_deleted',
+ field=models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记'),
+ ),
+ migrations.AddField(
+ model_name='taskdept',
+ name='update_time',
+ field=models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间'),
+ ),
+ ]
diff --git a/server/apps/supervision/migrations/0014_auto_20210330_1557.py b/server/apps/supervision/migrations/0014_auto_20210330_1557.py
new file mode 100644
index 0000000..5bffc5b
--- /dev/null
+++ b/server/apps/supervision/migrations/0014_auto_20210330_1557.py
@@ -0,0 +1,23 @@
+# Generated by Django 3.0.5 on 2021-03-30 07:57
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('supervision', '0013_auto_20210330_1200'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='content',
+ name='sortnum',
+ field=models.IntegerField(default=1, verbose_name='排序号'),
+ ),
+ migrations.AlterField(
+ model_name='task',
+ name='state',
+ field=models.CharField(choices=[('创建中', '创建中'), ('待发布', '待发布'), ('执行中', '执行中'), ('已关闭', '已关闭')], default='创建中', max_length=50, verbose_name='任务状态'),
+ ),
+ ]
diff --git a/server/apps/supervision/models.py b/server/apps/supervision/models.py
index d227363..0529509 100644
--- a/server/apps/supervision/models.py
+++ b/server/apps/supervision/models.py
@@ -11,6 +11,7 @@ class Content(CommonAModel):
desc = models.TextField('详情', null=True, blank=True)
type = models.ForeignKey(Dict, verbose_name='材料类型', on_delete= models.DO_NOTHING)
can_doself = models.BooleanField('可随时主动报送', default=False)
+ sortnum = models.IntegerField('排序号', default=1)
class Meta:
verbose_name = '报送清单'
@@ -25,7 +26,7 @@ class Task(CommonBModel):
('创建中', '创建中'),
('待发布', '待发布'),
('执行中', '执行中'),
- ('已完成', '已完成'),
+ ('已关闭', '已关闭'),
)
name = models.CharField('名称', max_length=100)
end_date = models.DateField('截止时间', null=True, blank=True)
@@ -40,6 +41,16 @@ class Task(CommonBModel):
verbose_name_plural = verbose_name
+class TaskDept(BaseModel):
+ task = models.ForeignKey(Task, verbose_name='关联任务', on_delete=models.CASCADE, related_name='taskdept_task')
+ dept = models.ForeignKey(Organization, verbose_name='关联公司', on_delete=models.CASCADE, related_name='taskdept_dept')
+ up_rate = models.IntegerField('上报率', default=0)
+ confirm_rate = models.IntegerField('确认率', default=0)
+ class Meta:
+ verbose_name = '任务部门视图'
+ verbose_name_plural = verbose_name
+
+
class Record(CommonBModel):
"""
上报记录
@@ -51,7 +62,9 @@ class Record(CommonBModel):
('已确认', '已确认'),
('待整改', '待整改')
)
- content = models.ForeignKey(Content, verbose_name='材料内容', on_delete=models.DO_NOTHING, related_name='record_content')
+ content = models.ForeignKey(Content, verbose_name='材料内容ID', on_delete=models.DO_NOTHING, related_name='record_content')
+ content_name = models.CharField('材料名称', max_length=100)
+ content_desc = models.TextField('材料详情', null=True, blank=True)
task = models.ForeignKey(Task, verbose_name='关联任务', null=True, blank=True, on_delete=models.SET_NULL, related_name='record_task')
is_self = models.BooleanField('是否主动报送', default=False)
up_date = models.DateField('上报时间', null=True, blank=True)
@@ -59,7 +72,7 @@ class Record(CommonBModel):
end_date = models.DateField('截止时间', null=True, blank=True)
state = models.CharField('记录状态', max_length=50, choices=state_choices, default='待上报')
is_yes = models.BooleanField('是否适用', default=True)
- note = models.TextField('上报备注', null=True, blank=True)
+ note = models.TextField('上报要求', null=True, blank=True)
noteb = models.TextField('上报说明', null=True, blank=True)
files = models.ManyToManyField(File, verbose_name="关联文件")
class Meta:
diff --git a/server/apps/supervision/serializers.py b/server/apps/supervision/serializers.py
index caca285..fe4837f 100644
--- a/server/apps/supervision/serializers.py
+++ b/server/apps/supervision/serializers.py
@@ -39,7 +39,6 @@ class TaskListSerializer(serializers.ModelSerializer):
class RecordSerializer(serializers.ModelSerializer):
task_ = TaskListSerializer(source='task')
- content_=ContentListSerializer(source='content')
belong_dept_ = OrganizationSimpleSerializer(source='belong_dept', read_only=True)
files_ = FileSimpleSerializer(source='files', many=True, read_only=True)
up_user_ = UserSimpleSerializer(source='up_user', read_only = True)
@@ -63,3 +62,10 @@ class TaksDetailSerializer(serializers.ModelSerializer):
class Meta:
model = Task
fields = '__all__'
+
+class TaskDeptSerializer(serializers.ModelSerializer):
+ dept_ = OrganizationSimpleSerializer(source='dept', read_only=True)
+
+ class Meta:
+ model = TaskDept
+ fields = '__all__'
\ No newline at end of file
diff --git a/server/apps/supervision/views.py b/server/apps/supervision/views.py
index 0483ca0..c089334 100644
--- a/server/apps/supervision/views.py
+++ b/server/apps/supervision/views.py
@@ -1,23 +1,25 @@
+from django.conf import settings
+from django.core.cache import cache
+from django.db.models import Count, Q
+from django.db.models.query import QuerySet
from django.shortcuts import render
+from django.utils import timezone
+from rest_framework import status
+from rest_framework.decorators import action
from rest_framework.mixins import ListModelMixin
+from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet, ModelViewSet
+from utils.pagination import PageOrNot
+
+from apps.system.mixins import CreateUpdateCustomMixin
+from apps.system.models import Organization
+from apps.system.permission import get_permission_list, has_permission
+from apps.system.permission_data import RbacFilterSet
+
+from .filters import RecordFilter
from .models import *
from .serializers import *
-from rest_framework.decorators import action
-from django.conf import settings
-from rest_framework import status
-from rest_framework.response import Response
-from apps.system.models import Organization
-from django.db.models import Count
-from utils.pagination import PageOrNot
-from apps.system.mixins import CreateUpdateCustomMixin
-from apps.system.permission_data import RbacFilterSet
-from django.utils import timezone
-from .filters import RecordFilter
-from django.db.models.query import QuerySet
-from django.core.cache import cache
-from apps.system.permission import get_permission_list, has_permission
-from django.db.models import Q
+
# Create your views here.
class ContentViewSet(CreateUpdateCustomMixin, ModelViewSet):
@@ -50,6 +52,7 @@ class TaskViewSet(CreateUpdateCustomMixin, ModelViewSet):
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
instance.delete()
+ TaskDept.objects.filter(task=instance).delete()
Record.objects.filter(task=instance).delete()
return Response(status=status.HTTP_204_NO_CONTENT)
@@ -63,16 +66,25 @@ class TaskViewSet(CreateUpdateCustomMixin, ModelViewSet):
contents = request.data['contents']
if depts and contents:
record_list = []
+ taskdept_list = []
for m in depts:
+ xdata = {}
+ xdata['task'] = obj
+ xdata['dept'] = Organization.objects.get(pk=m)
+ taskdept_list.append(TaskDept(**xdata))
for n in contents:
data={}
- data['content'] = Content.objects.get(pk=n)
+ content = Content.objects.get(pk=n)
+ data['content'] = content
+ data['content_name'] = content.name
+ data['content_desc'] = content.desc
data['belong_dept'] = Organization.objects.get(pk=m)
data['task'] = obj
data['end_date'] = obj.end_date
data['create_by'] = request.user
data['state'] = '待发布'
record_list.append(Record(**data))
+ TaskDept.objects.bulk_create(taskdept_list)
Record.objects.bulk_create(record_list)
obj.state = '待发布'
obj.save()
@@ -109,21 +121,50 @@ class TaskViewSet(CreateUpdateCustomMixin, ModelViewSet):
Record.objects.filter(task=obj).update(state='待上报')
return Response(status=status.HTTP_200_OK)
return Response('任务状态错误', status=status.HTTP_400_BAD_REQUEST)
+
+ @action(methods=['get'], detail=True, perms_map = {'get':'*'})
+ def deptall(self, request, *args, **kwargs):
+ obj = self.get_object()
+ serializer = TaskDeptSerializer(TaskDept.objects.filter(task=obj).order_by('dept__sort'), many=True)
+ return Response(serializer.data)
+
+ @action(methods=['put'], detail=True, perms_map = {'put':'task_close'})
+ def close(self, request, *args, **kwargs):
+ """
+ 关闭任务
+ """
+ obj = self.get_object()
+ if obj.state == '执行中':
+ obj.state = '已关闭'
+ obj.save()
+ return Response(status=status.HTTP_200_OK)
+ return Response('任务状态错误', status=status.HTTP_400_BAD_REQUEST)
-def cal_task_rate(task):
+def cal_task_rate(task, dept):
"""
计算任务上报率, 确认率
+ 传入任务及公司
"""
objs = Record.objects.filter(task=task)
- if objs.exists():
- count = objs.count()
- up_rate = objs.filter(state__in=['已确认','已上报']).count()/count
- confirm_rate = objs.filter(state='已确认').count()/count
- task.up_rate = int(up_rate*100)
- task.confirm_rate = int(confirm_rate*100)
- if task.confirm_rate == 100:
- task.state ='已完成'
- task.save()
+ # if objs.exists():
+ # count = objs.count()
+ # up_rate = objs.filter(state__in=['已确认','已上报']).count()/count
+ # confirm_rate = objs.filter(state='已确认').count()/count
+ # task.up_rate = int(up_rate*100)
+ # task.confirm_rate = int(confirm_rate*100)
+ # if task.confirm_rate == 100:
+ # task.state ='已完成'
+ # task.save()
+ objs = Record.objects.filter(task=task).filter(belong_dept=dept)
+ count = objs.count()
+ up_rate = objs.filter(state__in=['已确认','已上报']).count()/count
+ confirm_rate = objs.filter(state='已确认').count()/count
+ instance = TaskDept.objects.get(task=task,dept=dept)
+ instance.up_rate = int(up_rate*100)
+ instance.confirm_rate = int(confirm_rate*100)
+ instance.save()
+from utils.queryset import get_child_queryset2
+
class RecordViewSet(RbacFilterSet, PageOrNot, CreateUpdateCustomMixin, ModelViewSet):
perms_map = {'get': '*', 'post': 'record_create',
@@ -131,9 +172,33 @@ class RecordViewSet(RbacFilterSet, PageOrNot, CreateUpdateCustomMixin, ModelView
queryset = Record.objects.all()
serializer_class = RecordSerializer
search_fields = ['content__name','task__name']
- ordering = ['-create_time']
+ ordering_fields = ['content__sortnum', 'belong_dept__sort']
+ ordering = ['content__sortnum', '-create_time']
filter_class = RecordFilter # 过滤类
+ def get_queryset(self):
+ queryset = self.queryset
+ if hasattr(self.get_serializer_class(), 'setup_eager_loading'):
+ queryset = self.get_serializer_class().setup_eager_loading(queryset)
+ if self.request.user.is_superuser:
+ pass
+ if hasattr(queryset.model, 'belong_dept'):
+ user = self.request.user
+ roles = user.roles
+ data_range = roles.values_list('datas', flat=True)
+ if '全部' in data_range:
+ pass
+ elif '本级及以下' in data_range:
+ belong_depts = get_child_queryset2(user.dept)
+ queryset = queryset.filter(belong_dept__in = belong_depts)
+ elif '本级' in data_range:
+ queryset = queryset.filter(belong_dept = user.dept)
+ if not self.request.query_params.get('pageoff', None):
+ queryset = queryset.exclude(state='待发布')
+ if self.request.query_params.get('only', None) == 'true':
+ queryset = queryset.filter(belong_dept = user.dept)
+ return queryset
+
@action(methods=['get'], detail=False, perms_map = {'get':'*'})
def todos(self, request, *args, **kwargs):
ret={}
@@ -151,6 +216,13 @@ class RecordViewSet(RbacFilterSet, PageOrNot, CreateUpdateCustomMixin, ModelView
instance.save()
return Response(status=status.HTTP_200_OK)
+ @action(methods=['put'], detail=False, perms_map = {'post':'record_update'})
+ def updates(self, request, *args, **kwargs):
+ ids = request.data.get('ids')
+ note = request.data.get('note', None)
+ Record.objects.filter(pk__in=ids).update(note=note)
+ return Response(status=status.HTTP_200_OK)
+
@action(methods=['post'], detail=False, perms_map = {'post':'record_createself'})
def createself(self, request, *args, **kwargs):
contents = request.data['contents']
@@ -167,9 +239,11 @@ class RecordViewSet(RbacFilterSet, PageOrNot, CreateUpdateCustomMixin, ModelView
上报
"""
obj = self.get_object()
+ if obj.task and obj.task.state == '已关闭':
+ return Response('该任务已关闭,无法上报', status=status.HTTP_400_BAD_REQUEST)
if obj.state in ['待整改','待上报']:
- if 'files' in request.data and len(request.data['files'])==0:
- if request.data.get('noteb', None) and request.data.get('is_yes', True):
+ if 'files' in request.data and (not request.data['files']):
+ if request.data.get('noteb', None) and (not request.data.get('is_yes', True)):
pass
else:
return Response('请上传文件或选择不适用并填写上报说明', status=status.HTTP_400_BAD_REQUEST)
@@ -182,7 +256,7 @@ class RecordViewSet(RbacFilterSet, PageOrNot, CreateUpdateCustomMixin, ModelView
obj.up_date = timezone.now()
obj.save()
if obj.task:
- cal_task_rate(obj.task)
+ cal_task_rate(obj.task, obj.belong_dept)
return Response(status=status.HTTP_200_OK)
return Response('记录状态错误', status=status.HTTP_400_BAD_REQUEST)
@@ -198,7 +272,7 @@ class RecordViewSet(RbacFilterSet, PageOrNot, CreateUpdateCustomMixin, ModelView
obj.state = '待整改'
obj.save()
if obj.task:
- cal_task_rate(obj.task)
+ cal_task_rate(obj.task, obj.belong_dept)
return Response(status=status.HTTP_200_OK)
else:
return Response('请填写备注', status=status.HTTP_400_BAD_REQUEST)
@@ -214,7 +288,7 @@ class RecordViewSet(RbacFilterSet, PageOrNot, CreateUpdateCustomMixin, ModelView
obj.state = '已确认'
obj.save()
if obj.task:
- cal_task_rate(obj.task)
+ cal_task_rate(obj.task, obj.belong_dept)
return Response(status=status.HTTP_200_OK)
return Response('记录状态错误', status=status.HTTP_400_BAD_REQUEST)
diff --git a/server/apps/system/migrations/0009_organization_can_supervision.py b/server/apps/system/migrations/0009_organization_can_supervision.py
new file mode 100644
index 0000000..0e66e43
--- /dev/null
+++ b/server/apps/system/migrations/0009_organization_can_supervision.py
@@ -0,0 +1,18 @@
+# Generated by Django 3.0.5 on 2021-03-30 08:34
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('system', '0008_auto_20210311_0919'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='organization',
+ name='can_supervision',
+ field=models.BooleanField(default=False, verbose_name='是否可监督'),
+ ),
+ ]
diff --git a/server/apps/system/models.py b/server/apps/system/models.py
index 64159e8..3987b9b 100644
--- a/server/apps/system/models.py
+++ b/server/apps/system/models.py
@@ -65,6 +65,7 @@ class Organization(SoftModel):
pid = models.ForeignKey('self', null=True, blank=True,
on_delete=models.SET_NULL, verbose_name='父')
sort = models.IntegerField('排序', default=1)
+ can_supervision = models.BooleanField('是否可监督', default=False)
class Meta:
verbose_name = '组织架构'
verbose_name_plural = verbose_name
diff --git a/server/apps/system/serializers.py b/server/apps/system/serializers.py
index 052f8c1..477df9f 100644
--- a/server/apps/system/serializers.py
+++ b/server/apps/system/serializers.py
@@ -70,8 +70,7 @@ class OrganizationSerializer(serializers.ModelSerializer):
"""
组织架构序列化
"""
- type = serializers.ChoiceField(
- choices=Organization.organization_type_choices, default='部门')
+ type = serializers.ChoiceField(choices=Organization.organization_type_choices, default='部门')
class Meta:
model = Organization
diff --git a/server/apps/system/views.py b/server/apps/system/views.py
index b218405..83f3e22 100644
--- a/server/apps/system/views.py
+++ b/server/apps/system/views.py
@@ -198,7 +198,7 @@ class OrganizationViewSet(PageOrNot,ModelViewSet):
serializer_class = OrganizationSerializer
pagination_class = None
search_fields = ['name']
- filterset_fields = ['pid','name']
+ filterset_fields = ['pid','name', 'type','can_supervision']
ordering_fields = ['sort']
ordering = ['sort', 'pk']