From 5ea61453906718cb50767d61d3273d6fa1ddd93b Mon Sep 17 00:00:00 2001 From: TianyangZhang Date: Mon, 3 Nov 2025 09:43:16 +0800 Subject: [PATCH] =?UTF-8?q?add:=20srm=20=E5=88=9B=E5=BB=BA=E6=96=B0?= =?UTF-8?q?=E7=9A=84=E6=A8=A1=E5=9D=97=20srm=20=E7=A7=91=E7=A0=94=E7=AE=A1?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ofm/migrations/0029_auto_20251103_0939.py | 35 +++++ apps/ofm/models.py | 146 ------------------ apps/ofm/serializers.py | 75 +-------- apps/ofm/services.py | 50 ------ apps/ofm/urls.py | 14 +- apps/ofm/views.py | 75 ++++++--- apps/srm/__init__.py | 0 apps/srm/admin.py | 3 + apps/srm/apps.py | 7 + apps/srm/migrations/0001_initial.py | 97 ++++++++++++ apps/srm/migrations/__init__.py | 0 apps/srm/models.py | 112 ++++++++++++++ apps/srm/serializers.py | 94 +++++++++++ apps/srm/services.py | 56 +++++++ apps/srm/tests.py | 3 + apps/srm/urls.py | 16 ++ apps/srm/views.py | 63 ++++++++ server/settings.py | 3 +- server/urls.py | 1 + 19 files changed, 542 insertions(+), 308 deletions(-) create mode 100644 apps/ofm/migrations/0029_auto_20251103_0939.py create mode 100644 apps/srm/__init__.py create mode 100644 apps/srm/admin.py create mode 100644 apps/srm/apps.py create mode 100644 apps/srm/migrations/0001_initial.py create mode 100644 apps/srm/migrations/__init__.py create mode 100644 apps/srm/models.py create mode 100644 apps/srm/serializers.py create mode 100644 apps/srm/services.py create mode 100644 apps/srm/tests.py create mode 100644 apps/srm/urls.py create mode 100644 apps/srm/views.py diff --git a/apps/ofm/migrations/0029_auto_20251103_0939.py b/apps/ofm/migrations/0029_auto_20251103_0939.py new file mode 100644 index 00000000..59a28727 --- /dev/null +++ b/apps/ofm/migrations/0029_auto_20251103_0939.py @@ -0,0 +1,35 @@ +# Generated by Django 3.2.12 on 2025-11-03 01:39 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('ofm', '0028_papersecret_belong_dept'), + ] + + operations = [ + migrations.RemoveField( + model_name='patentinfo', + name='belong_dept', + ), + migrations.RemoveField( + model_name='patentinfo', + name='create_by', + ), + migrations.RemoveField( + model_name='patentinfo', + name='ticket', + ), + migrations.RemoveField( + model_name='patentinfo', + name='update_by', + ), + migrations.DeleteModel( + name='Papersecret', + ), + migrations.DeleteModel( + name='PatentInfo', + ), + ] diff --git a/apps/ofm/models.py b/apps/ofm/models.py index 1d7e89d3..b3f4ef31 100644 --- a/apps/ofm/models.py +++ b/apps/ofm/models.py @@ -158,154 +158,8 @@ class Publicity(CommonBDModel): super().save(*args, **kwargs) -class PatentInfo(CommonBDModel): - """TN: 专利申密审批表单样式""" - PATENT_TYPE_CHOICES = ( - ('invention', '发明专利'), - ('utility', '实用新型专利'), - ('design', '外观设计专利'), - ) - APPLY_AREAS = ( - ('Domestic', '国内申请'), - ('Foreign', '国外申请'), - ('PCT', 'PCT申请'), - ) - - name = models.CharField('拟申请专利名称', max_length=100) - author = models.CharField('发明人(设计人)', max_length=100) - type = models.CharField('专利类型', max_length=50, choices=PATENT_TYPE_CHOICES, default='invention') - is_public = models.BooleanField('是否公开', default=False) - area = models.CharField('拟申请地域', max_length=50, choices=APPLY_AREAS, default='Domestic') - other_area = models.CharField('其它申请地域', max_length=50, blank=True, null=True) - tech_status = models.JSONField('技术状态', default=list, blank=True, help_text='技术状态信息列表,每个条目包含name(名称)、status(状态)、file(文件)字段') - tech_file = models.JSONField('技术文件', default=list, help_text='技术文件信息列表,每个条目包含name(名称)page(页数)字段') - ticket = models.ForeignKey('wf.ticket', verbose_name='关联工单', - on_delete=models.SET_NULL, related_name='patentInfo_ticket', null=True, blank=True, db_constraint=False) - -class Papersecret(CommonBDModel): - """TN: 论文申密审批表单""" - paper_name = models.CharField('拟发表论文名称', max_length=100) - publication_name = models.CharField('拟投期刊名称', max_length=100) - author = models.CharField('作者', max_length=100) - paper_type = models.CharField('拟发表文章类型', max_length=100) - is_chinese_core = models.BooleanField('是否为中文核心', default=False) - is_sci = models.BooleanField('是否被SCI/EI收录', default=False) - tech_status = models.JSONField('技术状态', default=list, blank=True, help_text='技术状态信息列表,每个条目包含name(名称)、status(状态)、file(文件)字段') - tech_file = models.JSONField('技术文件', default=list, help_text='技术文件信息列表,每个条目包含name(名称)page(页数)字段') - ticket = models.ForeignKey('wf.ticket', verbose_name='关联工单', - on_delete=models.SET_NULL, related_name='paperse_ticket', null=True, blank=True, db_constraint=False) -# class PatentRecord(CommonADModel): -# """TN: 专利台账登记""" -# volume_number = models.CharField(max_length=50, null=True, blank=True, verbose_name="卷号") -# application_number = models.CharField(max_length=50, verbose_name="申请号(交局后补登)") -# title = models.CharField(max_length=255, verbose_name="名称") - -# patent_type = models.CharField( -# max_length=20, -# choices=[ -# ("invention", "发明"), -# ("utility_model", "实用新型"), -# ("design", "外观设计") -# ], -# verbose_name="专利类型" -# ) -# organization = models.CharField(max_length=100, verbose_name="单位") -# inventors = models.CharField(max_length=255, verbose_name="发明人") -# agent = models.CharField(max_length=255, null=True, blank=True, verbose_name="代理人") -# affiliated_platforms = models.ManyToManyField('Platform', blank=True, verbose_name="归属平台") -# affiliated_projects = models.ManyToManyField('Project', blank=True, verbose_name="归属项目") -# application_date = models.DateField(null=True, blank=True, verbose_name="申请日") -# authorization_date = models.DateField(null=True, blank=True, verbose_name="授权日") -# validity_years = models.IntegerField(null=True, blank=True, verbose_name="有效年限(年)") -# annuity_paid = models.DecimalField(max_digits=10,decimal_places=2, null=True,blank=True,verbose_name="年费缴纳") - -# status = models.CharField( -# max_length=20, -# choices=[ -# ("not_disclosed", "未公开"), -# ("under_examination", "实审中"), -# ("first_office_action", "一通"), -# ("second_office_action", "二通"), -# ("rejected", "驳回"), -# ("reexamination", "复审"), -# ("authorized", "授权") -# ], -# verbose_name="状态" -# ) -# award_info = models.TextField(null=True, blank=True, verbose_name="报奖情况") -# bonus_amount = models.DecimalField(max_digits=10,decimal_places=2, null=True,blank=True,verbose_name="奖金金额(元)") -# class PaperRecord(models.Model): -# """TN: 论文台账登记""" -# index = models.PositiveIntegerField(verbose_name="序号") -# paper_code = models.CharField(max_length=100, blank=True, null=True, verbose_name="论文编号(投稿后补登)") -# title = models.CharField(max_length=255, verbose_name="名称") -# paper_type = models.CharField(max_length=100, verbose_name="论文类型") -# affiliation = models.CharField(max_length=255, verbose_name="单位") -# authors = models.CharField(max_length=255, verbose_name="作者") -# corresponding_author = models.CharField(max_length=255, blank=True, null=True, verbose_name="通讯作者") -# affiliated_platforms = models.ManyToManyField('Platform', blank=True, verbose_name="归属平台") -# affiliated_projects = models.ManyToManyField('Project', blank=True, verbose_name="归属项目") -# acceptance_date = models.DateField(blank=True, null=True, verbose_name="接受日期") -# publication_date = models.DateField(blank=True, null=True, verbose_name="发表日期") -# page_fee_paid = models.DecimalField( -# max_digits=10, -# decimal_places=2, -# blank=True, -# null=True, -# verbose_name="版面费缴纳" -# ) - -# status = models.CharField( -# max_length=50, -# choices=[ -# ("under_review", "审稿中"), -# ("revise_1", "一修"), -# ("revise_2", "二修"), -# ("accepted", "接收"), -# ("published", "发表") -# ], -# default="under_review", verbose_name="状态" -# ) -# award_status = models.CharField(max_length=255, blank=True, null=True, verbose_name="报奖情况") -# bonus_amount = models.DecimalField(max_digits=10,decimal_places=2,blank=True,null=True,verbose_name="奖金发放") - - -# class ProjectApproval(CommonBDModel): -# """TN: 立项审批表""" -# project_start_date = models.DateField("立项日期", null=True, blank=True) -# is_self_initiated = models.BooleanField("自立项目", default=False) -# is_city_level = models.BooleanField("市级项目", default=False) -# is_province_level = models.BooleanField("省级项目", default=False) -# construction_period = models.CharField("建设期", max_length=100, null=True, blank=True) -# project_members = models.TextField("项目组员", null=True, blank=True) -# project_budget = models.DecimalField("项目预算(万元)", max_digits=12, decimal_places=2, null=True, blank=True) -# project_description = models.TextField("项目基本情况", null=True, blank=True) -# project_performance = models.TextField("目标绩效", null=True, blank=True) - - -# class ProjectInfo(CommonBDModel): -# """TN: 项目信息表 - -# """ -# serial_number = models.CharField("序号", max_length=50, null=True, blank=True) -# red_head_doc_no = models.CharField("红头发文号/公示页", max_length=100, null=True, blank=True) -# name = models.CharField("名称", max_length=200, null=True, blank=True) -# project_type = models.CharField("项目类型", max_length=100, null=True, blank=True) -# platform = models.CharField("所属平台", max_length=100, null=True, blank=True) -# project_source = models.CharField("项目来源", max_length=100, null=True, blank=True) -# construction_period = models.CharField("建设期", max_length=100, null=True, blank=True) -# project_funding = models.DecimalField("项目资金(财政与自筹)", max_digits=15, decimal_places=2, null=True, blank=True) -# support_period = models.CharField("项目支持期", max_length=100, null=True, blank=True) -# undertaking_unit = models.CharField("承担单位", max_length=200, null=True, blank=True) -# responsible_person = models.CharField("负责人", max_length=50, null=True, blank=True) - -# project_members = models.TextField("项目人员", null=True, blank=True) -# milestone = models.TextField("里程碑节点", null=True, blank=True) -# mid_term_status = models.TextField("项目中期情况", null=True, blank=True) -# acceptance_status = models.TextField("项目验收情况", null=True, blank=True) -# sci_tech_achievements = models.TextField("科技成果", null=True, blank=True) diff --git a/apps/ofm/serializers.py b/apps/ofm/serializers.py index 791045a6..1e8bd1d7 100644 --- a/apps/ofm/serializers.py +++ b/apps/ofm/serializers.py @@ -1,5 +1,4 @@ -from .models import (Mroom, MroomBooking, MroomSlot, LendingSeal, Vehicle, FileRecord, BorrowRecord, Publicity, PatentInfo, Papersecret) -# Publicity, PatetInfo, PaperOfm, Platform, Project, PatentRecord, PaperRecord, ProjectApproval, ProjectInfo) +from .models import (Mroom, MroomBooking, MroomSlot, LendingSeal, Vehicle, FileRecord, BorrowRecord, Publicity) from apps.utils.serializers import CustomModelSerializer from rest_framework import serializers from django.db import transaction @@ -122,78 +121,6 @@ class PublicitySerializer(CustomModelSerializer): read_only_fields = EXCLUDE_FIELDS -class PatentInfoSerializer(CustomModelSerializer): - create_by_name = serializers.CharField(source='create_by.name', read_only=True) - belong_dept_name = serializers.CharField(source='belong_dept.name', read_only=True) - ticket_ = TicketSimpleSerializer(source='ticket', read_only=True) - class Meta: - model = PatentInfo - fields = '__all__' - read_only_fields = EXCLUDE_FIELDS -class PaperSeSerializer(CustomModelSerializer): - create_by_name = serializers.CharField(source='create_by.name', read_only=True) - belong_dept_name = serializers.CharField(source='belong_dept.name', read_only=True) - ticket_ = TicketSimpleSerializer(source='ticket', read_only=True) - class Meta: - model = Papersecret - fields = '__all__' - read_only_fields = EXCLUDE_FIELDS - - -# class PlatformSerializer(serializers.ModelSerializer): -# class Meta: -# model = Platform -# fields = ['id', 'name'] - - -# class ProjectSerializer(serializers.ModelSerializer): -# class Meta: -# model = Project -# fields = ['id', 'name'] - - -# class ProjectMemberSerializer(CustomModelSerializer): -# affiliated_platforms = serializers.PrimaryKeyRelatedField( -# many=True, -# queryset=Platform.objects.all(), -# write_only=True -# ) -# affiliated_platforms_detail = PlatformSerializer( -# source='affiliated_platforms', many=True, read_only=True -# ) - -# affiliated_projects = serializers.PrimaryKeyRelatedField( -# many=True, -# queryset=Project.objects.all(), -# write_only=True -# ) -# affiliated_projects_detail = ProjectSerializer( -# source='affiliated_projects', many=True, read_only=True -# ) -# class Meta: -# model = PatentRecord -# fields = '__all__' - - -# class PaperRecordSerializer(CustomModelSerializer): -# class Meta: -# model = PaperRecord -# fields = '__all__' -# read_only_fields = EXCLUDE_FIELDS - - -# class ProjectApprovalSerializer(CustomModelSerializer): -# class Meta: -# model = ProjectApproval -# fields = '__all__' -# read_only_fields = EXCLUDE_FIELDS - - -# class ProjectInfoSerializer(CustomModelSerializer): -# class Meta: -# model = ProjectInfo -# fields = '__all__' -# read_only_fields = EXCLUDE_FIELDS \ No newline at end of file diff --git a/apps/ofm/services.py b/apps/ofm/services.py index 09d3f613..3ed56207 100644 --- a/apps/ofm/services.py +++ b/apps/ofm/services.py @@ -140,53 +140,3 @@ def save_ticket_data(ticket: Ticket, new_ticket_data: dict, **kwargs): obj.save() -def bind_patent(ticket: Ticket, transition, new_ticket_data: dict): - ins = PatentInfo.objects.get(id=new_ticket_data['t_id']) - ticket_data = ticket.ticket_data - ticket_data.update({ - 't_model': 'patent', - 't_id': ins.id, - }) - ticket.ticket_data = ticket_data - ticket.create_by = ins.create_by - ticket.save() - if ins.ticket is None: - ins.ticket = ticket - ins.save() - -def patent_save_ticket_data(ticket: Ticket, new_ticket_data: dict, **kwargs): - try: - obj = PatentInfo.objects.get(id=new_ticket_data['t_id']) - except PatentInfo.DoesNotExist: - raise ParseError("Publicity t_id 不存在") - data_save = {k: v for k, v in new_ticket_data.items() if k not in ['t_model', 't_id']} - - for k, v in data_save.items(): - setattr(obj, k, v) - obj.save() - - -def paperse_patent(ticket: Ticket, transition, new_ticket_data: dict): - ins = Papersecret.objects.get(id=new_ticket_data['t_id']) - ticket_data = ticket.ticket_data - ticket_data.update({ - 't_model': 'paperse', - 't_id': ins.id, - }) - ticket.ticket_data = ticket_data - ticket.create_by = ins.create_by - ticket.save() - if ins.ticket is None: - ins.ticket = ticket - ins.save() - -def paperse_save_ticket_data(ticket: Ticket, new_ticket_data: dict, **kwargs): - try: - obj = Papersecret.objects.get(id=new_ticket_data['t_id']) - except Papersecret.DoesNotExist: - raise ParseError("Publicity t_id 不存在") - data_save = {k: v for k, v in new_ticket_data.items() if k not in ['t_model', 't_id']} - - for k, v in data_save.items(): - setattr(obj, k, v) - obj.save() \ No newline at end of file diff --git a/apps/ofm/urls.py b/apps/ofm/urls.py index 84ebb77b..ea494a51 100644 --- a/apps/ofm/urls.py +++ b/apps/ofm/urls.py @@ -1,10 +1,6 @@ from django.urls import path, include from rest_framework.routers import DefaultRouter -from apps.ofm.views import (MroomViewSet, MroomBookingViewSet, MroomSlotViewSet,LendingSealViewSet, VehicleViewSet, FilerecordViewSet, - FileborrowViewSet, PublicityViewSet, PatentInfoViewSet, PapersecretViewSet) - # SealModelViewSet, - # , PublicityViewSet, , PaperViewSet, PlatformViewSet, - # ProjectViewSet, PatentRecordViewSet, PaperRecordViewSet, ProjectApprovalViewSet, ProjectInfoViewSet) +from apps.ofm.views import (MroomViewSet, MroomBookingViewSet, MroomSlotViewSet,LendingSealViewSet, VehicleViewSet, FilerecordViewSet, FileborrowViewSet, PublicityViewSet) API_BASE_URL = 'api/ofm/' HTML_BASE_URL = 'dhtml/ofm/' @@ -19,14 +15,6 @@ router.register('vehicle', VehicleViewSet, basename='vehicle') router.register('filerecord', FilerecordViewSet, basename='filerecord') router.register('fileborrow', FileborrowViewSet, basename='fileborrow') router.register('publicity', PublicityViewSet, basename='publicity') -router.register('patentinfo', PatentInfoViewSet, basename='patentinfo') -router.register('paperse', PapersecretViewSet, basename='PaperSe') -# router.register('platform', PlatformViewSet, basename='platform') -# router.register('project', ProjectViewSet, basename='project') -# router.register('patentrecord', PatentRecordViewSet, basename='patentrecord') -# router.register('paperrecord', PaperRecordViewSet, basename='paperrecord') -# router.register('projectapproval', ProjectApprovalViewSet, basename='projectapproval') -# router.register('projectinfo', ProjectInfoViewSet, basename='projectinfo') urlpatterns = [ path(API_BASE_URL, include(router.urls)), ] diff --git a/apps/ofm/views.py b/apps/ofm/views.py index 354e4a11..5b3639e4 100644 --- a/apps/ofm/views.py +++ b/apps/ofm/views.py @@ -1,17 +1,13 @@ from django.shortcuts import render from apps.utils.viewsets import CustomModelViewSet, CustomGenericViewSet -from .models import Mroom, MroomBooking, MroomSlot, LendingSeal, Vehicle, FileRecord, BorrowRecord, Publicity, PatentInfo, Papersecret - # Publicity, , PaperOfm, Platform, Project, PatentRecord, PaperRecord, ProjectApproval, ProjectInfo) +from .models import Mroom, MroomBooking, MroomSlot, LendingSeal, Vehicle, FileRecord, BorrowRecord, Publicity + from .serializers import (MroomSerializer, MroomBookingSerializer, MroomSlotSerializer, LendingSealSerializer, - VehicleSerializer, FileRecordSerializer, BorrowRecordSerializer, PublicitySerializer, PatentInfoSerializer, PaperSeSerializer) - # ,SealSerializer, - # LendingSealSerializer, FileRecordSerializer, BorrowRecordSerializer, PublicitySerializer, - # PatentInfoSerializer, PaperSerializer, PlatformSerializer, ProjectSerializer, ProjectMemberSerializer, PaperRecordSerializer, ProjectApprovalSerializer, ProjectInfoSerializer) -from rest_framework.decorators import action + VehicleSerializer, FileRecordSerializer, BorrowRecordSerializer, PublicitySerializer) from apps.utils.mixins import CustomListModelMixin from rest_framework.exceptions import ParseError from apps.ofm.filters import MroomBookingFilterset, SealFilter, BorrowRecordFilter - +from rest_framework.response import Response class MroomViewSet(CustomModelViewSet): """list: 会议室 @@ -171,26 +167,57 @@ class PublicityViewSet(CustomModelViewSet): ordering = ["-create_time", "number"] -class PatentInfoViewSet(CustomModelViewSet): - """list: 专利 +# class PatentInfoViewSet(CustomModelViewSet): +# """list: 专利 - 专利 - """ - queryset = PatentInfo.objects.all() - serializer_class = PatentInfoSerializer - filterset_fields = ["name", "author", "type"] - ordering = ["-create_time", "name", "author", "type"] +# 专利 +# """ +# queryset = PatentInfo.objects.all() +# serializer_class = PatentInfoSerializer +# filterset_fields = ["name", "author", "type"] +# ordering = ["-create_time", "name", "author", "type"] -class PapersecretViewSet(CustomModelViewSet): - """list: 论文申密审批 +# class PapersecretViewSet(CustomModelViewSet): +# """list: 论文申密审批 - 论文申密审批 - """ - queryset = Papersecret.objects.all() - serializer_class = PaperSeSerializer - filterset_fields = ["paper_name", "author"] - ordering = ["create_time", "paper_name"] +# 论文申密审批 +# """ +# queryset = Papersecret.objects.all() +# serializer_class = PaperSeSerializer +# filterset_fields = ["paper_name", "author"] +# ordering = ["-create_time", "paper_name"] + + +# class PatentRecordViewSet(CustomModelViewSet): +# """list: 专利台账登记 + +# 专利台账登记 +# """ +# queryset = PatentRecord.objects.all() +# serializer_class = PatentRecordSerializer +# select_related_fields = ["patent"] +# filterset_fields = ["title", "volume_number","inventors"] +# ordering = ["-create_time", "title", "type"] +# search_fields = ["title", "volume_number", "inventors"] + +# def get_queryset(self): +# qs = super().get_queryset() +# patent_type = self.request.query_params.get('patent_type', None) +# if patent_type: +# qs = qs.filter(patent__type=patent_type) +# return qs + + +# @action(detail=False, methods=['get']) +# def patent_name(self, request): +# """获取专利列表""" +# search = request.query_params.get('search', '') +# queryset = PatentInfo.objects.all() +# if search: +# queryset = queryset.filter(name__icontains=search) +# patents = [{'id': patent.id, 'name': patent.name} for patent in queryset] +# return Response(patents) # class PlatformViewSet(CustomModelViewSet): diff --git a/apps/srm/__init__.py b/apps/srm/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/srm/admin.py b/apps/srm/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/apps/srm/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/apps/srm/apps.py b/apps/srm/apps.py new file mode 100644 index 00000000..f2787d3d --- /dev/null +++ b/apps/srm/apps.py @@ -0,0 +1,7 @@ +from django.apps import AppConfig + + +class SrmConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'apps.srm' + verbose_name = '科研管理' diff --git a/apps/srm/migrations/0001_initial.py b/apps/srm/migrations/0001_initial.py new file mode 100644 index 00000000..1b07f7f9 --- /dev/null +++ b/apps/srm/migrations/0001_initial.py @@ -0,0 +1,97 @@ +# Generated by Django 3.2.12 on 2025-11-03 01:39 + +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', '0006_auto_20241213_1249'), + ('wf', '0004_workflow_view_path2'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='PatentInfo', + 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=100, verbose_name='拟申请专利名称')), + ('author', models.CharField(max_length=100, verbose_name='发明人(设计人)')), + ('type', models.CharField(choices=[('invention', '发明专利'), ('utility', '实用新型专利'), ('design', '外观设计专利')], default='invention', max_length=50, verbose_name='专利类型')), + ('is_public', models.BooleanField(default=False, verbose_name='是否公开')), + ('area', models.CharField(choices=[('Domestic', '国内申请'), ('Foreign', '国外申请'), ('PCT', 'PCT申请')], default='Domestic', max_length=50, verbose_name='拟申请地域')), + ('other_area', models.CharField(blank=True, max_length=50, null=True, verbose_name='其它申请地域')), + ('tech_status', models.JSONField(blank=True, default=list, help_text='技术状态信息列表,每个条目包含name(名称)、status(状态)、file(文件)字段', verbose_name='技术状态')), + ('tech_file', models.JSONField(default=list, help_text='技术文件信息列表,每个条目包含name(名称)page(页数)字段', verbose_name='技术文件')), + ('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='patentinfo_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='patentinfo_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('ticket', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='patentInfo_ticket', to='wf.ticket', verbose_name='关联工单')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='patentinfo_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='PatentRecord', + 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='删除标记')), + ('volume_number', models.CharField(blank=True, max_length=50, null=True, verbose_name='卷号')), + ('application_number', models.CharField(max_length=50, verbose_name='申请号(交局后补登)')), + ('organization', models.CharField(max_length=100, verbose_name='单位')), + ('inventors', models.CharField(max_length=255, verbose_name='发明人')), + ('agent', models.CharField(blank=True, max_length=255, null=True, verbose_name='代理人')), + ('affiliated_platforms', models.CharField(blank=True, max_length=255, verbose_name='归属平台')), + ('affiliated_projects', models.CharField(blank=True, max_length=255, verbose_name='归属项目')), + ('application_date', models.DateField(blank=True, null=True, verbose_name='申请日')), + ('authorization_date', models.DateField(blank=True, null=True, verbose_name='授权日')), + ('validity_years', models.IntegerField(blank=True, null=True, verbose_name='有效年限(年)')), + ('annuity_paid', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True, verbose_name='年费缴纳')), + ('status', models.CharField(choices=[('not_disclosed', '未公开'), ('under_examination', '实审中'), ('first_office_action', '一通'), ('second_office_action', '二通'), ('rejected', '驳回'), ('reexamination', '复审'), ('authorized', '授权')], max_length=20, verbose_name='状态')), + ('award_info', models.TextField(blank=True, null=True, verbose_name='报奖情况')), + ('bonus_amount', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True, verbose_name='奖金金额(元)')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='patentrecord_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('patent', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='patent_record', to='srm.patentinfo', verbose_name='专利名称')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='patentrecord_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='Papersecret', + 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='删除标记')), + ('paper_name', models.CharField(max_length=100, verbose_name='拟发表论文名称')), + ('publication_name', models.CharField(max_length=100, verbose_name='拟投期刊名称')), + ('author', models.CharField(max_length=100, verbose_name='作者')), + ('paper_type', models.CharField(max_length=100, verbose_name='拟发表文章类型')), + ('is_chinese_core', models.BooleanField(default=False, verbose_name='是否为中文核心')), + ('is_sci', models.BooleanField(default=False, verbose_name='是否被SCI/EI收录')), + ('tech_status', models.JSONField(blank=True, default=list, help_text='技术状态信息列表,每个条目包含name(名称)、status(状态)、file(文件)字段', verbose_name='技术状态')), + ('tech_file', models.JSONField(default=list, help_text='技术文件信息列表,每个条目包含name(名称)page(页数)字段', verbose_name='技术文件')), + ('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='papersecret_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='papersecret_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('ticket', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='paperse_ticket', to='wf.ticket', verbose_name='关联工单')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='papersecret_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/apps/srm/migrations/__init__.py b/apps/srm/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/srm/models.py b/apps/srm/models.py new file mode 100644 index 00000000..7ab14e00 --- /dev/null +++ b/apps/srm/models.py @@ -0,0 +1,112 @@ +from django.db import models +from django.db import models, transaction +from apps.utils.models import CommonADModel, BaseModel, CommonBDModel +from apps.system.models import User +from django.core.validators import RegexValidator +from datetime import datetime +from rest_framework.exceptions import ParseError + +# Create your models here. +class PatentInfo(CommonBDModel): + """TN: 专利申密审批表单样式""" + PATENT_TYPE_CHOICES = ( + ('invention', '发明专利'), + ('utility', '实用新型专利'), + ('design', '外观设计专利'), + ) + APPLY_AREAS = ( + ('Domestic', '国内申请'), + ('Foreign', '国外申请'), + ('PCT', 'PCT申请'), + ) + + name = models.CharField('拟申请专利名称', max_length=100) + author = models.CharField('发明人(设计人)', max_length=100) + type = models.CharField('专利类型', max_length=50, choices=PATENT_TYPE_CHOICES, default='invention') + is_public = models.BooleanField('是否公开', default=False) + area = models.CharField('拟申请地域', max_length=50, choices=APPLY_AREAS, default='Domestic') + other_area = models.CharField('其它申请地域', max_length=50, blank=True, null=True) + tech_status = models.JSONField('技术状态', default=list, blank=True, help_text='技术状态信息列表,每个条目包含name(名称)、status(状态)、file(文件)字段') + tech_file = models.JSONField('技术文件', default=list, help_text='技术文件信息列表,每个条目包含name(名称)page(页数)字段') + ticket = models.ForeignKey('wf.ticket', verbose_name='关联工单', + on_delete=models.SET_NULL, related_name='patentInfo_ticket', null=True, blank=True, db_constraint=False) + +class Papersecret(CommonBDModel): + """TN: 论文申密审批表单""" + paper_name = models.CharField('拟发表论文名称', max_length=100) + publication_name = models.CharField('拟投期刊名称', max_length=100) + author = models.CharField('作者', max_length=100) + paper_type = models.CharField('拟发表文章类型', max_length=100) + is_chinese_core = models.BooleanField('是否为中文核心', default=False) + is_sci = models.BooleanField('是否被SCI/EI收录', default=False) + tech_status = models.JSONField('技术状态', default=list, blank=True, help_text='技术状态信息列表,每个条目包含name(名称)、status(状态)、file(文件)字段') + tech_file = models.JSONField('技术文件', default=list, help_text='技术文件信息列表,每个条目包含name(名称)page(页数)字段') + ticket = models.ForeignKey('wf.ticket', verbose_name='关联工单', + on_delete=models.SET_NULL, related_name='paperse_ticket', null=True, blank=True, db_constraint=False) + +class PatentRecord(CommonADModel): + """TN: 专利台账登记""" + volume_number = models.CharField(max_length=50, null=True, blank=True, verbose_name="卷号") + application_number = models.CharField(max_length=50, verbose_name="申请号(交局后补登)") + patent = models.ForeignKey('PatentInfo', verbose_name="专利名称", on_delete=models.CASCADE, related_name='patent_record') + organization = models.CharField(max_length=100, verbose_name="单位") + inventors = models.CharField(max_length=255, verbose_name="发明人") + agent = models.CharField(max_length=255, null=True, blank=True, verbose_name="代理人") + affiliated_platforms = models.CharField(max_length=255, blank=True, verbose_name="归属平台") + affiliated_projects = models.CharField(max_length=255, blank=True, verbose_name="归属项目") + application_date = models.DateField(null=True, blank=True, verbose_name="申请日") + authorization_date = models.DateField(null=True, blank=True, verbose_name="授权日") + validity_years = models.IntegerField(null=True, blank=True, verbose_name="有效年限(年)") + annuity_paid = models.DecimalField(max_digits=10,decimal_places=2, null=True,blank=True,verbose_name="年费缴纳") + + status = models.CharField( + max_length=20, + choices=[ + ("not_disclosed", "未公开"), + ("under_examination", "实审中"), + ("first_office_action", "一通"), + ("second_office_action", "二通"), + ("rejected", "驳回"), + ("reexamination", "复审"), + ("authorized", "授权") + ], + verbose_name="状态" + ) + award_info = models.TextField(null=True, blank=True, verbose_name="报奖情况") + bonus_amount = models.DecimalField(max_digits=10,decimal_places=2, null=True,blank=True,verbose_name="奖金金额(元)") + + +# class ProjectApproval(CommonBDModel): +# """TN: 立项审批表""" +# project_start_date = models.DateField("立项日期", null=True, blank=True) +# is_self_initiated = models.BooleanField("自立项目", default=False) +# is_city_level = models.BooleanField("市级项目", default=False) +# is_province_level = models.BooleanField("省级项目", default=False) +# construction_period = models.CharField("建设期", max_length=100, null=True, blank=True) +# project_members = models.TextField("项目组员", null=True, blank=True) +# project_budget = models.DecimalField("项目预算(万元)", max_digits=12, decimal_places=2, null=True, blank=True) +# project_description = models.TextField("项目基本情况", null=True, blank=True) +# project_performance = models.TextField("目标绩效", null=True, blank=True) + + +# class ProjectInfo(CommonBDModel): +# """TN: 项目信息表 + +# """ +# serial_number = models.CharField("序号", max_length=50, null=True, blank=True) +# red_head_doc_no = models.CharField("红头发文号/公示页", max_length=100, null=True, blank=True) +# name = models.CharField("名称", max_length=200, null=True, blank=True) +# project_type = models.CharField("项目类型", max_length=100, null=True, blank=True) +# platform = models.CharField("所属平台", max_length=100, null=True, blank=True) +# project_source = models.CharField("项目来源", max_length=100, null=True, blank=True) +# construction_period = models.CharField("建设期", max_length=100, null=True, blank=True) +# project_funding = models.DecimalField("项目资金(财政与自筹)", max_digits=15, decimal_places=2, null=True, blank=True) +# support_period = models.CharField("项目支持期", max_length=100, null=True, blank=True) +# undertaking_unit = models.CharField("承担单位", max_length=200, null=True, blank=True) +# responsible_person = models.CharField("负责人", max_length=50, null=True, blank=True) + +# project_members = models.TextField("项目人员", null=True, blank=True) +# milestone = models.TextField("里程碑节点", null=True, blank=True) +# mid_term_status = models.TextField("项目中期情况", null=True, blank=True) +# acceptance_status = models.TextField("项目验收情况", null=True, blank=True) +# sci_tech_achievements = models.TextField("科技成果", null=True, blank=True) \ No newline at end of file diff --git a/apps/srm/serializers.py b/apps/srm/serializers.py new file mode 100644 index 00000000..12c4a003 --- /dev/null +++ b/apps/srm/serializers.py @@ -0,0 +1,94 @@ +from .models import (PatentInfo, Papersecret, PatentRecord) +from apps.utils.serializers import CustomModelSerializer +from rest_framework import serializers +from django.db import transaction +from rest_framework.exceptions import ParseError +from apps.utils.constants import EXCLUDE_FIELDS +from apps.wf.serializers import TicketSimpleSerializer + +class PatentInfoSerializer(CustomModelSerializer): + create_by_name = serializers.CharField(source='create_by.name', read_only=True) + belong_dept_name = serializers.CharField(source='belong_dept.name', read_only=True) + ticket_ = TicketSimpleSerializer(source='ticket', read_only=True) + class Meta: + model = PatentInfo + fields = '__all__' + read_only_fields = EXCLUDE_FIELDS + + +class PaperSeSerializer(CustomModelSerializer): + create_by_name = serializers.CharField(source='create_by.name', read_only=True) + belong_dept_name = serializers.CharField(source='belong_dept.name', read_only=True) + ticket_ = TicketSimpleSerializer(source='ticket', read_only=True) + class Meta: + model = Papersecret + fields = '__all__' + read_only_fields = EXCLUDE_FIELDS + + +class PatentRecordSerializer(CustomModelSerializer): + create_by_name = serializers.CharField(source='create_by.name', read_only=True) + belong_dept_name = serializers.CharField(source='belong_dept.name', read_only=True) + patent_info = serializers.PrimaryKeyRelatedField(queryset=PatentInfo.objects.all(), many=True, write_only=True, label="专利信息") + patent_name = serializers.CharField(source='patent.name', read_only=True, label="专利名称") + patent_type = serializers.CharField(source='patent.type', read_only=True, label="专利类型") + class Meta: + model = PatentRecord + fields = '__all__' + read_only_fields = EXCLUDE_FIELDS + + +# class PlatformSerializer(serializers.ModelSerializer): +# class Meta: +# model = Platform +# fields = ['id', 'name'] + + +# class ProjectSerializer(serializers.ModelSerializer): +# class Meta: +# model = Project +# fields = ['id', 'name'] + + +# class ProjectMemberSerializer(CustomModelSerializer): +# affiliated_platforms = serializers.PrimaryKeyRelatedField( +# many=True, +# queryset=Platform.objects.all(), +# write_only=True +# ) +# affiliated_platforms_detail = PlatformSerializer( +# source='affiliated_platforms', many=True, read_only=True +# ) + +# affiliated_projects = serializers.PrimaryKeyRelatedField( +# many=True, +# queryset=Project.objects.all(), +# write_only=True +# ) +# affiliated_projects_detail = ProjectSerializer( +# source='affiliated_projects', many=True, read_only=True +# ) +# class Meta: +# model = PatentRecord +# fields = '__all__' + + +# class PaperRecordSerializer(CustomModelSerializer): +# class Meta: +# model = PaperRecord +# fields = '__all__' +# read_only_fields = EXCLUDE_FIELDS + + +# class ProjectApprovalSerializer(CustomModelSerializer): +# class Meta: +# model = ProjectApproval +# fields = '__all__' +# read_only_fields = EXCLUDE_FIELDS + + +# class ProjectInfoSerializer(CustomModelSerializer): +# class Meta: +# model = ProjectInfo +# fields = '__all__' +# read_only_fields = EXCLUDE_FIELDS \ No newline at end of file diff --git a/apps/srm/services.py b/apps/srm/services.py new file mode 100644 index 00000000..0a157be5 --- /dev/null +++ b/apps/srm/services.py @@ -0,0 +1,56 @@ +from apps.wf.models import Ticket +# TicketFlow, Transition, Workflow, CustomField, State, +from apps.srm.models import PatentInfo, Papersecret +from rest_framework.exceptions import ParseError + + +def bind_patent(ticket: Ticket, transition, new_ticket_data: dict): + ins = PatentInfo.objects.get(id=new_ticket_data['t_id']) + ticket_data = ticket.ticket_data + ticket_data.update({ + 't_model': 'patent', + 't_id': ins.id, + }) + ticket.ticket_data = ticket_data + ticket.create_by = ins.create_by + ticket.save() + if ins.ticket is None: + ins.ticket = ticket + ins.save() + +def patent_save_ticket_data(ticket: Ticket, new_ticket_data: dict, **kwargs): + try: + obj = PatentInfo.objects.get(id=new_ticket_data['t_id']) + except PatentInfo.DoesNotExist: + raise ParseError("Publicity t_id 不存在") + data_save = {k: v for k, v in new_ticket_data.items() if k not in ['t_model', 't_id']} + + for k, v in data_save.items(): + setattr(obj, k, v) + obj.save() + + +def paperse_patent(ticket: Ticket, transition, new_ticket_data: dict): + ins = Papersecret.objects.get(id=new_ticket_data['t_id']) + ticket_data = ticket.ticket_data + ticket_data.update({ + 't_model': 'paperse', + 't_id': ins.id, + }) + ticket.ticket_data = ticket_data + ticket.create_by = ins.create_by + ticket.save() + if ins.ticket is None: + ins.ticket = ticket + ins.save() + +def paperse_save_ticket_data(ticket: Ticket, new_ticket_data: dict, **kwargs): + try: + obj = Papersecret.objects.get(id=new_ticket_data['t_id']) + except Papersecret.DoesNotExist: + raise ParseError("Publicity t_id 不存在") + data_save = {k: v for k, v in new_ticket_data.items() if k not in ['t_model', 't_id']} + + for k, v in data_save.items(): + setattr(obj, k, v) + obj.save() \ No newline at end of file diff --git a/apps/srm/tests.py b/apps/srm/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/apps/srm/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/apps/srm/urls.py b/apps/srm/urls.py new file mode 100644 index 00000000..72f33124 --- /dev/null +++ b/apps/srm/urls.py @@ -0,0 +1,16 @@ +from django.urls import path, include +from rest_framework.routers import DefaultRouter +from apps.srm.views import PatentInfoViewSet, PapersecretViewSet, PatentRecordViewSet + + +API_BASE_URL = 'api/srm/' +HTML_BASE_URL = 'dhtml/srm/' + +router = DefaultRouter() +router.register('patentinfo', PatentInfoViewSet, basename='patentinfo') +router.register('paperse', PapersecretViewSet, basename='PaperSe') +router.register('patentrecord', PatentRecordViewSet, basename='patentrecord') + +urlpatterns = [ + path(API_BASE_URL, include(router.urls)), +] diff --git a/apps/srm/views.py b/apps/srm/views.py new file mode 100644 index 00000000..d2a73343 --- /dev/null +++ b/apps/srm/views.py @@ -0,0 +1,63 @@ +from django.shortcuts import render + +# Create your views here. +from django.shortcuts import render +from apps.utils.viewsets import CustomModelViewSet, CustomGenericViewSet +from .models import PatentInfo, Papersecret, PatentRecord +from .serializers import PatentInfoSerializer, PaperSeSerializer, PatentRecordSerializer + +from rest_framework.exceptions import ParseError +from rest_framework.response import Response +from rest_framework.decorators import action + +class PatentInfoViewSet(CustomModelViewSet): + """list: 专利 + + 专利 + """ + queryset = PatentInfo.objects.all() + serializer_class = PatentInfoSerializer + filterset_fields = ["name", "author", "type"] + ordering = ["-create_time", "name", "author", "type"] + + +class PapersecretViewSet(CustomModelViewSet): + """list: 论文申密审批 + + 论文申密审批 + """ + queryset = Papersecret.objects.all() + serializer_class = PaperSeSerializer + filterset_fields = ["paper_name", "author"] + ordering = ["-create_time", "paper_name"] + + +class PatentRecordViewSet(CustomModelViewSet): + """list: 专利台账登记 + + 专利台账登记 + """ + queryset = PatentRecord.objects.all() + serializer_class = PatentRecordSerializer + select_related_fields = ["patent"] + filterset_fields = ["title", "volume_number","inventors"] + ordering = ["-create_time", "title", "type"] + search_fields = ["title", "volume_number", "inventors"] + + def get_queryset(self): + qs = super().get_queryset() + patent_type = self.request.query_params.get('patent_type', None) + if patent_type: + qs = qs.filter(patent__type=patent_type) + return qs + + + @action(detail=False, methods=['get']) + def patent_name(self, request): + """获取专利列表""" + search = request.query_params.get('search', '') + queryset = PatentInfo.objects.all() + if search: + queryset = queryset.filter(name__icontains=search) + patents = [{'id': patent.id, 'name': patent.name} for patent in queryset] + return Response(patents) \ No newline at end of file diff --git a/server/settings.py b/server/settings.py index ec75b8d0..09477a4e 100755 --- a/server/settings.py +++ b/server/settings.py @@ -85,7 +85,8 @@ INSTALLED_APPS = [ 'apps.cm', 'apps.cms', 'apps.wpmw', - 'apps.ofm' + 'apps.ofm', + 'apps.srm', ] MIDDLEWARE = [ diff --git a/server/urls.py b/server/urls.py index 211b2007..bfde6f72 100755 --- a/server/urls.py +++ b/server/urls.py @@ -76,6 +76,7 @@ urlpatterns = [ path('', include('apps.cms.urls')), path('', include('apps.wpmw.urls')), path('', include('apps.ofm.urls')), + path('', include('apps.srm.urls')), # 前端页面入口 path('', TemplateView.as_view(template_name="index.html")),