This commit is contained in:
caoqianming 2020-10-29 08:40:29 +08:00
parent cb734240e2
commit c3fbfa02fa
13 changed files with 264 additions and 89 deletions

View File

@ -152,7 +152,7 @@ export const asyncRoutes = [
path: 'certapp/:id/:action/', path: 'certapp/:id/:action/',
name: 'Certappmember', name: 'Certappmember',
component: () => import('@/views/certapp/certapphandle'), component: () => import('@/views/certapp/certapphandle'),
meta: { title: '派', icon: 'example', perms: ['plan_view'] }, meta: { title: '派', icon: 'example', perms: ['plan_view'] },
hidden: true hidden: true
}, },
] ]
@ -289,6 +289,13 @@ export const asyncRoutes = [
meta: { title: '证书颁发', icon: 'example', perms: ['certificate_issue'] }, meta: { title: '证书颁发', icon: 'example', perms: ['certificate_issue'] },
hidden: true hidden: true
}, },
{
path: 'certapp/:id/issue/',
name: 'Certappissue',
component: () => import('@/views/certapp/certapphandle'),
meta: { title: '发证/通知', icon: 'example', perms: ['certapp_issue'] },
hidden: true
},
] ]
}, },
{ {

View File

@ -218,7 +218,7 @@ getDictList({type__code:'cert_decision', pageoff:true}).then(res=>{
if (!valid) return; if (!valid) return;
accessCertapp(this.certapp, this.formData).then((res) => { accessCertapp(this.certapp, this.formData).then((res) => {
this.$message.success('成功') this.$message.success('成功')
}); })
}); });
}, },
handleAcessunit(val,id){ handleAcessunit(val,id){
@ -227,7 +227,7 @@ getDictList({type__code:'cert_decision', pageoff:true}).then(res=>{
this.formData.state = res.data.state this.formData.state = res.data.state
this.$emit("stateChange", res.data.state); this.$emit("stateChange", res.data.state);
this.$emit("flowChange"); this.$emit("flowChange");
}) }).catch(()=>{this.getUnitList()})
} }
} }

View File

@ -35,15 +35,19 @@
>刷新</el-button> >刷新</el-button>
</el-col> </el-col>
</el-row> </el-row>
<el-card style="margin-top:6px">
<div slot="header" class="clearfix">
<span>待评定业务</span>
</div>
<el-table <el-table
v-loading="listLoading" v-loading="listLoading"
:data="tableData.results" :data="tableData.results"
style="width: 100%;margin-top:10px;"
border border
fit fit
stripe stripe
highlight-current-row highlight-current-row
height="320"
@row-click="handleRclick"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
<el-table-column label="申请单号"> <el-table-column label="申请单号">
@ -99,6 +103,55 @@
:limit.sync="listQuery.page_size" :limit.sync="listQuery.page_size"
@pagination="getList" @pagination="getList"
/> />
</el-card>
<el-card style="margin-top:6px">
<div slot="header" class="clearfix">
<span>本业务认证单元</span>
</div>
<el-table
v-loading="listLoading2"
:data="tableData2"
border
fit
stripe
highlight-current-row
height="320"
>
<el-table-column type="index" width="50" />
<el-table-column label="单元名称">
<template slot-scope="scope" v-if="scope.row.certunit_">{{ scope.row.certunit_.name }}</template>
</el-table-column>
<el-table-column label="单元描述">
<template slot-scope="scope" v-if="scope.row.certunit_">
{{scope.row.certunit_.description}}
</template>
</el-table-column>
<el-table-column label="状态">
<template slot-scope="scope">
{{ scope.row.teststate}}
</template>
</el-table-column>
<el-table-column label="认证决定">
<template slot-scope="scope" v-if="scope.row.decision_">
{{ scope.row.decision_.name }}
</template>
</el-table-column>
<el-table-column label="关联证书">
<template slot-scope="scope" v-if="scope.row.certificate_">{{ scope.row.certificate_.number}}</template>
</el-table-column>
<el-table-column label="操作" fixed="right">
<template slot-scope="scope" >
<el-button
v-if="scope.row.teststate=='待评定'"
type="primary"
size="small"
:disabled="!checkPermission(['certapp_accessment'])"
@click="handleAccessment2(scope)"
>评定</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</div> </div>
</template> </template>
<script> <script>
@ -110,15 +163,20 @@ import checkPermission from '@/utils/permission'
import Treeselect from '@riophae/vue-treeselect' import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css' import '@riophae/vue-treeselect/dist/vue-treeselect.css'
import { genTree } from '../../utils' import { genTree } from '../../utils'
import { getCertappunitList } from "@/api/certappunit"
export default { export default {
components: { Pagination, Treeselect }, components: { Pagination, Treeselect },
data() { data() {
return { return {
nowCetapp:{},
tableData: {count:0}, tableData: {count:0},
listLoading: true, tableData2: [],
listLoading: false,
listLoading2:false,
listQuery: { listQuery: {
page: 1, page: 1,
page_size: 20 page_size: 20,
certappunit_certapp__teststate:'待评定'
}, },
deptOptions: [], deptOptions: [],
field_list:[] field_list:[]
@ -148,7 +206,8 @@ export default {
resetFilter() { resetFilter() {
this.listQuery = { this.listQuery = {
page: 1, page: 1,
page_size: 20 page_size: 20,
certappunit_certapp__teststate:'待评定'
} }
this.getList() this.getList()
}, },
@ -179,7 +238,25 @@ this.$router.push({
name: "Certappaccess", name: "Certappaccess",
params: { id: scope.row.id, action:'access' }, params: { id: scope.row.id, action:'access' },
}); });
} },
handleAccessment2(scope) {
this.$router.push({
name: "Certappaccess",
params: { id: this.nowCetapp.id, action:'access' },
});
},
handleRclick(row, column, event) {
this.listLoading2 = true;
this.nowCetapp = {id:row.id,number:row.number}
getCertappunitList({ certapp: row.id, pageoff:true})
.then((res) => {
this.tableData2 = res.data;
this.listLoading2 = false;
})
.catch((e) => {
this.listLoading2 = false;
});
},
} }
}; };
</script> </script>

View File

@ -44,7 +44,7 @@
<el-tab-pane label="认证评定" name="Certappaccess" v-if="certapp" lazy> <el-tab-pane label="认证评定" name="Certappaccess" v-if="certapp" lazy>
<access :certapp="certapp" :key="Certappaccesskey" @stateChange="stateChange" @flowChange="flowChange"></access> <access :certapp="certapp" :key="Certappaccesskey" @stateChange="stateChange" @flowChange="flowChange"></access>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="证书颁发/通知" name="Certissue" v-if="certapp" lazy> <el-tab-pane label="证书颁发/通知" name="Certappissue" v-if="certapp" lazy>
<issue :certapp="certapp"></issue> <issue :certapp="certapp"></issue>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>

View File

@ -14,6 +14,9 @@
<el-table-column label="单元名称"> <el-table-column label="单元名称">
<template slot-scope="scope" v-if="scope.row.certunit_">{{ scope.row.certunit_.name }}</template> <template slot-scope="scope" v-if="scope.row.certunit_">{{ scope.row.certunit_.name }}</template>
</el-table-column> </el-table-column>
<el-table-column label="状态">
<template slot-scope="scope" >{{ scope.row.teststate }}</template>
</el-table-column>
<el-table-column label="认证决定"> <el-table-column label="认证决定">
<template slot-scope="scope" v-if="scope.row.decision_"> <template slot-scope="scope" v-if="scope.row.decision_">
{{ scope.row.decision_.name }} {{ scope.row.decision_.name }}

View File

@ -1,6 +1,7 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<div style="display:flex"> <el-row :gutter="6">
<el-col :xs="24" :md="4">
<treeselect <treeselect
v-model="listQuery.user__dept" v-model="listQuery.user__dept"
:multiple="false" :multiple="false"
@ -8,15 +9,18 @@
placeholder="所属组织" placeholder="所属组织"
:disable-branch-nodes="true" :disable-branch-nodes="true"
@input="handleFilter" @input="handleFilter"
style="width: 280px" clearable/> style="width: 100%" clearable/>
</el-col>
<el-col :xs="24" :md="4">
<el-input <el-input
v-model="listQuery.search" v-model="listQuery.search"
placeholder="姓名/易记码/编号/注册领域" placeholder="姓名/易记码/编号/注册领域"
style="width: 300px;margin-left:10px" style="width: 100%"
class="filter-item" class="filter-item"
@keyup.enter.native="handleFilter" @keyup.enter.native="handleFilter"
/> />
</el-col>
<el-col :xs="24" :md="4">
<el-button <el-button
class="filter-item" class="filter-item"
type="primary" type="primary"
@ -28,17 +32,22 @@
type="primary" type="primary"
icon="el-icon-refresh-left" icon="el-icon-refresh-left"
@click="resetFilter" @click="resetFilter"
>刷新重置</el-button> >刷新</el-button>
</div> </el-col>
</el-row>
<el-card style="margin-top:6px">
<div slot="header" class="clearfix">
<span>待处理业务</span>
</div>
<el-table <el-table
v-loading="listLoading" v-loading="listLoading"
:data="tableData.results" :data="tableData.results"
style="width: 100%;margin-top:10px;"
border border
fit fit
stripe stripe
highlight-current-row highlight-current-row
height="320"
@row-click="handleRclick"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
<el-table-column label="申请单号"> <el-table-column label="申请单号">
@ -75,9 +84,9 @@
<el-button <el-button
type="primary" type="primary"
size="small" size="small"
:disabled="!checkPermission(['certapp_accessment'])" :disabled="!checkPermission(['certificate_issue'])"
@click="handleIssue(scope)" @click="handleIssue(scope)"
></el-button> >/通知</el-button>
<el-button <el-button
size="small" size="small"
:disabled="!checkPermission(['certapp_detail'])" :disabled="!checkPermission(['certapp_detail'])"
@ -94,6 +103,55 @@
:limit.sync="listQuery.page_size" :limit.sync="listQuery.page_size"
@pagination="getList" @pagination="getList"
/> />
</el-card>
<el-card style="margin-top:6px">
<div slot="header" class="clearfix">
<span>本业务认证单元</span>
</div>
<el-table
v-loading="listLoading2"
:data="tableData2"
border
fit
stripe
highlight-current-row
height="320"
>
<el-table-column type="index" width="50" />
<el-table-column label="单元名称">
<template slot-scope="scope" v-if="scope.row.certunit_">{{ scope.row.certunit_.name }}</template>
</el-table-column>
<el-table-column label="单元描述">
<template slot-scope="scope" v-if="scope.row.certunit_">
{{scope.row.certunit_.description}}
</template>
</el-table-column>
<el-table-column label="状态">
<template slot-scope="scope">
{{ scope.row.teststate}}
</template>
</el-table-column>
<el-table-column label="认证决定">
<template slot-scope="scope" v-if="scope.row.decision_">
{{ scope.row.decision_.name }}
</template>
</el-table-column>
<el-table-column label="关联证书">
<template slot-scope="scope" v-if="scope.row.certificate_">{{ scope.row.certificate_.number}}</template>
</el-table-column>
<el-table-column label="操作" fixed="right">
<template slot-scope="scope" >
<el-button
v-if="scope.row.teststate=='已评定'"
type="primary"
size="small"
:disabled="!checkPermission(['certificate_issue'])"
@click="handleIssue2(scope)"
>发证/通知</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</div> </div>
</template> </template>
<script> <script>
@ -105,15 +163,20 @@ import checkPermission from '@/utils/permission'
import Treeselect from '@riophae/vue-treeselect' import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css' import '@riophae/vue-treeselect/dist/vue-treeselect.css'
import { genTree } from '../../utils' import { genTree } from '../../utils'
import { getCertappunitList } from "@/api/certappunit"
export default { export default {
components: { Pagination, Treeselect }, components: { Pagination, Treeselect },
data() { data() {
return { return {
nowCetapp:{},
tableData: {count:0}, tableData: {count:0},
listLoading: true, tableData2: [],
listLoading: false,
listLoading2:false,
listQuery: { listQuery: {
page: 1, page: 1,
page_size: 20 page_size: 20,
certappunit_certapp__teststate:'已评定'
}, },
deptOptions: [], deptOptions: [],
field_list:[] field_list:[]
@ -143,7 +206,8 @@ export default {
resetFilter() { resetFilter() {
this.listQuery = { this.listQuery = {
page: 1, page: 1,
page_size: 20 page_size: 20,
certappunit_certapp__teststate:'待评定'
} }
this.getList() this.getList()
}, },
@ -171,10 +235,28 @@ this.$router.push({
}, },
handleIssue(scope) { handleIssue(scope) {
this.$router.push({ this.$router.push({
name: "Certissue", name: "Certappissue",
params: { id: scope.row.id, action:'issue' }, params: { id: scope.row.id, action:'issue' },
}); });
} },
handleIssue2(scope) {
this.$router.push({
name: "Certappissue",
params: { id: this.nowCetapp.id, action:'issue' },
});
},
handleRclick(row, column, event) {
this.listLoading2 = true;
this.nowCetapp = {id:row.id,number:row.number}
getCertappunitList({ certapp: row.id, pageoff:true})
.then((res) => {
this.tableData2 = res.data;
this.listLoading2 = false;
})
.catch((e) => {
this.listLoading2 = false;
});
},
} }
}; };
</script> </script>

View File

@ -2,40 +2,8 @@ from utils import serializer
from rest_framework import serializers from rest_framework import serializers
from .models import * from .models import *
from apps.project.models import CertApp
from apps.system.serializers import DictSimpleSerializer, UserListSerializer, UserSimpleSerializer from apps.system.serializers import DictSimpleSerializer, UserSimpleSerializer
from apps.project.models import Project
from apps.plan.models import Member
from apps.project.serializers import PlanSerializer
from apps.plan.serializers import MemberSerializer
class ProjectSerializerX(serializers.ModelSerializer):
create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
certapps = serializers.SerializerMethodField()
plan_ = PlanSerializer(source='plan', read_only=True)
members = serializers.SerializerMethodField()
class Meta:
model = Project
fields = '__all__'
def get_certapps(self, obj):
certapps = []
for i in obj.certapp_project.filter(is_deleted=False):
certapps.append(i.cert_field.code +'(' + i.cccpv_class.name +')')
return certapps
def get_members(self, obj):
queryset = obj.certapp_project.all()
members = Member.objects.filter(certapp__in=queryset, is_deleted=False).distinct('is_leader','user').order_by('-is_leader')
serializer = MemberSerializer(members, many=True)
return serializer.data
@staticmethod
def setup_eager_loading(queryset):
""" Perform necessary eager loading of data. """
queryset = queryset.select_related('create_by', 'plan')
queryset = queryset.prefetch_related('certapp_project',)
return queryset
class CertappSerializerX(serializers.ModelSerializer): class CertappSerializerX(serializers.ModelSerializer):
cert_field_ = DictSimpleSerializer(source='cert_field', read_only=True) cert_field_ = DictSimpleSerializer(source='cert_field', read_only=True)
@ -43,7 +11,6 @@ class CertappSerializerX(serializers.ModelSerializer):
cnas_scopes_ = DictSimpleSerializer(source='cnas_scopes', many=True , read_only=True) cnas_scopes_ = DictSimpleSerializer(source='cnas_scopes', many=True , read_only=True)
create_by_ = UserSimpleSerializer(source='create_by', read_only=True) create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
accept_by_ = UserSimpleSerializer(source='accept_by', read_only=True) accept_by_ = UserSimpleSerializer(source='accept_by', read_only=True)
members = serializers.SerializerMethodField()
class Meta: class Meta:
model = CertApp model = CertApp
fields = '__all__' fields = '__all__'
@ -54,8 +21,4 @@ class CertappSerializerX(serializers.ModelSerializer):
queryset = queryset.select_related('cert_field', 'cccpv_class', 'create_by', 'accept_by') queryset = queryset.select_related('cert_field', 'cccpv_class', 'create_by', 'accept_by')
queryset = queryset.prefetch_related('cnas_scopes', 'member_certapp') queryset = queryset.prefetch_related('cnas_scopes', 'member_certapp')
return queryset return queryset
def get_members(self, obj):
members = Member.objects.filter(certapp=obj, is_deleted=False).order_by('-is_leader')
serializer = MemberSerializer(members, many=True)
return serializer.data

View File

@ -4,14 +4,19 @@ from rest_framework.mixins import ListModelMixin
from .models import * from .models import *
from .serializers import * from .serializers import *
from apps.project.models import * from apps.project.models import CertApp
# Create your views here. # Create your views here.
class CertaccessViewSet(PageOrNot, ListModelMixin, GenericViewSet): class CertaccessViewSet(PageOrNot, ListModelMixin, GenericViewSet):
""" """
业务评定 业务评定
""" """
perms_map = {'get': 'access_view'} perms_map = {'get': 'access_view'}
queryset = CertApp.objects.all()
serializer_class = CertappSerializerX serializer_class = CertappSerializerX
filterset_fields = [] filterset_fields = []
ordering = ['-create_time'] ordering = ['-create_time']
def get_queryset(self):
queryset = CertApp.objects.filter(state__in=['产品检测', '评定', '出证'])
if hasattr(self.get_serializer_class(), 'setup_eager_loading'):
queryset = self.get_serializer_class().setup_eager_loading(queryset)
return queryset

View File

@ -29,10 +29,7 @@ class EnterpriseAddressSerializer(serializers.ModelSerializer):
model = EnterpriseAddress model = EnterpriseAddress
fields = '__all__' fields = '__all__'
class SimpEnterpriseSerializer(serializers.ModelSerializer):
class Meta:
model = Enterprise
fields = ['name']
class CertunitSerializer(serializers.ModelSerializer): class CertunitSerializer(serializers.ModelSerializer):
standard_ = StandardSerializer(source='standard', read_only=True) standard_ = StandardSerializer(source='standard', read_only=True)
enterprise_ = serializers.CharField(source='enterprise',read_only=True) enterprise_ = serializers.CharField(source='enterprise',read_only=True)
@ -40,14 +37,15 @@ class CertunitSerializer(serializers.ModelSerializer):
model = Certunit model = Certunit
fields = '__all__' fields = '__all__'
class CertunitSimpleSerializer(serializers.ModelSerializer):
enterprise_ = SimpEnterpriseSerializer(source='enterprise',read_only=True)
class Meta:
model = Certunit
fields = ['id', 'name','description','enterprise','enterprise_']
class EnterpriseSimpleSerializer(serializers.ModelSerializer): class EnterpriseSimpleSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Enterprise model = Enterprise
fields = ['id', 'name'] fields = ['id', 'name']
class CertunitSimpleSerializer(serializers.ModelSerializer):
class Meta:
model = Certunit
fields = ['id', 'name','description']

View File

@ -48,14 +48,29 @@ class MemberViewSet(CreateUpdateCustomMixin, PageOrNot, ModelViewSet):
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data) serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
if CertApp.object.get(pk=request.data['certapp'])!='策划': if CertApp.objects.get(pk=request.data['certapp']).project.state !='策划':
return Response('业务状态异常,操作失败', status = status.HTTP_400_BAD_REQUEST) return Response('项目状态异常,操作失败', status = status.HTTP_400_BAD_REQUEST)
if Member.objects.filter(user = request.data['user'], certapp=request.data['certapp'], is_deleted=False).exists(): if Member.objects.filter(user = request.data['user'], certapp=request.data['certapp'], is_deleted=False).exists():
return Response('已存在该成员', status= status.HTTP_400_BAD_REQUEST) return Response('已存在该成员', status= status.HTTP_400_BAD_REQUEST)
self.perform_create(serializer) self.perform_create(serializer)
headers = self.get_success_headers(serializer.data) headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
if CertApp.objects.get(pk=request.data['certapp']).project.state !='策划中':
return Response('项目状态异常,操作失败', status = status.HTTP_400_BAD_REQUEST)
if getattr(instance, '_prefetched_objects_cache', None):
# If 'prefetch_related' has been applied to a queryset, we need to
# forcibly invalidate the prefetch cache on the instance.
instance._prefetched_objects_cache = {}
return Response(serializer.data)
@action(methods=['put'], detail=True, perms_map={'put':'audit_days'}, @action(methods=['put'], detail=True, perms_map={'put':'audit_days'},
url_name='audit_days') url_name='audit_days')
def days(self, request, *args, **kwargs): def days(self, request, *args, **kwargs):

View File

@ -0,0 +1,21 @@
# Generated by Django 3.0.7 on 2020-10-23 03:09
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('project', '0053_project_feedback_remark'),
]
operations = [
migrations.AddField(
model_name='certappunit',
name='assessor',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='certappunit_assessor', to=settings.AUTH_USER_MODEL, verbose_name='评定人'),
),
]

View File

@ -243,7 +243,7 @@ class Certappunit(CommonBModel):
('待提取报告', '待提取报告'), ('待提取报告', '待提取报告'),
('待实验室整改', '待实验室整改'), ('待实验室整改', '待实验室整改'),
('待评定', '待评定'), ('待评定', '待评定'),
('评定完成', '评定完成'), ('评定', '评定'),
('任务撤销', '任务撤销'), ('任务撤销', '任务撤销'),
) )
@ -272,7 +272,7 @@ class Certappunit(CommonBModel):
remarks = models.TextField('检验反馈备注', null=True, blank=True) remarks = models.TextField('检验反馈备注', null=True, blank=True)
path = models.CharField('文件地址', max_length=1000, null=True, blank=True) path = models.CharField('文件地址', max_length=1000, null=True, blank=True)
inspectionstate = models.CharField('实验室检验状态', choices=charge_choices,null=True, blank=True, max_length=50) inspectionstate = models.CharField('实验室检验状态', choices=charge_choices,null=True, blank=True, max_length=50)
assessor = models.ForeignKey(User, related_name='certappunit_assessor', on_delete=models.SET_NULL, null=True, blank=True, verbose_name='评定人')
class Meta: class Meta:
verbose_name = '认证单元' verbose_name = '认证单元'
verbose_name_plural = verbose_name verbose_name_plural = verbose_name

View File

@ -78,7 +78,7 @@ class CertappViewset(PageOrNot, RbacFilterSet, ModelViewSet):
queryset = CertApp.objects.all() queryset = CertApp.objects.all()
serializer_class = CertappSerializer serializer_class = CertappSerializer
ordering = ['-create_time'] ordering = ['-create_time']
filterset_fields = ['state', 'project'] filterset_fields = ['state', 'project', 'certappunit_certapp__teststate']
# filterset_class = CertAppFilter # filterset_class = CertAppFilter
@ -206,12 +206,16 @@ class CertappunitViewset(PageOrNot, ModelViewSet):
单元评定 单元评定
""" """
obj = self.get_object() obj = self.get_object()
if request.data['decision']: if obj.teststate == '待评定':
obj.decision = Dict.objects.get(pk=request.data['decision']) if request.data['decision']:
obj.decision = Dict.objects.get(pk=request.data['decision'])
else:
obj.decision = None
obj.teststate = '已评定'
obj.save()
return Response(status=status.HTTP_200_OK)
else: else:
obj.decision = None return Response('项目状态异常,操作失败', status=status.HTTP_400_BAD_REQUEST)
obj.save()
return Response(status=status.HTTP_200_OK)
@action(methods=['put'], detail=True, perms_map={'put':'certapp_testtask'}, url_name='certappunit_testtask') @action(methods=['put'], detail=True, perms_map={'put':'certapp_testtask'}, url_name='certappunit_testtask')
def testtask(self, request, pk=None): def testtask(self, request, pk=None):
""" """