add: srm 创建新的模块 srm 科研管理

This commit is contained in:
TianyangZhang 2025-11-03 09:43:16 +08:00
parent 80ead2f426
commit 5ea6145390
19 changed files with 542 additions and 308 deletions

View File

@ -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',
),
]

View File

@ -158,154 +158,8 @@ class Publicity(CommonBDModel):
super().save(*args, **kwargs) 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)

View File

@ -1,5 +1,4 @@
from .models import (Mroom, MroomBooking, MroomSlot, LendingSeal, Vehicle, FileRecord, BorrowRecord, Publicity, PatentInfo, Papersecret) from .models import (Mroom, MroomBooking, MroomSlot, LendingSeal, Vehicle, FileRecord, BorrowRecord, Publicity)
# Publicity, PatetInfo, PaperOfm, Platform, Project, PatentRecord, PaperRecord, ProjectApproval, ProjectInfo)
from apps.utils.serializers import CustomModelSerializer from apps.utils.serializers import CustomModelSerializer
from rest_framework import serializers from rest_framework import serializers
from django.db import transaction from django.db import transaction
@ -122,78 +121,6 @@ class PublicitySerializer(CustomModelSerializer):
read_only_fields = EXCLUDE_FIELDS 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

View File

@ -140,53 +140,3 @@ def save_ticket_data(ticket: Ticket, new_ticket_data: dict, **kwargs):
obj.save() 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()

View File

@ -1,10 +1,6 @@
from django.urls import path, include from django.urls import path, include
from rest_framework.routers import DefaultRouter from rest_framework.routers import DefaultRouter
from apps.ofm.views import (MroomViewSet, MroomBookingViewSet, MroomSlotViewSet,LendingSealViewSet, VehicleViewSet, FilerecordViewSet, from apps.ofm.views import (MroomViewSet, MroomBookingViewSet, MroomSlotViewSet,LendingSealViewSet, VehicleViewSet, FilerecordViewSet, FileborrowViewSet, PublicityViewSet)
FileborrowViewSet, PublicityViewSet, PatentInfoViewSet, PapersecretViewSet)
# SealModelViewSet,
# , PublicityViewSet, , PaperViewSet, PlatformViewSet,
# ProjectViewSet, PatentRecordViewSet, PaperRecordViewSet, ProjectApprovalViewSet, ProjectInfoViewSet)
API_BASE_URL = 'api/ofm/' API_BASE_URL = 'api/ofm/'
HTML_BASE_URL = 'dhtml/ofm/' HTML_BASE_URL = 'dhtml/ofm/'
@ -19,14 +15,6 @@ router.register('vehicle', VehicleViewSet, basename='vehicle')
router.register('filerecord', FilerecordViewSet, basename='filerecord') router.register('filerecord', FilerecordViewSet, basename='filerecord')
router.register('fileborrow', FileborrowViewSet, basename='fileborrow') router.register('fileborrow', FileborrowViewSet, basename='fileborrow')
router.register('publicity', PublicityViewSet, basename='publicity') 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 = [ urlpatterns = [
path(API_BASE_URL, include(router.urls)), path(API_BASE_URL, include(router.urls)),
] ]

View File

@ -1,17 +1,13 @@
from django.shortcuts import render from django.shortcuts import render
from apps.utils.viewsets import CustomModelViewSet, CustomGenericViewSet from apps.utils.viewsets import CustomModelViewSet, CustomGenericViewSet
from .models import Mroom, MroomBooking, MroomSlot, LendingSeal, Vehicle, FileRecord, BorrowRecord, Publicity, PatentInfo, Papersecret from .models import Mroom, MroomBooking, MroomSlot, LendingSeal, Vehicle, FileRecord, BorrowRecord, Publicity
# Publicity, , PaperOfm, Platform, Project, PatentRecord, PaperRecord, ProjectApproval, ProjectInfo)
from .serializers import (MroomSerializer, MroomBookingSerializer, MroomSlotSerializer, LendingSealSerializer, from .serializers import (MroomSerializer, MroomBookingSerializer, MroomSlotSerializer, LendingSealSerializer,
VehicleSerializer, FileRecordSerializer, BorrowRecordSerializer, PublicitySerializer, PatentInfoSerializer, PaperSeSerializer) VehicleSerializer, FileRecordSerializer, BorrowRecordSerializer, PublicitySerializer)
# ,SealSerializer,
# LendingSealSerializer, FileRecordSerializer, BorrowRecordSerializer, PublicitySerializer,
# PatentInfoSerializer, PaperSerializer, PlatformSerializer, ProjectSerializer, ProjectMemberSerializer, PaperRecordSerializer, ProjectApprovalSerializer, ProjectInfoSerializer)
from rest_framework.decorators import action
from apps.utils.mixins import CustomListModelMixin from apps.utils.mixins import CustomListModelMixin
from rest_framework.exceptions import ParseError from rest_framework.exceptions import ParseError
from apps.ofm.filters import MroomBookingFilterset, SealFilter, BorrowRecordFilter from apps.ofm.filters import MroomBookingFilterset, SealFilter, BorrowRecordFilter
from rest_framework.response import Response
class MroomViewSet(CustomModelViewSet): class MroomViewSet(CustomModelViewSet):
"""list: 会议室 """list: 会议室
@ -171,26 +167,57 @@ class PublicityViewSet(CustomModelViewSet):
ordering = ["-create_time", "number"] ordering = ["-create_time", "number"]
class PatentInfoViewSet(CustomModelViewSet): # class PatentInfoViewSet(CustomModelViewSet):
"""list: 专利 # """list: 专利
专利 # 专利
""" # """
queryset = PatentInfo.objects.all() # queryset = PatentInfo.objects.all()
serializer_class = PatentInfoSerializer # serializer_class = PatentInfoSerializer
filterset_fields = ["name", "author", "type"] # filterset_fields = ["name", "author", "type"]
ordering = ["-create_time", "name", "author", "type"] # ordering = ["-create_time", "name", "author", "type"]
class PapersecretViewSet(CustomModelViewSet): # class PapersecretViewSet(CustomModelViewSet):
"""list: 论文申密审批 # """list: 论文申密审批
论文申密审批 # 论文申密审批
""" # """
queryset = Papersecret.objects.all() # queryset = Papersecret.objects.all()
serializer_class = PaperSeSerializer # serializer_class = PaperSeSerializer
filterset_fields = ["paper_name", "author"] # filterset_fields = ["paper_name", "author"]
ordering = ["create_time", "paper_name"] # 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): # class PlatformViewSet(CustomModelViewSet):

0
apps/srm/__init__.py Normal file
View File

3
apps/srm/admin.py Normal file
View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

7
apps/srm/apps.py Normal file
View File

@ -0,0 +1,7 @@
from django.apps import AppConfig
class SrmConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'apps.srm'
verbose_name = '科研管理'

View File

@ -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,
},
),
]

View File

112
apps/srm/models.py Normal file
View File

@ -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)

94
apps/srm/serializers.py Normal file
View File

@ -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

56
apps/srm/services.py Normal file
View File

@ -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()

3
apps/srm/tests.py Normal file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

16
apps/srm/urls.py Normal file
View File

@ -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)),
]

63
apps/srm/views.py Normal file
View File

@ -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)

View File

@ -85,7 +85,8 @@ INSTALLED_APPS = [
'apps.cm', 'apps.cm',
'apps.cms', 'apps.cms',
'apps.wpmw', 'apps.wpmw',
'apps.ofm' 'apps.ofm',
'apps.srm',
] ]
MIDDLEWARE = [ MIDDLEWARE = [

View File

@ -76,6 +76,7 @@ urlpatterns = [
path('', include('apps.cms.urls')), path('', include('apps.cms.urls')),
path('', include('apps.wpmw.urls')), path('', include('apps.wpmw.urls')),
path('', include('apps.ofm.urls')), path('', include('apps.ofm.urls')),
path('', include('apps.srm.urls')),
# 前端页面入口 # 前端页面入口
path('', TemplateView.as_view(template_name="index.html")), path('', TemplateView.as_view(template_name="index.html")),