diff --git a/server/apps/__init__.py b/server/apps/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/apps/ability/migrations/0025_qaction_qactionitem_qorg_qtask_quali_qualilib.py b/server/apps/ability/migrations/0025_qaction_qactionitem_qorg_qtask_quali_qualilib.py new file mode 100644 index 0000000..11f175a --- /dev/null +++ b/server/apps/ability/migrations/0025_qaction_qactionitem_qorg_qtask_quali_qualilib.py @@ -0,0 +1,138 @@ +# Generated by Django 3.0.5 on 2022-05-16 02:44 + +from django.conf import settings +import django.contrib.postgres.fields.jsonb +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('system', '0020_auto_20220513_0926'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('ability', '0024_auto_20220316_0858'), + ] + + operations = [ + migrations.CreateModel( + name='QualiLib', + fields=[ + ('id', models.AutoField(auto_created=True, 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='名称')), + ('levels', django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=list, null=True, verbose_name='等级')), + ('scopes', django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=list, null=True, verbose_name='范围')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='Quali', + fields=[ + ('id', models.AutoField(auto_created=True, 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=[('CMA', 'CMA'), ('CNAS', 'CNAS'), ('OTHER', 'OTHER')], verbose_name='资质类型')), + ('grade', models.PositiveSmallIntegerField(verbose_name='等级')), + ('scope', models.TextField(blank=True, null=True, verbose_name='范围')), + ('level', models.CharField(max_length=10, verbose_name='等级')), + ('description', models.TextField(blank=True, null=True, verbose_name='描述')), + ('end_date', models.DateField(blank=True, null=True, verbose_name='截至日期')), + ('city', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='quali_city', to='system.City')), + ('citys', models.ManyToManyField(related_name='quali_citys', to='system.City', verbose_name='备案城市')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='quali_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('org', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='system.Organization', verbose_name='所属单位')), + ('province', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='system.Province')), + ('qualilib', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='ability.QualiLib', verbose_name='关联资质库')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='quali_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='QTask', + fields=[ + ('id', models.AutoField(auto_created=True, 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=100, verbose_name='名称')), + ('end_date', models.DateField(blank=True, null=True, verbose_name='截止时间')), + ('state', models.CharField(choices=[('待发布', '待发布'), ('进行中', '进行中'), ('已关闭', '已关闭')], default='待发布', max_length=50, verbose_name='任务状态')), + ('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='qtask_belong_dept', to='system.Organization', verbose_name='所属部门')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='qtask_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='qtask_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'verbose_name': '资质报送任务', + 'verbose_name_plural': '资质报送任务', + }, + ), + migrations.CreateModel( + name='QOrg', + fields=[ + ('id', models.AutoField(auto_created=True, 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='删除标记')), + ('count', models.PositiveIntegerField(default=0)), + ('count_confirmed', models.PositiveIntegerField(default=0)), + ('org', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='qorg_org', to='system.Organization', verbose_name='关联公司')), + ('qtask', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='qorg_qtask', to='ability.QTask', verbose_name='关联任务')), + ], + options={ + 'verbose_name': '资质报送任务部门', + 'verbose_name_plural': '资质报送任务部门', + }, + ), + migrations.CreateModel( + name='QActionItem', + fields=[ + ('id', models.AutoField(auto_created=True, 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='删除标记')), + ('action', models.PositiveSmallIntegerField(blank=True, choices=[('update', '更新'), ('citys:add', '新增备案城市'), ('citys:remove', '移除备案城市')], null=True, verbose_name='操作类型')), + ('field', models.CharField(max_length=20, verbose_name='变动字段')), + ('value1', django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=dict, null=True, verbose_name='原值')), + ('value2', django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=dict, null=True, verbose_name='新值')), + ('city', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='system.City')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='QAction', + fields=[ + ('id', models.AutoField(auto_created=True, 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='删除标记')), + ('action', models.CharField(choices=[('service:update', '更新服务'), ('quali:create', '新增资质'), ('quali:update', '更新资质'), ('ablity:create', '新增能力')], max_length=20, verbose_name='操作类型')), + ('num', models.PositiveIntegerField(blank=True, null=True, verbose_name='新增能力数量')), + ('value1', django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=dict, null=True, verbose_name='值1')), + ('value2', django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=dict, null=True, verbose_name='值2')), + ('confirmed', models.BooleanField(default=False, verbose_name='是否确认')), + ('afield', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='quali_afield', to='system.Dict', verbose_name='所属领域')), + ('atype', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='quali_atype', to='system.Dict', verbose_name='能力类型')), + ('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='qaction_belong_dept', to='system.Organization', verbose_name='所属部门')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='qaction_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('file', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='system.File', verbose_name='能力文件')), + ('qtask', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ability.QOrg')), + ('quali', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='ability.Quali', verbose_name='操作资质')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='qaction_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/server/apps/ability/migrations/0026_qactionitem_qaction.py b/server/apps/ability/migrations/0026_qactionitem_qaction.py new file mode 100644 index 0000000..8b6b963 --- /dev/null +++ b/server/apps/ability/migrations/0026_qactionitem_qaction.py @@ -0,0 +1,19 @@ +# Generated by Django 3.0.5 on 2022-05-16 03:35 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('ability', '0025_qaction_qactionitem_qorg_qtask_quali_qualilib'), + ] + + operations = [ + migrations.AddField( + model_name='qactionitem', + name='qaction', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='items_qaction', to='ability.QAction', verbose_name='关联操作'), + ), + ] diff --git a/server/apps/ability/models.py b/server/apps/ability/models.py index e0c2f87..5f0216b 100644 --- a/server/apps/ability/models.py +++ b/server/apps/ability/models.py @@ -1,8 +1,8 @@ -from datetime import MAXYEAR + +from apps.system.models import City, Dict, Province from django.db import models -from django.db.models.fields import related from utils.model import BaseModel -from apps.system.models import Organization, User +from apps.system.models import CommonAModel, CommonBModel, File, Organization, User # Create your models here. from django.contrib.postgres.fields import JSONField @@ -121,3 +121,108 @@ class Qualificationother(BaseModel): qualification = models.ForeignKey(Qualification, on_delete=models.CASCADE, related_name='other_qualification') name = models.TextField('其他资质', null=True, blank=True) description = models.TextField('资质范围', null=True, blank=True) + +class QualiLib(BaseModel): + """ + 资质库 + """ + name = models.CharField('名称', max_length=20) + levels = JSONField('等级', default=list, null=True, blank=True) + scopes = JSONField('范围', default=list, null=True, blank=True) + + +class Quali(CommonAModel): + """ + 资质 + """ + QUALI_TYPE_CHOICES=( + ('CMA', 'CMA'), + ('CNAS', 'CNAS'), + ('OTHER', 'OTHER') + ) + QUALI_GRADE_CHOICES = ( + (10, '国家级'), + (20, '省级'), + (30, '市级') + ) + org = models.ForeignKey(Organization, on_delete=models.CASCADE, verbose_name='所属单位') + name = models.CharField('资质名称', max_length=20) + type = models.PositiveSmallIntegerField('资质类型', choices=QUALI_TYPE_CHOICES) + grade = models.PositiveSmallIntegerField('等级') + scope = models.TextField('范围', null=True, blank=True) + level = models.CharField('等级', max_length=10) + province = models.ForeignKey(Province, on_delete=models.SET_NULL, null=True, blank=True) + city = models.ForeignKey(City, on_delete=models.SET_NULL, null=True, blank=True, related_name='quali_city') + citys = models.ManyToManyField(City, verbose_name='备案城市', related_name='quali_citys') + description = models.TextField('描述', null=True, blank=True) + qualilib = models.ForeignKey(QualiLib, verbose_name='关联资质库', + null=True, blank=True, on_delete=models.SET_NULL) + end_date = models.DateField('截至日期', null=True, blank=True) + + +class QTask(CommonBModel): + """ + 资质报送任务 + """ + state_choices = ( + ('待发布', '待发布'), + ('进行中', '进行中'), + ('已关闭', '已关闭'), + ) + name = models.CharField('名称', max_length=100) + end_date = models.DateField('截止时间', null=True, blank=True) + state = models.CharField('任务状态', max_length=50, choices=state_choices, default='待发布') + class Meta: + verbose_name = '资质报送任务' + verbose_name_plural = verbose_name + + +class QOrg(BaseModel): + qtask = models.ForeignKey(QTask, verbose_name='关联任务', on_delete=models.CASCADE, related_name='qorg_qtask') + org = models.ForeignKey(Organization, verbose_name='关联公司', on_delete=models.CASCADE, related_name='qorg_org') + count = models.PositiveIntegerField(default=0) + count_confirmed = models.PositiveIntegerField(default=0) + class Meta: + verbose_name = '资质报送任务部门' + verbose_name_plural = verbose_name + + +class QAction(CommonBModel): + """ + 任务操作 + """ + QACTION_CHOICE = ( + ('service:update', '更新服务'), + ('quali:create', '新增资质'), + ('quali:update', '更新资质'), + ('ablity:create', '新增能力'), + ) + action = models.CharField('操作类型', max_length=20, choices=QACTION_CHOICE) + quali = models.ForeignKey(Quali, null=True, blank=True, verbose_name='操作资质', on_delete=models.CASCADE) + file = models.ForeignKey(File, null=True, blank=True, verbose_name='能力文件', on_delete=models.CASCADE) + atype = models.ForeignKey(Dict, null=True, blank=True, verbose_name='能力类型', + on_delete=models.CASCADE, related_name='quali_atype') + afield = models.ForeignKey(Dict, null=True, blank=True, verbose_name='所属领域', + on_delete=models.CASCADE, related_name='quali_afield') + num = models.PositiveIntegerField('新增能力数量', null=True, blank=True) + qtask = models.ForeignKey(QOrg, on_delete=models.CASCADE) + value1 = JSONField('值1', null=True, blank=True, default=dict) + value2 = JSONField('值2', null=True, blank=True, default=dict) + confirmed = models.BooleanField('是否确认',default=False) + + +class QActionItem(BaseModel): + QACTIONITEM_CHOICE = ( + ('update', '更新'), + ('citys:add', '新增备案城市'), + ('citys:remove', '移除备案城市'), + ) + action = models.PositiveSmallIntegerField('操作类型', null=True, blank=True, choices=QACTIONITEM_CHOICE) + field = models.CharField('变动字段', max_length=20) + value1 = JSONField('原值', null=True, blank=True, default=dict) + value2 = JSONField('新值', null=True, blank=True, default=dict) + city = models.ForeignKey(City, on_delete=models.SET_NULL, null=True, blank=True) + qaction = models.ForeignKey(QAction, verbose_name='关联操作', + on_delete=models.CASCADE, related_name='items_qaction', null=True, blank=True) + + diff --git a/server/apps/ability/serializers.py b/server/apps/ability/serializers.py index 7e7f2b5..7fb5cae 100644 --- a/server/apps/ability/serializers.py +++ b/server/apps/ability/serializers.py @@ -80,4 +80,5 @@ class CorrectSerializer(serializers.ModelSerializer): def setup_eager_loading(queryset): """ Perform necessary eager loading of data. """ queryset = queryset.select_related('ssbm') - return queryset \ No newline at end of file + return queryset + diff --git a/server/apps/ability/serializers_qtask.py b/server/apps/ability/serializers_qtask.py new file mode 100644 index 0000000..3a4f3e0 --- /dev/null +++ b/server/apps/ability/serializers_qtask.py @@ -0,0 +1,153 @@ +from rest_framework import serializers + +from apps.system.models import City, Organization +from .models import QAction, QActionItem, QOrg, QTask, Quali, QualiLib +from django.db import transaction +from apps.system.serializers import OrganizationSimpleSerializer, DictSerializer +from rest_framework.exceptions import ParseError + + +class QualiLibListSerializer(serializers.ModelSerializer): + class Meta: + model = QualiLib + fields = '__all__' + +class QualiListSerializer(serializers.ModelSerializer): + province_name = serializers.CharField(source='province.name', read_only=True) + city_name = serializers.CharField(source='city.name', read_only=True) + service = serializers.CharField(source='org.service', read_only=True) + class Meta: + model = Quali + fields = '__all__' + + +class QTaskCreateUpdateSerializer(serializers.ModelSerializer): + orgs = serializers.PrimaryKeyRelatedField(label='上报公司ID列表', + queryset = Organization.objects.all(), many=True) + class Meta: + model = QTask + fields = ['name', 'end_date', 'orgs'] + + @transaction.atomic + def create(self, validated_data): + orgs = validated_data.pop('orgs') + validated_data['state'] = '待发布' + instance = super().create(validated_data) + for i in orgs: + QOrg.objects.get_or_create(qtask=instance, org=i, + defaults={'qtask': instance, 'org': i}) + return instance + + @transaction.atomic + def update(self, instance, validated_data): + if instance.state == '已关闭': + raise ParseError('任务已关闭,不可更改') + orgs = validated_data.pop('orgs') + instance = super().update(instance, validated_data) + for i in orgs: + QOrg.objects.get_or_create(qtask=instance, org=i, + defaults={'qtask': instance, 'org': i}) + return instance + + +class QTaskListSerializer(serializers.ModelSerializer): + orgs_count = serializers.SerializerMethodField() + + class Meta: + model = QTask + fields = '__all__' + + def get_orgs_count(self, obj): + count = QOrg.objects.filter(qtask=obj).count() + return count + +class QTaskSimpleSerializer(serializers.ModelSerializer): + class Meta: + model = QTask + fields = '__all__' + +class QOrgListSerializer(serializers.ModelSerializer): + org_ = OrganizationSimpleSerializer(source='org', read_only=True) + qtask_ = QTaskSimpleSerializer(source='qtask', read_only=True) + class Meta: + model = QOrg + fields = '__all__' + + +class QActionListSerializer(serializers.ModelSerializer): + quali_name = serializers.CharField(source='quali.name', read_only=True) + atype_name = serializers.CharField(source='atype.name', read_only=True) + afield_name = serializers.CharField(source='afield.name', read_only=True) + class Meta: + model = QAction + fields = '__all__' + + +class QActionServiceSerializer(serializers.ModelSerializer): + class Meta: + model = QAction + fields = ['qtask', 'value2'] + + def create(self, validated_data): + validated_data['action'] = 'service:update' + return super().create(validated_data) + +class QualiCreateSerializer(serializers.ModelSerializer): + citys = serializers.PrimaryKeyRelatedField(queryset=City.objects.all(), many=True, label='城市ID列表') + class Meta: + model = Quali + fields = ['name', 'type', 'grade', 'scope', 'level', 'province', 'city', 'description', 'citys'] + +class QualiUpdateSerializer(serializers.ModelSerializer): + citys = serializers.PrimaryKeyRelatedField(queryset=City.objects.all(), many=True, label='城市ID列表') + class Meta: + model = Quali + fields = ['name', 'type', 'grade', 'scope', 'level', 'province', 'city', 'description', 'id', 'citys'] + +class QualiSerializer(serializers.ModelSerializer): + class Meta: + model = Quali + fields = '__all__' + +class QActionQualiCreateSerializer(serializers.ModelSerializer): + value2 = QualiCreateSerializer() + class Meta: + model = QAction + fields = ['qtask', 'value2'] + + def create(self, validated_data): + validated_data['action'] = 'quali:create' + return super().create(validated_data) + +class QActionQualiUpdateSerializer(serializers.ModelSerializer): + value2 = QualiUpdateSerializer() + class Meta: + model = QAction + fields = ['qtask', 'value2'] + + def create(self, validated_data): + validated_data['action'] = 'quali:create' + return super().create(validated_data) + +class QActionACreateSerializer(serializers.ModelSerializer): + class Meta: + model = QAction + fields = ['atype', 'afield', 'file', 'num', 'qtask'] + extra_kwargs = {'atype': {'required': True}, 'afield': {'required': True}, 'file': {'required': True}} + + def create(self, validated_data): + validated_data['action'] = 'ablity:create' + return super().create(validated_data) + + +class QActionItemSerializer(serializers.ModelSerializer): + class Meta: + model = QActionItem + fields = ['action', 'field', 'value1', 'value2', 'city'] + + +class QActionDetailSerializer(serializers.ModelSerializer): + update_detail = QActionItemSerializer(source='items_qaction', many=True, read_only=True) + class Meta: + model = QAction + fields ='__all__' \ No newline at end of file diff --git a/server/apps/ability/urls.py b/server/apps/ability/urls.py index 4786208..0c96777 100644 --- a/server/apps/ability/urls.py +++ b/server/apps/ability/urls.py @@ -1,6 +1,8 @@ from django.db.models import base from django.urls import path, include from rest_framework import routers + +from apps.ability.views_qtask import QActionViewSet, QOrgViewSet, QualiLibViewSet, QualiViewSet from .views import AbilityContentViewSet, AbilityRecordViewSet, CMAViewSet, CNASViewSet, CorrectViewSet, QualificationViewSet,InspectionViewSet,QualificationotherViewSet, QueryRecordListViewSet, correct_ability, correct_cma, merge_cma, merge_cnas router = routers.DefaultRouter() @@ -13,6 +15,10 @@ router.register('queryrecord', QueryRecordListViewSet, basename="queryrecord") router.register('correct', CorrectViewSet, basename="correct") router.register('content', AbilityContentViewSet, basename="abilitycontent") router.register('record', AbilityRecordViewSet, basename="abilityrecord") +router.register('qualilib', QualiLibViewSet), +router.register('quali', QualiViewSet), +router.register('qorg', QOrgViewSet), +router.register('qaction', QActionViewSet) urlpatterns = [ path('merge/cma/', merge_cma), path('merge/cnas/', merge_cnas), diff --git a/server/apps/ability/views_qtask.py b/server/apps/ability/views_qtask.py new file mode 100644 index 0000000..036ca9a --- /dev/null +++ b/server/apps/ability/views_qtask.py @@ -0,0 +1,223 @@ +from rest_framework.viewsets import GenericViewSet +from rest_framework.mixins import ListModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin, RetrieveModelMixin +from rest_framework.decorators import action +from apps.ability.models import QAction, QActionItem, QOrg, QTask, Quali, QualiLib +from apps.ability.serializers_qtask import QActionDetailSerializer, QActionListSerializer, QActionQualiCreateSerializer, QActionQualiUpdateSerializer, QActionServiceSerializer, QOrgListSerializer, QTaskCreateUpdateSerializer, QTaskListSerializer, QualiCreateSerializer, QualiLibListSerializer, QualiListSerializer, QualiSerializer, QualiUpdateSerializer +from django.db import transaction +from rest_framework.response import Response +from rest_framework import status +from apps.system.mixins import CreateUpdateCustomMixin +from utils.pagination import PageOrNot +from rest_framework.exceptions import ParseError +from rest_framework import serializers +from rest_framework.exceptions import ParseError + +class QualiLibViewSet(PageOrNot, ListModelMixin, GenericViewSet): + perms_map = {'get': '*'} + queryset = QualiLib.objects.all() + serializer_class = QualiLibListSerializer + search_fields = ['name'] + ordering = ['-create_time'] + +class QualiViewSet(ListModelMixin, GenericViewSet): + perms_map = {'get': '*'} + queryset = Quali.objects.all() + serializer_class = QualiListSerializer + search_fields = ['name', 'type', 'grade'] + ordering = ['org__sort'] + +class QTaskViewSet(CreateUpdateCustomMixin, CreateModelMixin, ListModelMixin, UpdateModelMixin, GenericViewSet): + perms_map = {'get': 'qtask_view', 'post': 'qtask_create'} + queryset = QTask.objects.all() + serializer_class = QTaskListSerializer + ordering = ['-create_time'] + + def get_serializer_class(self): + if self.action in ['create', 'update']: + return QTaskCreateUpdateSerializer + return super().get_serializer_class() + + @action(methods=['put'], detail=True, perms_map = {'put':'qtask_start'}) + @transaction.atomic + def start(self, request, *args, **kwargs): + """ + 发布任务 + """ + obj = self.get_object() + if obj.state == '待发布': + obj.state = '进行中' + obj.save() + QOrg.objects.filter(qtask=obj).update(state='待报送') + return Response() + return Response('任务状态错误', status=status.HTTP_400_BAD_REQUEST) + +class QOrgViewSet(ListModelMixin, GenericViewSet): + perms_map = {'get': 'qtask_view'} + queryset = QOrg.objects.select_related('qtask', 'org') + filterset_fields = ['qtask', 'org', 'qtask__state'] + serializer_class = QOrgListSerializer + ordering = ['-create_time'] + + @action(methods=['get'], detail=False, perms_map = {'post':'qtask_my'}) + def my(self, request, *args, **kwargs): + """ + 我的报送任务 + """ + user = self.request.user + queryset = self.filter_queryset(self.get_queryset().filter(org=user.dept)) + + page = self.paginate_queryset(queryset) + if page is not None: + serializer = self.get_serializer(page, many=True) + return self.get_paginated_response(serializer.data) + + serializer = self.get_serializer(queryset, many=True) + return Response(serializer.data) + +def cal_count(qtask, org): + qs = QAction.objects.filter(qtask=qtask, belong_dept=org) + qorg = QOrg.objects.get(qtask=qtask, org=org) + qorg.count = qs.count() + qorg.count_confirmed = qs.filter(confirmed=True).count() + qorg.save() + + +class QActionViewSet(PageOrNot, ListModelMixin, DestroyModelMixin, RetrieveModelMixin,GenericViewSet): + perms_map = {'get': 'qtask_view'} + queryset = QAction.objects.select_related('file', 'atype', 'afield', 'qtask', 'belong_dept') + filterset_fields = ['qtask', 'belong_dept', 'atype', 'afield'] + + def get_serializer_class(self): + if self.action == 'list': + return QActionListSerializer + elif self.action == 'retrieve': + return QActionDetailSerializer + return super().get_serializer_class() + + @action(methods=['get'], detail=False, perms_map = {'post':'qaction_my'}) + def my(self, request, *args, **kwargs): + """ + 我的报送操作 + """ + user = self.request.user + queryset = self.filter_queryset(self.get_queryset().filter(belong_dept=user.dept)) + + page = self.paginate_queryset(queryset) + if page is not None: + serializer = self.get_serializer(page, many=True) + return self.get_paginated_response(serializer.data) + + serializer = self.get_serializer(queryset, many=True) + return Response(serializer.data) + + def perform_destroy(self, instance): + if not instance.confirmed: + instance.delete(soft=False) + raise ParseError('报送已确认, 不可删除') + + @action(methods=['post'], detail=False, + perms_map = {'post':'qaction_create'}, serializer_class=QActionServiceSerializer) + @transaction.atomic + def service_update(self, request, *args, **kwargs): + """ + 更新提供服务 + """ + user = request.user + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + serializer.save(create_by=user, belong_dept=user.dept) + vdata = serializer.validated_data + cal_count(vdata['qtask'], user.dept) + return Response() + + @action(methods=['post'], detail=False, + perms_map = {'post':'qaction_create'}, serializer_class=QActionQualiCreateSerializer) + @transaction.atomic + def quali_create(self, request, *args, **kwargs): + """ + 新增资质 + """ + user = request.user + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + serializer.save(create_by=user, belong_dept=user.dept) + vdata = serializer.validated_data + cal_count(vdata['qtask'], user.dept) + return Response() + + @action(methods=['post'], detail=False, + perms_map = {'post':'qaction_update'}, serializer_class=QActionQualiUpdateSerializer) + @transaction.atomic + def quali_update(self, request, *args, **kwargs): + """ + 修改资质 + """ + user = request.user + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + serializer.save(create_by=user, belong_dept=user.dept) + vdata = serializer.validated_data + cal_count(vdata['qtask'], user.dept) + return Response() + + @action(methods=['post'], detail=False, + perms_map = {'post':'ability_create'}, serializer_class=QActionQualiCreateSerializer) + @transaction.atomic + def ability_create(self, request, *args, **kwargs): + """ + 新增能力 + """ + user = request.user + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + serializer.save(create_by=user, belong_dept=user.dept) + vdata = serializer.validated_data + cal_count(vdata['qtask'], user.dept) + return Response() + + @action(methods=['put'], detail=True, perms_map = {'put':'qaction_confirm'}, + serializer_class=serializers.Serializer) + @transaction.atomic + def confirm(self, request, *args, **kwargs): + """ + 确认 + """ + obj = self.get_object() + if obj.confirmed: + raise ParseError('该动作已确认') + if obj.action == 'service.update': + org = obj.org + org.service = obj.service + org.save() + elif obj.action == 'quali:create': + serializer = QualiCreateSerializer(data=obj.value2) + serializer.save(org=obj.belong_dept, create_by=obj.create_by) + elif obj.action == 'quali:update': + quali = Quali.objects.get(id=obj.value2.get('id')) + old_data = QualiSerializer(instance=quali).data + obj.value1 = old_data + s = QualiUpdateSerializer(instance=quali, data=obj.value2) + s.save(update_by=obj.create_by) + # 比较差别 + for k, v in obj.value2.items(): + if v != old_data[k]: + QActionItem.objects.create(action='update', field=k, vaule1=old_data[k], value2=v, qaction=obj) + if k == 'citys': + old_citys = set(old_data['citys']) + new_citys = set(v) + removes = old_citys.difference(new_citys) + adds = new_citys.difference(old_citys) + for i in removes: + QAction.objects.create(action='city:remove', field='citys', city=i, qaction=obj) + for i in adds: + QAction.objects.create(action='city:add', field='citys', city=i, qaction=obj) + elif obj.action == 'ability:create': + pass + obj.confirmed = True + obj.save() + return Response(status=status.HTTP_200_OK) + + + + + \ No newline at end of file diff --git a/server/apps/system/migrations/0019_auto_20220513_0905.py b/server/apps/system/migrations/0019_auto_20220513_0905.py new file mode 100644 index 0000000..69d4133 --- /dev/null +++ b/server/apps/system/migrations/0019_auto_20220513_0905.py @@ -0,0 +1,34 @@ +# Generated by Django 3.0.5 on 2022-05-13 01:05 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('system', '0018_auto_20210430_1156'), + ] + + operations = [ + migrations.CreateModel( + name='Province', + fields=[ + ('id', models.PositiveSmallIntegerField(primary_key=True, serialize=False, verbose_name='id')), + ('name', models.CharField(max_length=20)), + ], + ), + migrations.AddField( + model_name='organization', + name='service', + field=models.TextField(blank=True, null=True, verbose_name='提供服务'), + ), + migrations.CreateModel( + name='City', + fields=[ + ('id', models.PositiveSmallIntegerField(primary_key=True, serialize=False, verbose_name='id')), + ('name', models.CharField(max_length=20)), + ('parent', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='system.Province')), + ], + ), + ] diff --git a/server/apps/system/migrations/0020_auto_20220513_0926.py b/server/apps/system/migrations/0020_auto_20220513_0926.py new file mode 100644 index 0000000..82d7e2c --- /dev/null +++ b/server/apps/system/migrations/0020_auto_20220513_0926.py @@ -0,0 +1,23 @@ +# Generated by Django 3.0.5 on 2022-05-13 01:26 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('system', '0019_auto_20220513_0905'), + ] + + operations = [ + migrations.AlterField( + model_name='city', + name='id', + field=models.PositiveIntegerField(primary_key=True, serialize=False, verbose_name='id'), + ), + migrations.AlterField( + model_name='province', + name='id', + field=models.PositiveIntegerField(primary_key=True, serialize=False, verbose_name='id'), + ), + ] diff --git a/server/apps/system/models.py b/server/apps/system/models.py index 5713fe8..42cf25f 100644 --- a/server/apps/system/models.py +++ b/server/apps/system/models.py @@ -6,7 +6,14 @@ from django.db.models.query import QuerySet from utils.model import SoftModel, BaseModel from simple_history.models import HistoricalRecords +class Province(models.Model): + id = models.PositiveIntegerField('id', primary_key=True) + name = models.CharField(max_length=20) +class City(models.Model): + id = models.PositiveIntegerField('id', primary_key=True) + name = models.CharField(max_length=20) + parent = models.ForeignKey(Province, on_delete=models.CASCADE) class Position(BaseModel): """ @@ -61,6 +68,7 @@ class Organization(SoftModel): on_delete=models.SET_NULL, verbose_name='父') sort = models.CharField('排序', null=True, blank=True, max_length=100) can_supervision = models.BooleanField('是否可监督', default=False) + service = models.TextField('提供服务', null=True, blank=True) class Meta: verbose_name = '组织架构' verbose_name_plural = verbose_name diff --git a/server/server/settings_dev.py b/server/server/settings_dev.py index 1aa5ba8..1e913d9 100644 --- a/server/server/settings_dev.py +++ b/server/server/settings_dev.py @@ -1,20 +1,21 @@ from .settings import * DEBUG = True DATABASES = { - # 'default': { - # 'ENGINE': 'django.db.backends.postgresql', - # 'NAME': 'cma', - # 'USER': 'postgres', - # 'PASSWORD': 'zctest1234', - # 'HOST': '47.95.0.242', - # 'PORT': '5432', - # } - 'default': { - 'ENGINE': 'django.db.backends.postgresql', - 'NAME': 'cma', - 'USER': 'cma', - 'PASSWORD': 'cma123', - 'HOST': '172.16.80.102', - 'PORT': '5432', - } + 'default': { + 'ENGINE': 'django.db.backends.postgresql', + 'NAME': 'cma', + 'USER': 'postgres', + 'PASSWORD': 'zctest1234', + 'HOST': '47.95.0.242', + 'PORT': '5432', + } +# 'default': { +# 'ENGINE': 'django.db.backends.postgresql', +# 'NAME': 'cma', +# 'USER': 'cma', +# 'PASSWORD': 'cma123', +# # 'HOST': '172.16.80.102', +# 'HOST': '1.203.161.102', +# 'PORT': '5432', +# } }