Merge branch 'develop' of https://e.coding.net/ctcdevteam/hberp/hberp into develop
This commit is contained in:
commit
d1fd46446a
|
|
@ -129,7 +129,7 @@ class RecordFormField(CommonAModel):
|
||||||
|
|
||||||
class ProductProcess(CommonAModel):
|
class ProductProcess(CommonAModel):
|
||||||
"""
|
"""
|
||||||
产品生产工艺
|
产品生产工艺集
|
||||||
"""
|
"""
|
||||||
product = models.ForeignKey(Material, verbose_name='产品', on_delete=models.CASCADE)
|
product = models.ForeignKey(Material, verbose_name='产品', on_delete=models.CASCADE)
|
||||||
process = models.ForeignKey(Process, verbose_name='工序', on_delete=models.CASCADE)
|
process = models.ForeignKey(Process, verbose_name='工序', on_delete=models.CASCADE)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
class SamConfig(AppConfig):
|
||||||
|
name = 'apps.pm'
|
||||||
|
verbose_name = '生产计划管理'
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
# Generated by Django 3.2.6 on 2021-10-08 08:02
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
('mtm', '0018_material_count'),
|
||||||
|
('sam', '0004_order_planed_count'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ProductionPlan',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(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='删除标记')),
|
||||||
|
('number', models.CharField(max_length=50, unique=True, verbose_name='编号')),
|
||||||
|
('count', models.IntegerField(default=0, verbose_name='生产数量')),
|
||||||
|
('start_date', models.DateField(verbose_name='计划开工日期')),
|
||||||
|
('end_date', models.DateField(verbose_name='计划完工日期')),
|
||||||
|
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='productionplan_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||||
|
('order', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='sam.order', verbose_name='关联订单')),
|
||||||
|
('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='生产产品')),
|
||||||
|
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='productionplan_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': '生产计划',
|
||||||
|
'verbose_name_plural': '生产计划',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.2.6 on 2021-10-08 08:30
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('pm', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='productionplan',
|
||||||
|
name='count',
|
||||||
|
field=models.IntegerField(default=1, verbose_name='生产数量'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
from apps.system.models import CommonAModel
|
||||||
|
from django.db import models
|
||||||
|
from django.contrib.auth.models import AbstractUser
|
||||||
|
from django.db.models.base import Model
|
||||||
|
import django.utils.timezone as timezone
|
||||||
|
from django.db.models.query import QuerySet
|
||||||
|
|
||||||
|
from utils.model import SoftModel, BaseModel
|
||||||
|
from apps.mtm.models import Material
|
||||||
|
from apps.sam.models import Order
|
||||||
|
|
||||||
|
|
||||||
|
class ProductionPlan(CommonAModel):
|
||||||
|
"""
|
||||||
|
生产计划
|
||||||
|
"""
|
||||||
|
number = models.CharField('编号', max_length=50, unique=True)
|
||||||
|
order = models.ForeignKey(Order, verbose_name='关联订单', null=True, blank=True, on_delete=models.SET_NULL)
|
||||||
|
product = models.ForeignKey(Material, verbose_name='生产产品', on_delete=models.CASCADE)
|
||||||
|
count = models.IntegerField('生产数量', default=1)
|
||||||
|
start_date = models.DateField('计划开工日期')
|
||||||
|
end_date = models.DateField('计划完工日期')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = '生产计划'
|
||||||
|
verbose_name_plural = verbose_name
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.number
|
||||||
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
from apps.pm.models import ProductionPlan
|
||||||
|
from rest_framework import serializers
|
||||||
|
from apps.sam.serializers import OrderSerializer
|
||||||
|
from apps.mtm.serializers import MaterialSimpleSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class ProductionPlanCreateFromOrderSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = ProductionPlan
|
||||||
|
fields = ['order', 'number', 'count', 'start_date', 'end_date']
|
||||||
|
|
||||||
|
class ProductionPlanSerializer(serializers.ModelSerializer):
|
||||||
|
order_ = OrderSerializer(source='order', read_only=True)
|
||||||
|
product_ = MaterialSimpleSerializer(source='product', read_only=True)
|
||||||
|
class Meta:
|
||||||
|
model = ProductionPlan
|
||||||
|
fields ='__all__'
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
from apps.pm.views import ProductionPlanViewSet
|
||||||
|
from django.db.models import base
|
||||||
|
from rest_framework import urlpatterns
|
||||||
|
from django.urls import path, include
|
||||||
|
from rest_framework.routers import DefaultRouter
|
||||||
|
|
||||||
|
router = DefaultRouter()
|
||||||
|
router.register('productionplan', ProductionPlanViewSet, basename='productionplan')
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('', include(router.urls)),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
from apps.system.mixins import CreateUpdateModelAMixin
|
||||||
|
from apps.pm.serializers import ProductionPlanCreateFromOrderSerializer, ProductionPlanSerializer
|
||||||
|
from rest_framework.mixins import CreateModelMixin, ListModelMixin
|
||||||
|
from apps.pm.models import ProductionPlan
|
||||||
|
from rest_framework.viewsets import GenericViewSet, ModelViewSet
|
||||||
|
from django.shortcuts import render
|
||||||
|
from apps.sam.models import Order
|
||||||
|
from rest_framework.exceptions import APIException
|
||||||
|
from rest_framework.response import Response
|
||||||
|
# Create your views here.
|
||||||
|
|
||||||
|
def updateOrderPlanedCount(order):
|
||||||
|
"""
|
||||||
|
更新订单已排数量
|
||||||
|
"""
|
||||||
|
planed_count = 0
|
||||||
|
plans = ProductionPlan.objects.filter(order=order)
|
||||||
|
for i in plans:
|
||||||
|
planed_count = planed_count + i.count
|
||||||
|
order.planed_count = planed_count
|
||||||
|
order.save()
|
||||||
|
|
||||||
|
class ProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, CreateModelMixin, GenericViewSet):
|
||||||
|
"""
|
||||||
|
生产计划
|
||||||
|
"""
|
||||||
|
perms_map = {'*': '*'}
|
||||||
|
queryset = ProductionPlan.objects.select_related('order', 'order__contract', 'product')
|
||||||
|
serializer_class = ProductionPlanSerializer
|
||||||
|
search_fields = ['number']
|
||||||
|
filterset_fields = []
|
||||||
|
ordering_fields = ['id']
|
||||||
|
ordering = ['-id']
|
||||||
|
|
||||||
|
def get_serializer_class(self):
|
||||||
|
if self.action in ['create']:
|
||||||
|
return ProductionPlanCreateFromOrderSerializer
|
||||||
|
return ProductionPlanSerializer
|
||||||
|
|
||||||
|
def create(self, request, *args, **kwargs):
|
||||||
|
data = request.data
|
||||||
|
serializer = self.get_serializer(data=data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
if data.get('order', None):
|
||||||
|
order = Order.objects.get(pk=data['order'])
|
||||||
|
if order.planed_count >= data['count'] or data['count'] > 0:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
raise APIException('排产数量错误')
|
||||||
|
instance = serializer.save(create_by=request.user, product=order.product)
|
||||||
|
updateOrderPlanedCount(instance.order)
|
||||||
|
return Response()
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.2.6 on 2021-10-08 07:34
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('sam', '0003_contract_invoice'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='order',
|
||||||
|
name='planed_count',
|
||||||
|
field=models.IntegerField(default=0, verbose_name='已排数量'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -5,6 +5,7 @@ from django.db.models.base import Model
|
||||||
import django.utils.timezone as timezone
|
import django.utils.timezone as timezone
|
||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
|
|
||||||
|
|
||||||
from utils.model import SoftModel, BaseModel
|
from utils.model import SoftModel, BaseModel
|
||||||
from apps.mtm.models import Material
|
from apps.mtm.models import Material
|
||||||
|
|
||||||
|
|
@ -62,6 +63,7 @@ class Order(CommonAModel):
|
||||||
contract = models.ForeignKey(Contract, verbose_name='所属合同', null=True, blank=True, on_delete=models.SET_NULL)
|
contract = models.ForeignKey(Contract, verbose_name='所属合同', null=True, blank=True, on_delete=models.SET_NULL)
|
||||||
product = models.ForeignKey(Material, verbose_name='所需产品', on_delete=models.CASCADE)
|
product = models.ForeignKey(Material, verbose_name='所需产品', on_delete=models.CASCADE)
|
||||||
count = models.IntegerField('所需数量', default=0)
|
count = models.IntegerField('所需数量', default=0)
|
||||||
|
planed_count = models.IntegerField('已排数量', default=0)
|
||||||
delivery_date = models.DateField('交货日期')
|
delivery_date = models.DateField('交货日期')
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = '订单信息'
|
verbose_name = '订单信息'
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@ from apps.sam.models import Contract, Customer, Order
|
||||||
from rest_framework.viewsets import ModelViewSet
|
from rest_framework.viewsets import ModelViewSet
|
||||||
from apps.system.mixins import CreateUpdateCustomMixin
|
from apps.system.mixins import CreateUpdateCustomMixin
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
|
from rest_framework.decorators import action
|
||||||
|
from django.db.models import F
|
||||||
|
from rest_framework.response import Response
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
class CustomerViewSet(CreateUpdateCustomMixin, ModelViewSet):
|
class CustomerViewSet(CreateUpdateCustomMixin, ModelViewSet):
|
||||||
"""
|
"""
|
||||||
|
|
@ -55,4 +57,14 @@ class OrderViewSet(CreateUpdateCustomMixin, ModelViewSet):
|
||||||
def get_serializer_class(self):
|
def get_serializer_class(self):
|
||||||
if self.action in ['create', 'update']:
|
if self.action in ['create', 'update']:
|
||||||
return OrderCreateUpdateSerializer
|
return OrderCreateUpdateSerializer
|
||||||
return OrderSerializer
|
return OrderSerializer
|
||||||
|
|
||||||
|
@action(methods=['get'], detail=False, perms_map={'get':'*'})
|
||||||
|
def toplan(self, request, pk=None):
|
||||||
|
queryset = Order.objects.filter(count__gt=F('planed_count')).order_by('-id')
|
||||||
|
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)
|
||||||
|
|
@ -115,6 +115,13 @@ class TicketFlowSerializer(serializers.ModelSerializer):
|
||||||
model = TicketFlow
|
model = TicketFlow
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
|
class TicketFlowSimpleSerializer(serializers.ModelSerializer):
|
||||||
|
participant_ = UserSimpleSerializer(source='participant', read_only=True)
|
||||||
|
state_ = StateSimpleSerializer(source='state', read_only=True)
|
||||||
|
class Meta:
|
||||||
|
model = TicketFlow
|
||||||
|
exclude = ['ticket_data']
|
||||||
|
|
||||||
|
|
||||||
class TicketHandleSerializer(serializers.Serializer):
|
class TicketHandleSerializer(serializers.Serializer):
|
||||||
transition = serializers.IntegerField(label="流转id")
|
transition = serializers.IntegerField(label="流转id")
|
||||||
|
|
|
||||||
|
|
@ -57,10 +57,11 @@ class WfService(object):
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_ticket_steps(cls, ticket:Ticket):
|
def get_ticket_steps(cls, ticket:Ticket):
|
||||||
steps = cls.get_worlflow_states(ticket.workflow)
|
steps = cls.get_worlflow_states(ticket.workflow)
|
||||||
|
nsteps_list = []
|
||||||
for i in steps:
|
for i in steps:
|
||||||
if ticket.state.is_hidden and ticket.state != i:
|
if ticket.state == i or (not i.is_hidden):
|
||||||
steps.remove(i)
|
nsteps_list.append(i)
|
||||||
return steps
|
return nsteps_list
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_ticket_transitions(cls, ticket:Ticket):
|
def get_ticket_transitions(cls, ticket:Ticket):
|
||||||
|
|
@ -104,7 +105,7 @@ class WfService(object):
|
||||||
expression = i['expression'].format(**ticket_all_value)
|
expression = i['expression'].format(**ticket_all_value)
|
||||||
import datetime, time # 用于支持条件表达式中对时间的操作
|
import datetime, time # 用于支持条件表达式中对时间的操作
|
||||||
if eval(expression):
|
if eval(expression):
|
||||||
destination_state = State.objects.get(i['expression'].get('target_state'))
|
destination_state = State.objects.get(pk=i['target_state'])
|
||||||
return destination_state
|
return destination_state
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
from django.db.models import base
|
from django.db.models import base
|
||||||
from rest_framework import urlpatterns
|
from rest_framework import urlpatterns
|
||||||
from apps.wf.views import CustomFieldViewSet, StateViewSet, TicketViewSet, TransitionViewSet, WorkflowViewSet
|
from apps.wf.views import CustomFieldViewSet, StateViewSet, TicketFlowViewSet, TicketViewSet, TransitionViewSet, WorkflowViewSet
|
||||||
from django.urls import path, include
|
from django.urls import path, include
|
||||||
from rest_framework.routers import DefaultRouter
|
from rest_framework.routers import DefaultRouter
|
||||||
|
|
||||||
|
|
@ -10,6 +10,7 @@ router.register('state', StateViewSet, basename='wf_state')
|
||||||
router.register('transition', TransitionViewSet, basename='wf_transitions')
|
router.register('transition', TransitionViewSet, basename='wf_transitions')
|
||||||
router.register('customfield', CustomFieldViewSet, basename='wf_customfield')
|
router.register('customfield', CustomFieldViewSet, basename='wf_customfield')
|
||||||
router.register('ticket', TicketViewSet, basename='wf_ticket')
|
router.register('ticket', TicketViewSet, basename='wf_ticket')
|
||||||
|
router.register('ticketflow', TicketFlowViewSet, basename='wf_ticketflow')
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', include(router.urls)),
|
path('', include(router.urls)),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ from django.core.exceptions import AppRegistryNotReady
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin
|
from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin
|
||||||
from apps.wf.serializers import CustomFieldSerializer, StateSerializer, TicketCreateSerializer, TicketFlowSerializer, TicketHandleSerializer, TicketSerializer, TransitionSerializer, WorkflowSerializer, TicketListSerializer, TicketDetailSerializer
|
from apps.wf.serializers import CustomFieldSerializer, StateSerializer, TicketCreateSerializer, TicketFlowSerializer, TicketFlowSimpleSerializer, TicketHandleSerializer, TicketSerializer, TransitionSerializer, WorkflowSerializer, TicketListSerializer, TicketDetailSerializer
|
||||||
from django.shortcuts import get_object_or_404, render
|
from django.shortcuts import get_object_or_404, render
|
||||||
from rest_framework.viewsets import GenericViewSet, ModelViewSet
|
from rest_framework.viewsets import GenericViewSet, ModelViewSet
|
||||||
from rest_framework.decorators import action, api_view
|
from rest_framework.decorators import action, api_view
|
||||||
|
|
@ -247,6 +247,16 @@ class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin
|
||||||
ticket = self.get_object()
|
ticket = self.get_object()
|
||||||
steps = WfService.get_ticket_steps(ticket)
|
steps = WfService.get_ticket_steps(ticket)
|
||||||
return Response(StateSerializer(instance=steps, many=True).data)
|
return Response(StateSerializer(instance=steps, many=True).data)
|
||||||
|
|
||||||
|
@action(methods=['get'], detail=True, perms_map={'get':'*'})
|
||||||
|
def flowlogs(self, request, pk=None):
|
||||||
|
"""
|
||||||
|
工单流转记录
|
||||||
|
"""
|
||||||
|
ticket = self.get_object()
|
||||||
|
flowlogs = TicketFlow.objects.filter(ticket=ticket).order_by('-create_time')
|
||||||
|
serializer = TicketFlowSerializer(instance=flowlogs, many=True)
|
||||||
|
return Response(serializer.data)
|
||||||
|
|
||||||
@action(methods=['get'], detail=True, perms_map={'get':'*'})
|
@action(methods=['get'], detail=True, perms_map={'get':'*'})
|
||||||
def transitions(self, request, pk=None):
|
def transitions(self, request, pk=None):
|
||||||
|
|
@ -276,6 +286,13 @@ class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin
|
||||||
return Response()
|
return Response()
|
||||||
else:
|
else:
|
||||||
raise APIException('无需接单')
|
raise APIException('无需接单')
|
||||||
|
|
||||||
|
@action(methods=['post'], detail=True, perms_map={'post':'*'})
|
||||||
|
def retreat(self, request, pk=None):
|
||||||
|
"""
|
||||||
|
撤回工单,允许创建人在指定状态撤回工单至初始状态,状态设置中开启允许撤回
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
class TicketFlowViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
|
class TicketFlowViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
|
||||||
"""
|
"""
|
||||||
|
|
@ -285,5 +302,5 @@ class TicketFlowViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
|
||||||
queryset = TicketFlow.objects.all()
|
queryset = TicketFlow.objects.all()
|
||||||
serializer_class = TicketFlowSerializer
|
serializer_class = TicketFlowSerializer
|
||||||
search_fields = ['suggestion']
|
search_fields = ['suggestion']
|
||||||
filterset_fields = ['paticipant', 'state', 'ticket']
|
filterset_fields = ['ticket']
|
||||||
ordering = ['-create_time']
|
ordering = ['-create_time']
|
||||||
|
|
@ -54,7 +54,8 @@ INSTALLED_APPS = [
|
||||||
'apps.mtm',
|
'apps.mtm',
|
||||||
'apps.inm',
|
'apps.inm',
|
||||||
'apps.sam',
|
'apps.sam',
|
||||||
'apps.qm'
|
'apps.qm',
|
||||||
|
'apps.pm'
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ urlpatterns = [
|
||||||
path('api/inm/', include('apps.inm.urls')),
|
path('api/inm/', include('apps.inm.urls')),
|
||||||
path('api/sam/', include('apps.sam.urls')),
|
path('api/sam/', include('apps.sam.urls')),
|
||||||
path('api/qm/', include('apps.qm.urls')),
|
path('api/qm/', include('apps.qm.urls')),
|
||||||
|
path('api/pm/', include('apps.pm.urls')),
|
||||||
# 工具
|
# 工具
|
||||||
path('api/utils/signature/', GenSignature.as_view()),
|
path('api/utils/signature/', GenSignature.as_view()),
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue