diff --git a/client/src/api/certapp.js b/client/src/api/certapp.js
index 06bca08..d62c7e9 100644
--- a/client/src/api/certapp.js
+++ b/client/src/api/certapp.js
@@ -61,4 +61,19 @@ export function accessCertapp(id, data) {
method: 'put',
data
})
+}
+
+export function feedbackCertapp(id, data) {
+ return request({
+ url: `/project/certapp/${id}/feedback/`,
+ method: 'put',
+ data
+ })
+}
+
+export function flowCertapp(id) {
+ return request({
+ url: `/project/certapp/${id}/flow/`,
+ method: 'get',
+ })
}
\ No newline at end of file
diff --git a/client/src/api/project.js b/client/src/api/project.js
index 2b781d4..c4ff8ec 100644
--- a/client/src/api/project.js
+++ b/client/src/api/project.js
@@ -67,4 +67,20 @@ export function acceptAudit(id) {
url: `/project/project/${id}/accept/`,
method: 'put',
})
+}
+
+export function startProject(id, data) {
+ return request({
+ url: `/project/project/${id}/start/`,
+ method: 'put',
+ data
+ })
+}
+
+export function feedbackProject(id, data) {
+ return request({
+ url: `/project/project/${id}/feedback/`,
+ method: 'put',
+ data
+ })
}
\ No newline at end of file
diff --git a/client/src/router/index.js b/client/src/router/index.js
index 94c841e..8367d97 100644
--- a/client/src/router/index.js
+++ b/client/src/router/index.js
@@ -184,10 +184,17 @@ export const asyncRoutes = [
hidden: true
},
{
- path: 'certapp/:id/:action/',
+ path: 'certapp/:id/feedback/',
name: 'Certappfeedback',
component: () => import('@/views/certapp/certapphandle'),
- meta: { title: '业务审核反馈', icon: 'example', perms: ['certapp_feedback'] },
+ meta: { title: '审核反馈', icon: 'example', perms: ['certapp_feedback'] },
+ hidden: true
+ },
+ {
+ path: 'certapp/:id/test/',
+ name: 'Certapptest',
+ component: () => import('@/views/certapp/certapphandle'),
+ meta: { title: '检测任务', icon: 'example', perms: ['certapp_test'] },
hidden: true
},
]
@@ -232,7 +239,6 @@ export const asyncRoutes = [
meta: { title: '任务反馈', noCache: true, icon: '', perms: ['feedbacks_create']},
hidden: true
},
-
]
},
{
diff --git a/client/src/styles/index.scss b/client/src/styles/index.scss
index 687eb0a..bacfa40 100644
--- a/client/src/styles/index.scss
+++ b/client/src/styles/index.scss
@@ -103,4 +103,8 @@ div:focus {
// }
.el-tabs__header {
margin: 0 0 6px;
+}
+
+ul {
+ padding-inline-start: 6px;
}
\ No newline at end of file
diff --git a/client/src/views/accessment/access.vue b/client/src/views/accessment/access.vue
index 7e97828..97b5a53 100644
--- a/client/src/views/accessment/access.vue
+++ b/client/src/views/accessment/access.vue
@@ -49,7 +49,7 @@
- 保存
+ 保存
@@ -71,9 +71,15 @@
{{ scope.row.certunit_.name }}
-
-
- {{ scope.row.certificate_.number }}
+
+
+ {{ scope.row.teststate }}
+
+
+
+
+ {{ scope.row.certificate_.number }}
+ 暂无
@@ -218,6 +224,9 @@ getDictList({type__code:'cert_decision', pageoff:true}).then(res=>{
handleAcessunit(val,id){
accessCertappunit(id, {'decision':val}).then(res=>{
this.$message.success('成功')
+ this.formData.state = res.data.state
+ this.$emit("stateChange", res.data.state);
+ this.$emit("flowChange");
})
}
diff --git a/client/src/views/audit/conclusion.vue b/client/src/views/audit/conclusion.vue
index 41aaa70..1c6c308 100644
--- a/client/src/views/audit/conclusion.vue
+++ b/client/src/views/audit/conclusion.vue
@@ -1,8 +1,10 @@
+ 提交反馈
diff --git a/client/src/views/audit/member.vue b/client/src/views/audit/member.vue
index 7d493a1..0a669c4 100644
--- a/client/src/views/audit/member.vue
+++ b/client/src/views/audit/member.vue
@@ -99,7 +99,7 @@
-
+
审核员参与天数/人日数
diff --git a/client/src/views/audit/task.vue b/client/src/views/audit/task.vue
index 8201bf2..6c62067 100644
--- a/client/src/views/audit/task.vue
+++ b/client/src/views/audit/task.vue
@@ -1,6 +1,6 @@
-
+
-
-
+
+
@@ -23,20 +23,20 @@
/>
- 搜索
- 重置
+ 搜索
+ 重置
- 接受任务
- 详情
+ 安排时间
+ 开始审核
+ 接受任务
+ 反馈
+ 详情
@@ -205,20 +224,29 @@
- 反馈
- 详情
+ 反馈
+ 安排检测
+ 详情
@@ -239,7 +267,7 @@ export default {
components: { Pagination, Treeselect },
data() {
return {
- projectstate:'',
+ projectstate: "",
listLoading: false,
listLoading2: false,
listQuery: {
@@ -281,9 +309,27 @@ export default {
params: { id: scope.row.id },
});
},
+ handleEdate(scope) {
+ this.$router.push({
+ name: "AuditProject",
+ params: { id: scope.row.id },
+ });
+ },
+ handleFeedbackp(scope){
+ this.$router.push({
+ name: "AuditProject",
+ params: { id: scope.row.id },
+ });
+ },
+ handleStart(scope) {
+ this.$router.push({
+ name: "AuditProject",
+ params: { id: scope.row.id },
+ });
+ },
handleRclick(row, column, event) {
this.listLoading2 = true;
- this.projectstate = row.state
+ this.projectstate = row.state;
getAuditCertappList({ project: row.id, pageoff: true })
.then((res) => {
this.certappData = res.data;
@@ -294,17 +340,26 @@ export default {
});
},
handleAccept(scope) {
- acceptAudit(scope.row.id).then(res=>{
- this.getProjectList_()
- this.$message.success('成功')
- }).catch(e=>{})
- },
- handleCertappFeedback(scope) {
- this.$router.push({
- name: "Certappfeedback",
- params: { id: scope.row.id },
+ this.$confirm("确认接受该项目吗?", "", {
+ confirmButtonText: "确认",
+ cancelButtonText: "取消",
+ type: "warning",
+ }).then(() => {
+ acceptAudit(scope.row.id)
+ .then((res) => {
+ this.getProjectList_();
+ this.$message.success("成功");
+ })
+ .catch((e) => {});
});
},
+
+ handleCertappFeedback(scope) {
+ this.$router.push({name:"Certappfeedback", params:{action:'feedback', id:scope.row.id}})
+ },
+ handleCertappTest(scope) {
+ this.$router.push({name:"Certapptest", params:{action:'test', id:scope.row.id}})
+ },
handleCertappDetail(scope) {
this.$router.push({
name: "Certappdetail",
@@ -316,7 +371,7 @@ export default {
name: "AuditProject",
params: { id: scope.row.id },
});
- }
+ },
},
};
diff --git a/client/src/views/certapp/cccform.vue b/client/src/views/certapp/cccform.vue
index a70d023..2a9d31b 100644
--- a/client/src/views/certapp/cccform.vue
+++ b/client/src/views/certapp/cccform.vue
@@ -243,8 +243,8 @@
- 返回列表
- 保存
+ 返回
+ 保存
-
删除
-
@@ -190,10 +188,17 @@ export default {
this.$router.push({name:"Certappupdate", params:{ id:scope.row.id}})
},
handleDelete(scope) {
- deleteCertapp(scope.row.id).then(res=>{
+ this.$confirm('确认删除?', '警告', {
+ confirmButtonText: '确认',
+ cancelButtonText: '取消',
+ type: 'error'
+ }).then(()=>{
+deleteCertapp(scope.row.id).then(res=>{
this.$message.success('成功')
this.getList()
})
+ }).catch(e=>{})
+
},
getfields(){
getDictList({type__code:'cert_field'}).then(res=>{
diff --git a/client/src/views/certapp/certapphandle.vue b/client/src/views/certapp/certapphandle.vue
index 4f7aa90..26ed05c 100644
--- a/client/src/views/certapp/certapphandle.vue
+++ b/client/src/views/certapp/certapphandle.vue
@@ -35,14 +35,14 @@
-
-
+
+
-
+
-
+
@@ -56,10 +56,12 @@
- {{activity.content}}
+ :timestamp="item.create_time"
+ placement="top">
+ {{item.handler_.name}}
+ {{item.operation}}
@@ -73,7 +75,7 @@
import CCCform from "@/views/certapp/cccform"
import Certunit from "@/views/certapp/certunit"
import CHARGE from "@/views/certapp/charge"
-import { getCertapp, completeCertapp } from "@/api/certapp"
+import { getCertapp, completeCertapp, flowCertapp } from "@/api/certapp"
import router from '@/router';
import QMSform from "@/views/certapp/qmsform"
import Conclusion from "@/views/audit/conclusion"
@@ -90,24 +92,16 @@ export default {
props: [],
data() {
return {
- states:['申请', '受理', '策划', '现场审核', '产品检测', '评定', '出证', '归档'],
+ states:['申请', '受理', '策划', '现场审核', '产品检测', '评定', '出证', '完成'],
stateIndex:1,
activeName:'Basic',
certapp:null,
certappdata:null,
kind:'CCC',
isLoad:false,
- activities: [{
- content: '活动按期开始',
- timestamp: '2018-04-15'
- }, {
- content: '通过审核',
- timestamp: '2018-04-13'
- }, {
- content: '创建成功',
- timestamp: '2018-04-11'
- }],
+ activities: [ ],
Certunitkey:'',
+ Certappaccesskey:''
};
},
computed: {},
@@ -128,6 +122,7 @@ export default {
},
getParams(){
var id = this.$route.params.id
+ this.getFlow(id)
this.certapp = id
getCertapp(id).then(res=>{
this.certappdata = res.data
@@ -150,6 +145,17 @@ export default {
this.$message.success('成功')
this.$router.go(-1)
})
+ },
+ stateChange(val){
+ this.stateIndex = this.states.indexOf(val)
+ },
+ getFlow(val){
+ flowCertapp(val).then(res=>{
+ this.activities = res.data
+ })
+ },
+ flowChange(){
+ this.getFlow(this.certapp)
}
}
};
diff --git a/client/src/views/certapp/certunit.vue b/client/src/views/certapp/certunit.vue
index e003d6f..2d96d07 100644
--- a/client/src/views/certapp/certunit.vue
+++ b/client/src/views/certapp/certunit.vue
@@ -26,7 +26,7 @@
{{ scope.row.create_time }}
-
+
-
+
创建新记录
保存
diff --git a/client/src/views/certapp/detectiontask.vue b/client/src/views/certapp/detectiontask.vue
index b468caa..c4b7972 100644
--- a/client/src/views/certapp/detectiontask.vue
+++ b/client/src/views/certapp/detectiontask.vue
@@ -29,7 +29,7 @@
{{ scope.row.charge }}
- {{ scope.row.testorg_.name}}
+ {{ scope.row.testorg_.name}}
{{ scope.row.testitem}}
@@ -39,22 +39,14 @@
{{ scope.row.create_time }}
-
+
-
- 删除
下达实验室
-
diff --git a/client/src/views/certapp/review.vue b/client/src/views/certapp/review.vue
index 50a1951..19cca09 100644
--- a/client/src/views/certapp/review.vue
+++ b/client/src/views/certapp/review.vue
@@ -38,7 +38,7 @@
-
+
保存
diff --git a/client/src/views/project/handle.vue b/client/src/views/project/handle.vue
index db9f3f7..0198cdb 100644
--- a/client/src/views/project/handle.vue
+++ b/client/src/views/project/handle.vue
@@ -6,7 +6,7 @@
项目信息
-
+
项目号
@@ -31,27 +31,29 @@
任务下达人
{{project.assign_by_.name}}
-
+
预计审核时间
- {{edate_[0].substring(0,16)}}-{{edate_[1].substring(0,16)}}
+ {{edate_[0].substring(0,16)}} -{{edate_[1].substring(0,16)}}
-
+
+ 实际审核时间
+ {{project.start_date.substring(0,16)}}
+ -{{project.end_date.substring(0,16)}}
+
+
可派差
-
+
-
-
-
+
-
-
- 保存
-
-
+
+ 保存
+
+
+
+
+
+
+
+ 开始审核
+
@@ -98,6 +117,16 @@
+
+
+ 项目进度
+
+
+
+
+
@@ -164,14 +193,20 @@
v-if="$route.name == 'AuditProject'"
type="primary"
size="small"
- :disabled="!checkPermission(['certapp_detail']) || project.state != '现场审核中'"
+ :disabled="!checkPermission(['certapp_detail'])"
@click="handleFeedback(scope)"
>反馈
+ 安排检测
派人
- 审核组成员
+ 项目成员
审核总反馈
-
+
-
+
-
+
@@ -415,7 +451,7 @@
- 提交反馈
+ 提交反馈
@@ -453,7 +489,7 @@
import { getDictList } from "@/api/dict";
import { getCertappList } from "@/api/certapp";
import { getEnterprise } from "@/api/enterprise";
-import { getProject, updateProject, edateProject } from "@/api/project";
+import { getProject, updateProject, edateProject, startProject, feedbackProject } from "@/api/project";
import { getContactRecordList, createContactRecord } from "@/api/plan";
import Pagination from "@/components/Pagination";
import checkPermission from "@/utils/permission";
@@ -470,6 +506,8 @@ export default {
props: [],
data() {
return {
+ states:['创建中', '待策划', '策划中', '审核任务已下达', '审核任务已接受', '待现场审核', '现场审核中', '任务已反馈', '检测评定出证', '完成'],
+ stateIndex:1,
auditee: {},
project: { assign_by_: null },
certappData: [],
@@ -522,14 +560,26 @@ export default {
identityOptions: [],
edate:[],
edate_:[],
+ start_date:null,
rdate:[],
backformData:{
-
+ backdate:null,
+ feedback_remark:''
+ },
+ backrules:{
+ backdate: [
+ {
+ required: true,
+ message: "请选择日期",
+ trigger: "change",
+ },
+ ],
}
};
},
computed: {},
- watch: {},
+ watch: {
+ },
created() {
this.getParams();
this.getMemberList_();
@@ -549,6 +599,10 @@ export default {
this.edate = [this.project.edate0, this.project.edate1]
this.edate_ = [this.project.edate0, this.project.edate1]
}
+ if(this.project.end_date){
+ this.backformData.backdate = [this.project.start_date, this.project.end_date]
+ this.backformData.feedback_remark = this.project.feedback_remark
+ }
})
.then(() => {
getEnterprise(this.project.auditee).then((res) => {
@@ -673,23 +727,50 @@ export default {
handleMClick(row, c, e) {
this.formDataMember = deepClone(row);
},
- eDate(){
+ handleEdate(){
if(this.edate.length){
edateProject(this.project.id, {edate0:this.edate[0], edate1:this.edate[1]}).then(res=>{
this.$message.success('成功')
this.edate_ = this.edate
+ this.project.state = res.data.state
+ this.project.edate0 = res.data.edate0
+ this.project.edate1 = res.data.edate1
}).catch(e=>{})
}
},
+ handleStart(scope){
+ startProject(this.project.id, {start_date:this.start_date}).then(res=>{
+ this.$message.success('成功')
+ this.project.state = res.data.state
+ this.project.start_date = res.data.start_date
+ }).catch(e=>{})
+ },
+ handlePback(){
+ this.$refs['backform'].validate(valid => {
+ if (valid) {
+ feedbackProject(this.project.id, {start_date:this.backformData.backdate[0], end_date:this.backformData.backdate[1], feedback_remark:this.backformData.feedback_remark}).then(res=>{
+ this.$message.success('成功')
+ this.project.state = res.data.state
+ this.project.start_date = res.data.start_date
+ this.project.end_date = res.data.end_date
+ }).catch(e=>{})}
+ else{
+ return false
+ }})
+ },
handleFeedback(scope){
this.$router.push({name:"Certappfeedback", params:{action:'feedback', id:scope.row.id}})
},
+ handleCertappTest(scope) {
+ this.$router.push({name:"Certapptest", params:{action:'test', id:scope.row.id}})
+ },
handlePlan(scope){
this.$router.push({name:"Certappmember", params:{action:'member', id:scope.row.id}})
},
handleDetail(scope){
this.$router.push({name:"Certappdetail", params:{id:scope.row.id}})
- }
+ },
+
},
};
\ No newline at end of file
diff --git a/server/apps/accessment/serializers.py b/server/apps/accessment/serializers.py
index d26d7f6..b063fc3 100644
--- a/server/apps/accessment/serializers.py
+++ b/server/apps/accessment/serializers.py
@@ -1,26 +1,61 @@
-# from apps.system.models import Dict
-# from rest_framework import serializers
+from utils import serializer
+from rest_framework import serializers
-# from .models import Certaccess, Unitaccess
+from .models import *
-# from apps.system.serializers import DictSerializer
-
-# class CertaccessSerializer(serializers.ModelSerializer):
-# conclusion_ = DictSerializer(source='conclusion', read_only=True)
-# nonitems_ = DictSerializer(source='nonitems', read_only=True, many=True)
-
-# class Meta:
-# model = Certaccess
-# fields = '__all__'
+from apps.system.serializers import DictSimpleSerializer, UserListSerializer, 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__'
-# @staticmethod
-# def setup_eager_loading(queryset):
-# """ Perform necessary eager loading of data. """
-# queryset = queryset.select_related('conclusion',)
-# queryset = queryset.prefetch_related('nonitems',)
-# return queryset
+ 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
+
-# class UnitaccessSerializer(serializers.ModelSerializer):
-# class Meta:
-# model = Unitaccess
-# fields = '__all__'
\ No newline at end of file
+ @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):
+ cert_field_ = DictSimpleSerializer(source='cert_field', read_only=True)
+ cccpv_class_ = DictSimpleSerializer(source='cccpv_class' , read_only=True)
+ cnas_scopes_ = DictSimpleSerializer(source='cnas_scopes', many=True , read_only=True)
+ create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
+ accept_by_ = UserSimpleSerializer(source='accept_by', read_only=True)
+ members = serializers.SerializerMethodField()
+ class Meta:
+ model = CertApp
+ fields = '__all__'
+
+ @staticmethod
+ def setup_eager_loading(queryset):
+ """ Perform necessary eager loading of data. """
+ queryset = queryset.select_related('cert_field', 'cccpv_class', 'create_by', 'accept_by')
+ queryset = queryset.prefetch_related('cnas_scopes', 'member_certapp')
+ 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
\ No newline at end of file
diff --git a/server/apps/accessment/views.py b/server/apps/accessment/views.py
index 4f8b27b..4eabbb0 100644
--- a/server/apps/accessment/views.py
+++ b/server/apps/accessment/views.py
@@ -1,30 +1,17 @@
-# import random
+from rest_framework.viewsets import GenericViewSet
+from utils.pagination import PageOrNot
+from rest_framework.mixins import ListModelMixin
+from .models import *
+from .serializers import *
-# from django.shortcuts import render
-# from django.utils import timezone
-# from rest_framework import status
-# from rest_framework.decorators import action
-# from rest_framework.exceptions import NotAuthenticated, ParseError
-# from rest_framework.response import Response
-# from rest_framework.serializers import ModelSerializer
-# from rest_framework.views import APIView
-# from rest_framework.viewsets import GenericViewSet, ModelViewSet
-
-# from apps.system.mixins import CreateUpdateCustomMixin, OptimizationMixin
-# from apps.system.models import Dict
-# from apps.system.permission_data import RbacFilterSet
-# from utils.pagination import PageOrNot
-
-# from .models import *
-# from .serializers import *
-
-# # Create your views here.
-# class CertaccessViewSet(PageOrNot, CreateUpdateCustomMixin, ModelViewSet):
-# """
-# 业务评定
-# """
-# perms_map = {'get': 'certapp_view', 'post':'certaccess_create', 'put':'certaccess_update','delete': 'certaccess_delete'}
-# queryset = Certaccess.objects.all()
-# serializer_class = CertaccessSerializer
-# filterset_fields = ['certapp']
-# ordering = ['-create_time']
\ No newline at end of file
+from apps.project.models import *
+# Create your views here.
+class CertaccessViewSet(PageOrNot, ListModelMixin, GenericViewSet):
+ """
+ 业务评定
+ """
+ perms_map = {'get': 'access_view'}
+ queryset = CertApp.objects.all()
+ serializer_class = CertappSerializerX
+ filterset_fields = []
+ ordering = ['-create_time']
\ No newline at end of file
diff --git a/server/apps/audit/serializers.py b/server/apps/audit/serializers.py
index d82c2fa..b063fc3 100644
--- a/server/apps/audit/serializers.py
+++ b/server/apps/audit/serializers.py
@@ -3,13 +3,13 @@ from rest_framework import serializers
from .models import *
-from apps.system.serializers import DictSimpleSerializer, UserListSerializer
+from apps.system.serializers import DictSimpleSerializer, UserListSerializer, 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_ = UserListSerializer(source='create_by', read_only=True)
+ create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
certapps = serializers.SerializerMethodField()
plan_ = PlanSerializer(source='plan', read_only=True)
members = serializers.SerializerMethodField()
@@ -41,8 +41,8 @@ class CertappSerializerX(serializers.ModelSerializer):
cert_field_ = DictSimpleSerializer(source='cert_field', read_only=True)
cccpv_class_ = DictSimpleSerializer(source='cccpv_class' , read_only=True)
cnas_scopes_ = DictSimpleSerializer(source='cnas_scopes', many=True , read_only=True)
- create_by_ = UserListSerializer(source='create_by', read_only=True)
- accept_by_ = UserListSerializer(source='accept_by', read_only=True)
+ create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
+ accept_by_ = UserSimpleSerializer(source='accept_by', read_only=True)
members = serializers.SerializerMethodField()
class Meta:
model = CertApp
diff --git a/server/apps/crm/migrations/0016_remove_certunit_testorgs.py b/server/apps/crm/migrations/0016_remove_certunit_testorgs.py
new file mode 100644
index 0000000..08f0f8d
--- /dev/null
+++ b/server/apps/crm/migrations/0016_remove_certunit_testorgs.py
@@ -0,0 +1,17 @@
+# Generated by Django 3.0.7 on 2020-10-21 05:45
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('crm', '0015_certunit_testorgs'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='certunit',
+ name='testorgs',
+ ),
+ ]
diff --git a/server/apps/crm/models.py b/server/apps/crm/models.py
index cd9c0e0..e5b70a3 100644
--- a/server/apps/crm/models.py
+++ b/server/apps/crm/models.py
@@ -91,4 +91,4 @@ class Certunit(CommonAModel):
unittype = models.ForeignKey(UnitType, verbose_name='单元类型', on_delete = models.DO_NOTHING, related_name='certunit_unittype')
standard = models.ForeignKey(Standard, verbose_name='采用标准', on_delete = models.DO_NOTHING, related_name='certunit_standard')
enterprise = models.ForeignKey(Enterprise, verbose_name='所属公司', on_delete = models.DO_NOTHING, related_name='certunit_enterprise')
- testorgs = models.ManyToManyField(TestOrg, verbose_name='检测机构')
+ # testorgs = models.ManyToManyField(TestOrg, verbose_name='检测机构')
diff --git a/server/apps/project/migrations/0050_merge_20201020_1402.py b/server/apps/project/migrations/0050_merge_20201020_1402.py
new file mode 100644
index 0000000..c08ebb9
--- /dev/null
+++ b/server/apps/project/migrations/0050_merge_20201020_1402.py
@@ -0,0 +1,14 @@
+# Generated by Django 3.0.7 on 2020-10-20 06:02
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('project', '0044_auto_20201014_1412'),
+ ('project', '0049_certappunit_inspectionstate'),
+ ]
+
+ operations = [
+ ]
diff --git a/server/apps/project/migrations/0051_auto_20201020_1402.py b/server/apps/project/migrations/0051_auto_20201020_1402.py
new file mode 100644
index 0000000..bcd0aa1
--- /dev/null
+++ b/server/apps/project/migrations/0051_auto_20201020_1402.py
@@ -0,0 +1,28 @@
+# Generated by Django 3.0.7 on 2020-10-20 06:02
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('project', '0050_merge_20201020_1402'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='project',
+ name='start_date',
+ field=models.DateTimeField(blank=True, null=True, verbose_name='现场审核开始时间'),
+ ),
+ migrations.AlterField(
+ model_name='certapp',
+ name='state',
+ field=models.CharField(choices=[('申请', '申请'), ('受理', '受理'), ('策划', '策划'), ('现场审核', '现场审核'), ('产品检测', '产品检测'), ('评定', '评定'), ('出证', '出证'), ('完成', '完成')], default='申请', max_length=50, verbose_name='申请状态'),
+ ),
+ migrations.AlterField(
+ model_name='project',
+ name='state',
+ field=models.CharField(choices=[('创建中', '创建中'), ('待策划', '待策划'), ('策划中', '策划中'), ('审核任务已下达', '审核任务已下达'), ('审核任务已接受', '审核任务已接受'), ('待现场审核', '待现场审核'), ('现场审核中', '现场审核中'), ('任务已反馈', '任务已反馈'), ('检测评定', '检测评定'), ('完成', '完成')], default='创建中', max_length=50, verbose_name='项目状态'),
+ ),
+ ]
diff --git a/server/apps/project/migrations/0052_auto_20201020_1500.py b/server/apps/project/migrations/0052_auto_20201020_1500.py
new file mode 100644
index 0000000..91e79d4
--- /dev/null
+++ b/server/apps/project/migrations/0052_auto_20201020_1500.py
@@ -0,0 +1,23 @@
+# Generated by Django 3.0.7 on 2020-10-20 07:00
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('project', '0051_auto_20201020_1402'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='project',
+ name='end_date',
+ field=models.DateTimeField(blank=True, null=True, verbose_name='实际现场审核结束时间'),
+ ),
+ migrations.AlterField(
+ model_name='project',
+ name='start_date',
+ field=models.DateTimeField(blank=True, null=True, verbose_name='实际现场审核开始时间'),
+ ),
+ ]
diff --git a/server/apps/project/migrations/0053_project_feedback_remark.py b/server/apps/project/migrations/0053_project_feedback_remark.py
new file mode 100644
index 0000000..acec825
--- /dev/null
+++ b/server/apps/project/migrations/0053_project_feedback_remark.py
@@ -0,0 +1,18 @@
+# Generated by Django 3.0.7 on 2020-10-20 08:30
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('project', '0052_auto_20201020_1500'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='project',
+ name='feedback_remark',
+ field=models.TextField(blank=True, null=True, verbose_name='反馈备注'),
+ ),
+ ]
diff --git a/server/apps/project/models.py b/server/apps/project/models.py
index c6a2cf6..dacaf16 100644
--- a/server/apps/project/models.py
+++ b/server/apps/project/models.py
@@ -94,7 +94,8 @@ class Project(CommonBModel):
('待现场审核', '待现场审核'),
('现场审核中', '现场审核中'),
('任务已反馈', '任务已反馈'),
- ('归档', '归档')
+ ('检测评定', '检测评定'),
+ ('完成', '完成')
)
state = models.CharField('项目状态', choices=state_choices, default='创建中', max_length=50)
number = models.CharField('项目编号', max_length = 100, null=True, blank=True)
@@ -107,6 +108,9 @@ class Project(CommonBModel):
assgin_by = models.ForeignKey(User, on_delete=models.SET_NULL, verbose_name='审核任务下达人', null=True, blank=True)
edate0 = models.DateTimeField('预计审核开始时间', null=True, blank=True)
edate1 = models.DateTimeField('预计审核结束时间', null=True, blank=True)
+ start_date = models.DateTimeField('实际现场审核开始时间', null=True, blank=True)
+ end_date = models.DateTimeField('实际现场审核结束时间', null=True, blank=True)
+ feedback_remark = models.TextField('反馈备注', null=True, blank=True)
class Meta:
@@ -129,7 +133,7 @@ class CertApp(CommonBModel):
('产品检测', '产品检测'),
('评定', '评定'),
('出证', '出证'),
- ('归档', '归档'),
+ ('完成', '完成'),
)
result_choices = (
('未评审', '未评审'),
diff --git a/server/apps/project/serializers.py b/server/apps/project/serializers.py
index 73c28d3..347686a 100644
--- a/server/apps/project/serializers.py
+++ b/server/apps/project/serializers.py
@@ -39,6 +39,12 @@ from apps.laboratory.serializers import TestOrgSerializer
# class Meta:
# model = SubApplication
# fields = '__all__'
+class CertappflowSerializer(serializers.ModelSerializer):
+ handler_ = UserSimpleSerializer(source='handler', read_only=True)
+ class Meta:
+ model = CertAppFlow
+ fields = ['handler_', 'create_time', 'operation', 'state']
+
class CertappSerializer(serializers.ModelSerializer):
cert_field_ = DictSerializer(source='cert_field', read_only=True)
diff --git a/server/apps/project/views.py b/server/apps/project/views.py
index 15ae568..53d977c 100644
--- a/server/apps/project/views.py
+++ b/server/apps/project/views.py
@@ -19,7 +19,7 @@ from .filters import *
from utils.pagination import PageOrNot
from rest_framework.exceptions import ParseError, NotAuthenticated
from django.utils import timezone
-
+from rest_framework.mixins import ListModelMixin
# Create your views here.
# class ApplicationViewSet(RbacFilterSet, ModelViewSet):
# """
@@ -90,8 +90,8 @@ class CertappViewset(PageOrNot, RbacFilterSet, ModelViewSet):
serializer = self.get_serializer(data=postdata)
serializer.is_valid(raise_exception=True)
# self.perform_create(serializer)
- instance = serializer.save(create_by = self.request.user, belong_dept=self.request.user.dept, state='受理')
- CertAppFlow.objects.create(certapp = instance, handler=self.request.user, data=serializer.data, operation='创建申请', state='申请')
+ obj = serializer.save(create_by = self.request.user, belong_dept=self.request.user.dept, state='受理')
+ CertAppFlow.objects.create(certapp = obj, handler=self.request.user, data=serializer.data, operation='创建申请', state='申请')
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
@@ -104,7 +104,7 @@ class CertappViewset(PageOrNot, RbacFilterSet, ModelViewSet):
obj = self.get_object()
obj.state = '策划'
obj.save()
- CertAppFlow.objects.create(certapp = obj, handler=self.request.user, data=self.get_serializer(obj), operation='完成受理', state='受理')
+ CertAppFlow.objects.create(certapp = obj, handler=self.request.user, operation='完成受理', state='受理')
return Response(status=status.HTTP_200_OK)
@action(methods=['put'], detail=False, perms_map={'put':'certapp_review'},
@@ -116,8 +116,8 @@ class CertappViewset(PageOrNot, RbacFilterSet, ModelViewSet):
certapps = request.data['certapps']
rlist = request.data['rlist']
for i in rlist:
- instance = EvaluationDetail.objects.create(item=Evaluations.objects.get(id=i['id']),item_v=i['content'], create_by=request.user, result=i['result'] if 'result' in i and i['result'] else None)
- instance.cert_app.add(*certapps)
+ obj = EvaluationDetail.objects.create(item=Evaluations.objects.get(id=i['id']),item_v=i['content'], create_by=request.user, result=i['result'] if 'result' in i and i['result'] else None)
+ obj.cert_app.add(*certapps)
return Response(status=status.HTTP_200_OK)
@action(methods=['put'], detail=True, perms_map={'put':'certapp_access'}, url_name='certapp_access')
@@ -125,18 +125,50 @@ class CertappViewset(PageOrNot, RbacFilterSet, ModelViewSet):
"""
评定
"""
- # instance, ok = Certaccess.objects.get_or_create(certapp=self.get_object(), defaults={'certapp':self.get_object()
+ # obj, ok = Certaccess.objects.get_or_create(certapp=self.get_object(), defaults={'certapp':self.get_object()
# , 'conclusion':Dict.objects.get(pk=request.data['conclusion']), 'score':request.data['score']})
# if not ok:
- instance = self.get_object()
- instance.conclusion = Dict.objects.get(pk=request.data['conclusion'])
- instance.score = request.data['score']
- instance.state = '出证'
- instance.save()
- instance.nonitems.clear()
- instance.nonitems.add(*request.data['nonitems'])
- return Response(status=status.HTTP_200_OK)
+ obj = self.get_object()
+ oldstate = obj.state
+ obj.conclusion = Dict.objects.get(pk=request.data['conclusion'])
+ obj.score = request.data['score']
+ obj.state = '出证'
+ obj.save()
+ obj.nonitems.clear()
+ obj.nonitems.add(*request.data['nonitems'])
+ CertAppFlow.objects.create(certapp = obj, handler=self.request.user, operation='提交评定结论', state=oldstate)
+ return Response({'state':obj.state}, status=status.HTTP_200_OK)
+ @action(methods=['put'], detail=True, perms_map={'put':'certapp_feedback'},
+ url_name='certapp_feedback')
+ def feedback(self, request, *args, **kwargs):
+ """
+ 业务反馈
+ """
+ obj = self.get_object()
+ if obj.state in ['现场审核', '产品检测']:
+ oldstate = obj.state
+ if obj.cert_field.parent.code == 'PRO':
+ obj.state = '产品检测'
+ else:
+ obj.state = '评定'
+ obj.save()
+ CertAppFlow.objects.create(certapp = obj, handler=self.request.user, operation='提交现场审核反馈', state=oldstate)
+ return Response({'state':obj.state}, status=status.HTTP_200_OK)
+ else:
+ return Response('项目状态异常,操作失败', status=status.HTTP_400_BAD_REQUEST)
+
+ @action(methods=['get'], detail=True, perms_map={'get':'*'},
+ url_name='certapp_flow')
+ def flow(self, request, *args, **kwargs):
+ """
+ 业务流程进度
+ """
+ objs = CertAppFlow.objects.filter(certapp__pk=kwargs['pk'])
+ serializer = CertappflowSerializer(objs, many=True)
+ return Response(serializer.data)
+
+
class EvaluationDetailViewset(CreateUpdateCustomMixin, PageOrNot,ModelViewSet):
"""
@@ -155,7 +187,7 @@ class EvaluationDetailViewset(CreateUpdateCustomMixin, PageOrNot,ModelViewSet):
rlist = request.data['rlist']
for i in rlist:
- instance = EvaluationDetail.objects.update(item=Evaluations.objects.get(id=i['id']),item_v=i['content'], update_by=request.user, result=i['result'] )
+ obj = EvaluationDetail.objects.update(item=Evaluations.objects.get(id=i['id']),item_v=i['content'], update_by=request.user, result=i['result'] )
return Response(status=status.HTTP_200_OK)
@@ -255,11 +287,11 @@ class ProjectViewSet(RbacFilterSet, ModelViewSet):
postdata['number'] = random.randrange(8000,9000)
serializer = self.get_serializer(data=postdata)
serializer.is_valid(raise_exception=True)
- instance = serializer.save(create_by = self.request.user, belong_dept=self.request.user.dept)
+ obj = serializer.save(create_by = self.request.user, belong_dept=self.request.user.dept)
if 'certapps' in postdata and postdata['certapps']:
- CertApp.objects.filter(pk__in = postdata['certapps']).update(project=instance)
- instance.state = '待策划'
- instance.save()
+ CertApp.objects.filter(pk__in = postdata['certapps']).update(project=obj)
+ obj.state = '待策划'
+ obj.save()
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
@@ -302,10 +334,33 @@ class ProjectViewSet(RbacFilterSet, ModelViewSet):
制定预期审核时间
"""
obj = self.get_object()
- obj.edate0 = request.data['edate0']
- obj.edate1 = request.data['edate1']
- obj.save()
- return Response(status=status.HTTP_200_OK)
+ if obj.state == '审核任务已接受':
+ obj.edate0 = request.data['edate0']
+ obj.edate1 = request.data['edate1']
+ obj.state = '待现场审核'
+ obj.save()
+ for i in obj.certapp_project.all():
+ CertAppFlow.objects.create(certapp = i, handler=self.request.user, operation='已安排现场审核时间', state='现场审核')
+ return Response({'edate0':obj.edate0, 'edate1':obj.edate1, 'state':obj.state}, status=status.HTTP_200_OK)
+ else:
+ return Response('项目状态异常,操作失败', status=status.HTTP_400_BAD_REQUEST)
+
+ @action(methods=['put'], detail=True, perms_map={'put':'project_start'},
+ url_name='project_start')
+ def start(self, request, *args, **kwargs):
+ """
+ 开始审核
+ """
+ obj = self.get_object()
+ if obj.state == '待现场审核':
+ obj.start_date = request.data['start_date']
+ obj.state = '现场审核中'
+ obj.save()
+ for i in obj.certapp_project.all():
+ CertAppFlow.objects.create(certapp = i, handler=self.request.user, operation='现场审核中', state='现场审核')
+ return Response({'start_date':obj.start_date,'state':obj.state}, status=status.HTTP_200_OK)
+ else:
+ return Response('项目状态异常,操作失败', status=status.HTTP_400_BAD_REQUEST)
@action(methods=['put'], detail=True, perms_map={'put':'audit_accept'},url_name='audit_accept')
def accept(self, request, *args, **kwargs):
@@ -317,9 +372,26 @@ class ProjectViewSet(RbacFilterSet, ModelViewSet):
obj.state = '审核任务已接受'
obj.save()
Member.objects.filter(certapp__project=obj).update(is_accepted=True)
- obj.certapp_project.all().update(state='审核')
+ obj.certapp_project.all().update(state='现场审核')
for i in obj.certapp_project.all():
CertAppFlow.objects.create(certapp = i, handler=self.request.user, operation='审核任务已接受', state='策划')
return Response(status=status.HTTP_200_OK)
return Response('项目状态异常,操作失败', status=status.HTTP_400_BAD_REQUEST)
+
+ @action(methods=['put'], detail=True, perms_map={'put':'project_feedback'},
+ url_name='project_feedback')
+ def feedback(self, request, *args, **kwargs):
+ """
+ 项目反馈
+ """
+ obj = self.get_object()
+ if obj.state == '现场审核中':
+ obj.start_date = request.data['start_date']
+ obj.end_date = request.data['end_date']
+ obj.feedback_remark = request.data['feedback_remark']
+ obj.state = '任务已反馈'
+ obj.save()
+ return Response({'start_date':obj.start_date, 'end_date':obj.end_date,'state':obj.state}, status=status.HTTP_200_OK)
+ else:
+ return Response('项目状态异常,操作失败', status=status.HTTP_400_BAD_REQUEST)
\ No newline at end of file
diff --git a/server/apps/system/migrations/0032_auto_20201022_1504.py b/server/apps/system/migrations/0032_auto_20201022_1504.py
new file mode 100644
index 0000000..d3faa95
--- /dev/null
+++ b/server/apps/system/migrations/0032_auto_20201022_1504.py
@@ -0,0 +1,23 @@
+# Generated by Django 3.0.7 on 2020-10-22 07:04
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('system', '0031_delete_bscodeset'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='dict',
+ name='code',
+ field=models.CharField(db_index=True, max_length=30, unique=True, verbose_name='编号'),
+ ),
+ migrations.AlterField(
+ model_name='dicttype',
+ name='code',
+ field=models.CharField(db_index=True, max_length=30, unique=True, verbose_name='代号'),
+ ),
+ ]
diff --git a/server/apps/system/models.py b/server/apps/system/models.py
index 6091a81..bdd4177 100644
--- a/server/apps/system/models.py
+++ b/server/apps/system/models.py
@@ -131,7 +131,7 @@ class DictType(SoftModel):
数据字典类型
"""
name = models.CharField('名称', max_length=30)
- code = models.CharField('代号', unique=True, max_length=30)
+ code = models.CharField('代号', unique=True, max_length=30, db_index=True)
parent = models.ForeignKey('self', null=True, blank=True,
on_delete=models.SET_NULL, verbose_name='父')
@@ -148,7 +148,7 @@ class Dict(SoftModel):
数据字典
"""
name = models.CharField('名称', max_length=1000)
- code = models.CharField('编号', max_length=30, unique=True)
+ code = models.CharField('编号', max_length=30, unique=True, db_index=True)
description = models.TextField('描述', blank=True, null=True)
other = JSONField('其它信息', blank=True, null=True)
type = models.ForeignKey(