This commit is contained in:
caoqianming 2020-09-02 11:12:51 +08:00
parent 328ea10969
commit 2a6fe56ed1
42 changed files with 2187 additions and 548 deletions

BIN
client/quota.dat Normal file

Binary file not shown.

View File

@ -6,19 +6,7 @@
<style type="text/css">
.el-table--medium td,   .el-table--medium th {
padding: 2px 0;
}
.el-form-item {
margin-bottom: 16px;
}
.el-card__body {
padding: 10px;
}
.el-card__header {
padding: 10px;
}
</style>
<script>
export default {

View File

@ -8,6 +8,15 @@ export function getEmployeeList(query) {
})
}
export function getEmployeeMList(query) {
//配置审核组用
return request({
url: '/employee/employee/team/',
method: 'get',
params: query
})
}
export function createEmployee(data) {
return request({
url: '/employee/employee/',

33
client/src/api/member.js Normal file
View File

@ -0,0 +1,33 @@
import request from '@/utils/request'
//审核组
export function getMemberList(query) {
return request({
url: '/plan/member/',
method: 'get',
params: query
})
}
export function createMember(data) {
return request({
url: '/plan/member/',
method: 'post',
data
})
}
export function deleteMember(id) {
return request({
url: `/plan/member/${id}/`,
method: 'delete'
})
}
export function updateMember(id, data) {
return request({
url: `/plan/member/${id}/`,
method: 'put',
data
})
}

79
client/src/api/plan.js Normal file
View File

@ -0,0 +1,79 @@
import request from '@/utils/request'
export function getContactRecordList(query) {
return request({
url: '/plan/contactrecord/',
method: 'get',
params: query
})
}
export function createContactRecord(data) {
return request({
url: '/plan/contactrecord/',
method: 'post',
data
})
}
export function deleteContactRecord(id) {
return request({
url: `/plan/contactrecord/${id}/`,
method: 'delete'
})
}
export function updateContactRecord(id, data) {
return request({
url: `/plan/contactrecord/${id}/`,
method: 'put',
data
})
}
export function getContactRecord(id) {
return request({
url: `/plan/contactrecord/${id}/`,
method: 'get',
})
}
export function getPlanList(query) {
return request({
url: '/plan/plan/',
method: 'get',
params: query
})
}
export function createPlan(data) {
return request({
url: '/plan/plan/',
method: 'post',
data
})
}
export function deletePlan(id) {
return request({
url: `/plan/plan/${id}/`,
method: 'delete'
})
}
export function updatePlan(id, data) {
return request({
url: `/plan/plan/${id}/`,
method: 'put',
data
})
}
export function getPlan(id) {
return request({
url: `/plan/plan/${id}/`,
method: 'get',
})
}

View File

@ -45,4 +45,12 @@ export function assginProject(id, data) {
method: 'put',
data
})
}
export function planProject(data) {
return request({
url: '/project/project/plan/',
method: 'put',
data
})
}

View File

@ -117,15 +117,75 @@ export const asyncRoutes = [
children: [
{
path: 'plan',
name: 'plan',
name: 'Plan',
component: () => import('@/views/plan/plan'),
meta: { title: '计划', icon: 'example', perms: ['plan_view'] }
},
{
path: 'paichai',
name: 'paichai',
component: () => import('@/views/project/project'),
meta: { title: '派差', icon: 'example', perms: ['project_view'] }
name: 'Paichai',
component: () => import('@/views/plan/paichai'),
meta: { title: '派差', icon: 'example', perms: ['plan_view'] }
},
{
path: 'project',
name: 'HandleProject',
component: () => import('@/views/plan/handle'),
meta: { title: '联系企业', icon: 'example', perms: ['project_view'] },
hidden: true
},
]
},
{
path: '/spot',
component: Layout,
redirect: '/spot/spot',
name: 'SpotM',
meta: { title: '现场审核', icon: 'example'},
children: [
{
path: 'spot',
name: 'Spot',
component: () => import('@/views/plan/plan'),
meta: { title: '现场审核', icon: 'example', perms: ['plan_view'] }
},
]
},
{
path: '/detectorg',
component: Layout,
redirect: '/detectorg/detectorg',
name: 'detectorg',
meta: { title: '产品检测', icon: 'example' },
children: [
{
path: 'detectorg',
name: 'DetectOrg',
component: () => import('@/views/detectorg/detectorg'),
meta: { title: '实验室信息', icon: 'example', perms: ['detectorg_manage'] }
},
{
path: 'detectorgnotice',
name: 'DetectOrgNotice',
component: () => import('@/views/detectorg/detectorgnotice'),
meta: { title: '实验室通知公告', icon: 'example', perms: ['detectorg_manage'] }
},
]
},
{
path: '/judge',
component: Layout,
redirect: '/judge/judge',
name: 'JudgeM',
meta: { title: '认证评定', icon: 'example'},
children: [
{
path: 'judge',
name: 'Judge',
component: () => import('@/views/plan/plan'),
meta: { title: '认证评定', icon: 'example', perms: ['plan_view'] }
},
]
},
@ -220,29 +280,6 @@ export const asyncRoutes = [
},
]
},
{
path: '/detectorg',
component: Layout,
redirect: '/detectorg/detectorg',
name: 'detectorg',
meta: { title: '实验室管理', icon: 'example' },
children: [
{
path: 'detectorg',
name: 'DetectOrg',
component: () => import('@/views/detectorg/detectorg'),
meta: { title: '实验室信息', icon: 'example', perms: ['detectorg_manage'] }
},
{
path: 'detectorgnotice',
name: 'DetectOrgNotice',
component: () => import('@/views/detectorg/detectorgnotice'),
meta: { title: '实验室通知公告', icon: 'example', perms: ['detectorg_manage'] }
},
]
},
{
path: '/certset',
component: Layout,

View File

@ -61,5 +61,28 @@ div:focus {
// main-container global css
.app-container {
padding: 20px;
padding: 10px;
}
.el-table--medium td,   .el-table--medium th {
padding: 2px 0;
}
.el-form-item {
margin-bottom: 16px;
}
.el-card__body {
padding: 6px;
}
.el-card__header {
padding: 6px;
}
.el-tabs--border-card>.el-tabs__content {
padding: 6px;
}
.el-dialog__header {
padding: 10px 10px 6px;
}
.el-dialog__body {
padding: 8px 12px;
}

View File

@ -0,0 +1,184 @@
<template>
<div>
<el-row :gutter="6">
<el-col :xs="24" :md="4">
<treeselect
v-model="listQuery.user__dept"
:multiple="false"
:options="deptOptions"
placeholder="所属组织"
:disable-branch-nodes="true"
@input="handleFilter"
clearable/>
</el-col>
<el-col :xs="24" :md="2">
<el-select
v-model="listQuery.is_fulltime"
placeholder="是否全职"
clearable
class="filter-item"
@change="handleFilter"
>
<el-option label="" value="true"/>
<el-option label="" value="false"/>
</el-select>
</el-col>
<el-col :xs="24" :md="6">
<el-input
v-model="listQuery.search"
placeholder="姓名/易记码/编号/注册领域/专业能力"
class="filter-item"
@keyup.enter.native="handleFilter"
/>
</el-col>
<el-col :xs="24" :md="4">
<el-button-group>
<el-button
class="filter-item"
type="primary"
icon="el-icon-search"
@click="handleFilter"
>搜索</el-button>
<el-button
class="filter-item"
type="warning"
icon="el-icon-refresh-left"
@click="resetFilter"
>刷新重置</el-button>
</el-button-group>
</el-col>
</el-row>
<el-table
v-loading="listLoading"
:data="tableData.results"
style="width: 100%;margin-top:10px;"
border
fit
stripe
highlight-current-row
max-height="600"
>
<el-table-column type="index" width="50" />
<el-table-column label="编号">
<template slot-scope="scope" v-if="scope.row.code">{{ scope.row.code }}</template>
</el-table-column>
<el-table-column label="账号">
<template slot-scope="scope">{{ scope.row.user_.username }}</template>
</el-table-column>
<el-table-column label="名称">
<template slot-scope="scope">{{ scope.row.user_.name }}</template>
</el-table-column>
<el-table-column label="所属部门">
<template slot-scope="scope">{{ scope.row.user_.dept_name }}</template>
</el-table-column>
<el-table-column label="注册领域">
<template slot-scope="scope" v-if="scope.row.fields">
<el-tag v-for="(item, index) in scope.row.fields.split(',')" :key="index" style="margin:2px" >{{item}}</el-tag>
</template>
</el-table-column>
<el-table-column label="专业能力">
<template slot-scope="scope" v-if="scope.row.majors">
<el-tooltip effect="dark" :content="item.abilitys.join('\n')" placement="top-start" v-for="(item, index) in scope.row.majors" :key="index">
<el-tag style="margin:2px" type="plain">
{{item.major}}
</el-tag>
</el-tooltip>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right">
<template slot-scope="scope">
<el-button-group>
<el-button
type="primary"
size="small"
@click="handleChose(scope)"
>选中</el-button>
<el-button
type="info"
size="small"
@click="handleDelete(scope)"
>详情</el-button>
</el-button-group>
</template>
</el-table-column>
</el-table>
<pagination
v-show="tableData.count>0"
:total="tableData.count"
:page.sync="listQuery.page"
:limit.sync="listQuery.page_size"
@pagination="getList"
/>
</div>
</template>
<script>
import { getEmployeeMList, deleteEmployee } from "@/api/employee"
import { getOrgList } from "@/api/org"
import { getDictList } from "@/api/dict"
import Pagination from "@/components/Pagination"
import checkPermission from '@/utils/permission'
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
import { genTree } from '../../utils'
export default {
name:'Userchose',
components: { Pagination, Treeselect },
props:['querydata'],
data() {
return {
tableData: {count:0},
listLoading: true,
listQuery: {
page: 1,
page_size: 10,
is_onjob:true
},
deptOptions: [],
};
},
created() {
this.getList();
this.getdeptOptions()
},
methods: {
checkPermission,
getList() {
this.listLoading = true;
getEmployeeMList(this.listQuery).then(response => {
if (response.data) {
this.tableData = response.data
}
this.listLoading = false
});
},
getdeptOptions() {
getOrgList().then(res=>{
this.deptOptions = genTree(res.data)
})
},
resetFilter() {
this.listQuery = {
page: 1,
page_size: 10,
is_onjob:true
}
this.getList()
},
handleFilter() {
this.listQuery.page = 1
this.getList()
},
// handleCreate() {
// this.$router.push({path:"/certset/implementrule/create"})
// },
handleChose(scope) {
this.$emit('handleChose',scope.row);
}
}
};
</script>

View File

@ -1,188 +1,182 @@
<template>
<div class="app-container">
<div class="app-container">
<el-row :gutter="20">
<el-col :span="4">
<el-input placeholder="输入关键字进行过滤" v-model="filterText"></el-input>
<el-row :gutter="20">
<el-col :span="4">
<el-input placeholder="输入关键字进行过滤"
v-model="filterText">
</el-input>
<el-tree
class="filter-tree"
:data="orgList"
:props="defaultProps"
default-expand-all
:expand-on-click-node="false"
:filter-node-method="filterNode"
@node-click="handleOrgClick"
ref="tree"
>
<span class="custom-tree-node" slot-scope="{ node, data }">
<span>{{ node.label }}</span>
</span>
</el-tree>
</el-col>
<el-tree class="filter-tree"
:data="orgList"
:props="defaultProps"
default-expand-all
:expand-on-click-node="false"
:filter-node-method="filterNode"
@node-click="handleOrgClick"
ref="tree">
<span class="custom-tree-node" slot-scope="{ node, data }">
<span>{{ node.label }}</span>
</span>
</el-tree>
</el-col>
<el-col :span="13">
<el-table ref="staffTable"
v-loading="listLoading"
:key="tableKey"
:data="staffList"
border
fit
highlight-current-row
@selection-change="handleStaffChange">
<el-table-column type="selection" :reserve-selection="true" width="55"></el-table-column>
<el-table-column label="姓名" align="center">
<template slot-scope="{row}">
<span>{{ row.user.name }}</span>
</template>
</el-table-column>
<el-col :span="13">
<el-table
ref="staffTable"
v-loading="listLoading"
:key="tableKey"
:data="staffList"
border
fit
highlight-current-row
@selection-change="handleStaffChange"
>
<el-table-column type="selection" :reserve-selection="true" width="55"></el-table-column>
<el-table-column label="姓名" align="center">
<template slot-scope="{row}">
<span>{{ row.user.name }}</span>
</template>
</el-table-column>
<el-table-column label="职务" align="center">
<template slot-scope="{row}">
<span>{{ row.user.position }}</span>
</template>
</el-table-column>
<el-table-column label="部门" align="center">
<template slot-scope="{row}">
<span>{{ row.user.dept_name }}</span>
</template>
</el-table-column>
</el-table>
</el-col>
<el-col :span="2" style="text-align:center;margin-top:20px">
<el-button @click="addStaff"
type="primary"
:disabled="!staffData.length"
icon="el-icon-arrow-right"
circle></el-button>
<!--<el-button @click="removeStaff"
<el-table-column label="职务" align="center">
<template slot-scope="{row}">
<span>{{ row.user.position }}</span>
</template>
</el-table-column>
<el-table-column label="部门" align="center">
<template slot-scope="{row}">
<span>{{ row.user.dept_name }}</span>
</template>
</el-table-column>
</el-table>
</el-col>
<el-col :span="2" style="text-align:center;margin-top:20px">
<el-button
@click="addStaff"
type="primary"
:disabled="!staffData.length"
icon="el-icon-arrow-right"
circle
></el-button>
<!--<el-button @click="removeStaff"
type="primary"
:disabled="!selectedStaffData.length"
icon="el-icon-arrow-left"
circle
style="margin-left: 0;margin-top: 10px;"></el-button>-->
</el-col>
<el-col :span="5">
<el-table ref="selectedStaffTable"
v-loading="listLoading"
:data="selectedStaffList"
border
fit
highlight-current-row
>
<el-table-column label="姓名" align="center">
<template slot-scope="{row}">
<span>{{ row.user.name }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<el-button type="danger" icon="el-icon-delete" circle @click.native.prevent="deleteRow(scope.$index, selectedStaffList)"></el-button>
</template>
</el-table-column>
</el-table>
</el-col>
</el-row>
<el-row :gutter="20" >
<el-button type="primary" @click="modifyStaff">提交</el-button>
</el-row>
</div>
</template>
style="margin-left: 0;margin-top: 10px;"></el-button>-->
</el-col>
<el-col :span="5">
<el-table
ref="selectedStaffTable"
v-loading="listLoading"
:data="selectedStaffList"
border
fit
highlight-current-row
>
<el-table-column label="姓名" align="center">
<template slot-scope="{row}">
<span>{{ row.user.name }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<el-button
type="danger"
icon="el-icon-delete"
circle
@click.native.prevent="deleteRow(scope.$index, selectedStaffList)"
></el-button>
</template>
</el-table-column>
</el-table>
</el-col>
</el-row>
<el-row :gutter="20">
<el-button type="primary" @click="modifyStaff">提交</el-button>
</el-row>
</div>
</template>
<script>
import { getEmployeeList, deleteEmployee } from "@/api/employee"
import { genTree } from "@/utils"
import { getOrgAll } from "@/api/org"
import "@riophae/vue-treeselect/dist/vue-treeselect.css"
import { getEmployeeList, deleteEmployee } from "@/api/employee";
import { genTree } from "@/utils";
import { getOrgAll } from "@/api/org";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
export default {
components: {},
name:'Userselet',
components: {},
props: [],
data() {
return {
dialogVisible: false,
listLoading: true,
staffTemp: {
data() {
return {
dialogVisible: false,
listLoading: true,
staffTemp: {
name: "",
email: "",
staffTypeId: ""
staffTypeId: "",
},
filterText: '',
filterText: "",
orgList: [],
staffList: [],
userlist:{count:0},
listQuery: {
staffList: [],
userlist: { count: 0 },
listQuery: {
page: 1,
page_size: 20
page_size: 20,
},
selectedStaffList: [],
staffData: [],
defaultProps: {
"label": "name",
"children": "children"
},
selectedStaffData: [],
tableKey: 0,
rowKey: "rowKey",
}
},
watch: {
filterText(val) {
this.$refs.tree.filter(val);
},
},
created() {
this.getStaffList(),
this.getList()
},
methods: {
selectedStaffList: [],
staffData: [],
defaultProps: {
label: "name",
children: "children",
},
selectedStaffData: [],
tableKey: 0,
rowKey: "rowKey",
};
},
watch: {
filterText(val) {
this.$refs.tree.filter(val);
},
},
created() {
this.getStaffList(), this.getList();
},
methods: {
// 从后台获取左边表格的数据
filterNode(value, data) {
if (!value) return true;
return data.label.indexOf(value) !== -1;
},
if (!value) return true;
return data.label.indexOf(value) !== -1;
},
getList() {
getOrgAll().then(response => {
getOrgAll().then((response) => {
this.orgList = genTree(response.data);
this.listLoading = false
})
this.listLoading = false;
});
},
deleteRow(index, rows) {
rows.splice(index, 1);
}
,
handleOrgClick(obj, node, vue) {
rows.splice(index, 1);
},
handleOrgClick(obj, node, vue) {
this.listQuery.page = 1;
this.listQuery.user__dept = obj.id;
this.getStaffList();
},
getStaffList() {
getEmployeeList(this.listQuery).then(response => {
this.staffList = response.data.results;
getEmployeeList(this.listQuery).then((response) => {
this.staffList = response.data.results;
});
this.listLoading = false;
this.listLoading = false;
},
// 将左边表格选择项存入staffData中
handleStaffChange(rows) {
this.staffData = [];
if (rows) {
rows.forEach(row => {
rows.forEach((row) => {
if (row) {
this.staffData.push(row);
}
@ -196,7 +190,7 @@ methods: {
this.$refs["selectedStaffTable"].clearSelection();
}, 0);
let repeat = false;
this.selectedStaffList.forEach(item => {
this.selectedStaffList.forEach((item) => {
if (this.staffData[0] && item.id === this.staffData[0].id) {
repeat = true;
alert("此员工已添加");
@ -204,7 +198,7 @@ methods: {
}
});
if (repeat === false) {
this.staffData.forEach(item => {
this.staffData.forEach((item) => {
this.selectedStaffList.push(item);
});
for (let i = 0; i < this.staffList.length; i++) {
@ -226,7 +220,7 @@ methods: {
this.$refs["staffTable"].clearSelection();
this.$refs["selectedStaffTable"].clearSelection();
}, 0);
this.selectedStaffData.forEach(item => {
this.selectedStaffData.forEach((item) => {
this.staffList.push(item);
});
for (let i = 0; i < this.selectedStaffList.length; i++) {
@ -240,9 +234,6 @@ methods: {
}
}
}
},
// 将右边表格选择项存入selectedStaffData中
//handleSelectedStaffChange(rows) {
@ -257,31 +248,24 @@ methods: {
//},
// 提交
modifyStaff() {
console.log(this.selectedStaffList);
var userlist = [];
var arrContact = new Array();
for (let i = 0; i < this.selectedStaffList.length; i++) {
var reVal = new Object();
reVal["id"]=this.selectedStaffList[i].id
reVal["name"]=this.selectedStaffList[i].user.name
arrContact.push(reVal);
}
userlist=arrContact;
this.$emit('closeMoule',userlist,)
this.dialogVisible = false
}
}
}
var userlist = [];
var arrContact = new Array();
for (let i = 0; i < this.selectedStaffList.length; i++) {
var reVal = new Object();
reVal["id"] = this.selectedStaffList[i].id;
reVal["name"] = this.selectedStaffList[i].user.name;
arrContact.push(reVal);
}
userlist = arrContact;
this.$emit("closeMoule", userlist);
this.dialogVisible = false;
},
},
};
</script>

View File

@ -0,0 +1,528 @@
<template>
<div class="app-container">
<el-row :gutter="6">
<el-col :xs="24" :md="8">
<el-card class="box-card" style="overflow-y:auto;overflow-x:hidden;height:200px">
<div slot="header" class="clearfix">
<span>受审核方</span>
<el-button style="float: right; padding: 0px 0" type="text">更多企业信息</el-button>
</div>
<div class="item">{{auditee.name}}</div>
<div v-for="item in auditee.address_" :key="item.id" class="text item">
<span class="span">{{item.type}}</span>
{{item.address}}
</div>
<div class="text item">
<span class="span">常用联系人</span>
{{auditee.linkman1_name}}/{{auditee.linkman1_duty}}/{{auditee.linkman1_mobile}}
</div>
<div class="text item">
<span class="span">备用联系人</span>
{{auditee.linkman2_name}}/{{auditee.linkman2_duty}}/{{auditee.linkman2_mobile}}
</div>
</el-card>
</el-col>
<el-col :xs="24" :md="16">
<el-card class="box-card" style="overflow-y:auto;overflow-x:hidden;height:200px">
<div slot="header" class="clearfix">
<span>项目信息</span>
</div>
<div class="text item">
<span class="span">项目号</span>
{{project.number}}
<span class="span" >所属计划</span>
<span v-if="project.plan_">{{project.plan_.name}}</span>
<span v-else>暂无</span>
</div>
<div class="text item">
<span class="span">项目概况</span>
<el-tag
v-for="(item, index) in project.certapps"
:key="index"
style="margin:2px;font-size:12px"
>{{item}}</el-tag>
</div>
<div class="text item">
<span class="span">当前状态</span>
{{project.status}}
</div>
<div class="text item" v-if="project.assign_by_">
<span class="span">下达人</span>
{{project.assign_by_.name}}
</div>
<div class="text2 item">
<!-- <el-switch
style="display: block"
v-model="can_paichai"
active-color="#13ce66"
inactive-color="#FF0000"
active-text="是否可派差">
</el-switch>-->
<el-checkbox v-model="can_paichai" border @change="handlePaichai">可派差</el-checkbox>
</div>
</el-card>
</el-col>
</el-row>
<el-row style="margin-top:6px">
<el-col>
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>业务信息</span>
</div>
<el-table
ref="projectTable"
v-loading="listLoading"
:data="certappData"
style="width: 100%;"
border
fit
stripe
highlight-current-row
max-height="300"
>
<el-table-column label="单号">
<template slot-scope="scope" v-if="scope.row.number">{{ scope.row.number }}</template>
</el-table-column>
<el-table-column label="认证领域/分类" width="300px">
<template slot-scope="scope">
<el-tag v-if="scope.row.cert_field_">{{scope.row.cert_field_.name}}</el-tag>
<el-tag
v-if="scope.row.cccpv_class_"
type="warning"
style="margin:2px"
>{{scope.row.cccpv_class_.name}}</el-tag>
</template>
</el-table-column>
<!-- <el-table-column label="申请信息" width="300px">
<template slot-scope="scope">
<div>
<span style="color:darkblue;font-weight:bold">申请方</span>
:{{ scope.row.applicant_v.name }}
</div>
<div v-if="scope.row.manufacture">
<span style="color:darkblue;font-weight:bold">制造商</span>
:{{ scope.row.manufacture_v.name }}
</div>
<div v-if="scope.row.factory">
<span style="color:darkblue;font-weight:bold">生产厂</span>
:{{ scope.row.factory_v.name }}
</div>
</template>
</el-table-column>-->
<el-table-column label="当前状态">
<template slot-scope="scope">{{ scope.row.status}}</template>
</el-table-column>
<el-table-column label="受理/确认人">
<template
slot-scope="scope"
v-if="scope.row.accept_by_"
>{{ scope.row.accept_by_.name}}</template>
</el-table-column>
<el-table-column label="创建日期">
<template slot-scope="scope">
<span>{{ scope.row.create_time }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="300">
<template slot-scope="scope">
<el-button-group>
<el-button
type="primary"
size="small"
:disabled="!checkPermission(['certapp_detail'])"
@click="handleDetail(scope)"
>详情</el-button>
</el-button-group>
</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
</el-row>
<el-row :gutter="6" style="margin-top:6px">
<el-col :xs="24" :md="9">
<el-card class="box-card" style="overflow-y:auto;overflow-x:hidden;">
<div slot="header" class="clearfix">
<span>联系记录</span>
</div>
<el-table
ref="projectTable"
v-loading="listLoading"
:data="contactData"
style="width: 100%;"
border
fit
stripe
highlight-current-row
height="200"
>
<el-table-column label="联系时间">
<template slot-scope="scope">{{ scope.row.contact_date }}</template>
</el-table-column>
<el-table-column label="内容" >
<template slot-scope="scope">{{ scope.row.content }}</template>
</el-table-column>
<el-table-column label="操作人">
<template slot-scope="scope">{{ scope.row.create_by_.name }}</template>
</el-table-column>
</el-table>
<el-row :gutter="10">
<el-col :xs="24" :md="12">
<el-form
ref="elForm"
:model="formData"
:rules="rules"
size="medium"
label-width="80px"
style="margin-top:2px"
label-position="left"
>
<el-row>
<el-col>
<el-form-item label="联系时间" prop="contact_date">
<el-date-picker
v-model="formData.contact_date"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
:style="{width: '100%'}"
placeholder="联系时间"
clearable
></el-date-picker>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col>
<el-form-item label="内容" prop="content">
<el-input
v-model="formData.content"
type="textarea"
:autosize="{ minRows: 2, maxRows: 4}"
></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<div style="text-align:right;">
<el-button-group>
<el-button type="primary" @click="createNewRecord" size="mini">创建新记录</el-button>
<!-- <el-button type="primary" @click="updateNowRecord" size="mini">保存</el-button> -->
<el-button @click="resetForm" size="mini">重置</el-button>
</el-button-group>
</div>
</el-row>
</el-form>
</el-col>
<el-col :xs="24" :md="12">
<el-row>
<el-card shadow="never" style="margin-top:2px">
<div slot="header" class="clearfix">
<span>常用语</span>
</div>
<el-tag
v-for="(item, index) in useditems"
:key="index"
@click.native="handleClickTag(item)"
style="margin:2px;font-size:12px"
>{{item}}</el-tag>
</el-card>
</el-row>
</el-col>
</el-row>
</el-card>
</el-col>
<el-col :xs="24" :md="15">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>审核组成员</span>
</div>
<el-table
ref="memberTable"
v-loading="listLoading"
:data="memberData"
style="width: 100%;"
border
fit
stripe
highlight-current-row
height="200"
@row-click="handleMClick"
>
<el-table-column label="姓名">
<template slot-scope="scope">{{ scope.row.user_.name }}</template>
</el-table-column>
<el-table-column label="是否组长" >
<template slot-scope="scope">
<i class="el-icon-circle-check" v-if="scope.row.is_leader" style="color:green;"></i>
</template>
</el-table-column>
<el-table-column label="身份" >
<template slot-scope="scope" v-if="scope.row.identity">{{ scope.row.identity_.name }}</template>
</el-table-column>
</el-table>
<el-form ref="elForm2" :model="formDataMember" label-width="80px" label-position="right" :rules="rules2" style="margin-top:2px">
<el-col :xs="24" :md="12">
<el-form-item label="成员" prop="user" >
<el-input placeholder="请选择成员" readonly clearable v-model="formDataMember.user_.name">
<el-button slot="append" icon="el-icon-search" @click="choseMember"></el-button>
</el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :md="12">
<el-form-item prop="is_leader">
<el-checkbox v-model="formDataMember.is_leader">组长</el-checkbox>
</el-form-item>
</el-col>
<el-col :xs="24" :md="12">
<el-form-item label="身份" prop="identity">
<el-select v-model="formDataMember.identity" placeholder="请选择">
<el-option
v-for="item in identityOptions"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-form>
<div style="text-align:right;">
<el-button-group>
<el-button type="primary" @click="appendNewM" size="mini">添加新成员</el-button>
<el-button type="warning" @click="updateNowM" size="mini">保存</el-button>
<el-button @click="resetForm2" size="mini">重置</el-button>
</el-button-group>
</div>
</el-card>
</el-col>
</el-row>
<el-dialog
title="选择组员"
:visible.sync="choseVisiable"
:close-on-click-modal="false"
width="80%"
:append-to-body="true"
>
<Userchose ref="Userchose" :queryData="queryData" @handleChose="choseComplete"></Userchose>
</el-dialog>
</div>
</template>
<style scoped>
.text {
font-size: 15px;
}
.el-checkbox__label {
font-size: 18px;
}
.item {
margin-bottom: 4px;
}
.span {
color: gray;
font-weight: bold;
}
</style>
<script>
import { getDictList } from "@/api/dict"
import { getCertappList } from "@/api/certapp";
import { getEnterprise } from "@/api/enterprise";
import { getProject, updateProject } from "@/api/project";
import { getContactRecordList, createContactRecord } from "@/api/plan";
import Pagination from "@/components/Pagination";
import checkPermission from "@/utils/permission";
import Userchose from "@/views/employee/userchose"
import { getMemberList, createMember, updateMember, deleteMember} from "@/api/member"
import { genTree, deepClone } from '@/utils'
export default {
components: { Pagination, Userchose },
props: [],
data() {
return {
auditee: {},
project: { assign_by_: null },
certappData: [],
contactData: [],
memberData:[],
can_paichai: false,
formData: {
content: "",
project: this.$route.query.project,
},
rules: {
contact_date: [
{
required: true,
message: "请选择日期",
trigger: "change",
},
],
content: [
{
required: true,
message: "请输入内容",
trigger: "change",
},
],
},
useditems: [
"可以,第一联系人",
"可以,第二联系人",
"不可以",
"C类企业飞行检查",
],
formDataMember:{
user:null,
user_:{},
is_leader:false,
project:this.$route.query.project
},
rules2:{
user: [
{
required: true,
message: "请选择组员",
trigger: "change",
},
],
},
choseVisiable:false,
queryData:{},
identityOptions:[]
};
},
computed: {},
watch: {},
created() {
this.getParams();
this.getMemberList_()
this.getCertappList_();
this.getContactRecordList_();
this.getIdOptions();
},
mounted() {},
methods: {
checkPermission,
getParams() {
getProject(this.$route.query.project).then((res) => {
this.project = res.data;
this.can_paichai = this.project.can_paichai;
}).then(()=>{
getEnterprise(this.project.auditee).then((res) => {
this.auditee = res.data;
})
})
},
getCertappList_() {
this.listLoading = true;
getCertappList({
project: this.$route.query.project,
pageoff: true,
}).then((res) => {
if (res.data) {
this.certappData = res.data;
}
this.listLoading = false;
});
},
getIdOptions(){
getDictList({type__code:'auditor_teamrole',pageoff:true}).then(res=>{
this.identityOptions = res.data
})
},
getContactRecordList_() {
getContactRecordList({
pageoff: true,
project: this.$route.query.project,
}).then((res) => {
this.contactData = res.data;
});
},
getMemberList_(){
getMemberList({project:this.$route.query.project, pageoff:true}).then(res=>{
this.memberData = res.data
})
},
submitForm() {
this.$refs["elForm"].validate((valid) => {
if (!valid) return;
// TODO 提交表单
});
},
resetForm() {
this.$refs["elForm"].resetFields();
},
resetForm2() {
this.$refs["elForm2"].resetFields();
this.formDataMember.user_ = {}
},
handleDetail() {},
handleClickTag(val) {
this.formData.content = val;
},
createNewRecord() {
createContactRecord(this.formData).then((rse) => {
this.$message.success("成功");
this.getContactRecordList_();
});
},
// contactClick(scope) {
// this.formData.scope
// },
handlePaichai(val) {
if (val) {
this.$confirm("确定标记为可派差?", "提示", {})
.then(() => {
updateProject(this.$route.query.project, {
can_paichai: true,
}).then((res) => {
this.$message.success("成功");
});
})
.catch((res) => {
this.can_paichai = false;
});
} else {
this.$confirm("取消派差标记?", "警告", { type: "warning" })
.then(() => {
this.$message.success("未写接口");
this.can_paichai = true;
})
.catch((res) => {
this.can_paichai = true;
});
}
},
choseMember(){
this.choseVisiable = true
},
appendNewM(){
createMember(this.formDataMember).then(res=>{
this.$message.success('成功')
this.getMemberList_()
})
},
updateNowM(){
if(this.formDataMember.id){
updateMember(this.formDataMember.id, this.formDataMember).then(res=>{
this.$message.success('成功')
this.getMemberList_()
})
}
},
choseComplete(val){
if(val){
this.formDataMember.user = val.user_.id
this.formDataMember.user_.name = val.user_.name
}
this.choseVisiable = false
},
handleMClick(row,c,e){
this.formDataMember = deepClone(row)
}
},
};
</script>

View File

@ -0,0 +1,220 @@
<template>
<div class="app-container">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>月计划</span>
</div>
<div>
<div>
<el-button type="primary" @click="handleCreatePlan" size="mini">新建计划</el-button>
</div>
<el-table
v-loading="listLoading"
:data="projectData.results"
style="width: 100%;margin-top:10px;"
border
fit
stripe
highlight-current-row
height="240"
>
<el-table-column type="index" width="55"></el-table-column>
<el-table-column label="项目号">
<template slot-scope="scope" v-if="scope.row.number">{{ scope.row.number }}</template>
</el-table-column>
<el-table-column label="受审核方" width="300px">
<template slot-scope="scope">{{ scope.row.auditee_v.name }}</template>
</el-table-column>
<el-table-column label="项目信息" width="300px" :show-overflow-tooltip="true">
<template slot-scope="scope" v-if="scope.row.certapps">
<el-tag
v-for="(item, index) in scope.row.certapps"
:key="index"
style="margin:2px"
>{{item}}</el-tag>
</template>
</el-table-column>
<el-table-column label="当前状态">
<template slot-scope="scope">{{ scope.row.status}}</template>
</el-table-column>
<el-table-column label="创建人">
<template slot-scope="scope">{{ scope.row.create_by_.name}}</template>
</el-table-column>
<el-table-column label="创建日期">
<template slot-scope="scope">
<span>{{ scope.row.create_time }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="300">
<template slot-scope="scope">
<el-button-group>
<el-button
type="primary"
size="small"
:disabled="!checkPermission(['plan_update'])"
@click="handleUpdatePlan(scope)"
>编辑</el-button>
<el-button
type="danger"
size="small"
:disabled="!checkPermission(['plan_delete'])"
@click="handleDeletePlan(scope)"
>删除</el-button>
</el-button-group>
</template>
</el-table-column>
</el-table>
<pagination
v-show="projectData.count>0"
:total="projectData.count"
:page.sync="listQuery_project.page"
:limit.sync="listQuery_project.page_size"
@pagination="getProjectList_"
/>
</div>
</el-card>
<el-card class="box-card" style="margin-top:2px">
<div slot="header" class="clearfix">
<span>待处理项目</span>
</div>
<div>
<el-table
v-loading="listLoading"
:data="projectData.results"
style="width: 100%;"
border
fit
stripe
highlight-current-row
height="280"
>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="项目号">
<template slot-scope="scope" v-if="scope.row.number">{{ scope.row.number }}</template>
</el-table-column>
<el-table-column label="受审核方" width="300px">
<template slot-scope="scope">{{ scope.row.auditee_v.name }}</template>
</el-table-column>
<el-table-column label="项目信息" width="300px" :show-overflow-tooltip="true">
<template slot-scope="scope" v-if="scope.row.certapps">
<el-tag
v-for="(item, index) in scope.row.certapps"
:key="index"
style="margin:2px"
>{{item}}</el-tag>
</template>
</el-table-column>
<el-table-column label="当前状态">
<template slot-scope="scope">{{ scope.row.status}}</template>
</el-table-column>
<el-table-column label="是否可派差">
<template slot-scope="scope">
<el-switch v-model="scope.row.can_paichai" disabled></el-switch>
</template>
</el-table-column>
<el-table-column label="下达人">
<template slot-scope="scope">{{ scope.row.assign_by_.name}}</template>
</el-table-column>
<el-table-column label="创建日期" width="190">
<template slot-scope="scope">
<span>{{ scope.row.create_time }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="300" fixed="right">
<template slot-scope="scope">
<el-button-group>
<el-button
type="primary"
size="small"
:disabled="!checkPermission(['project_update'])"
@click="contactCompany(scope)"
>联系企业</el-button>
<el-button
type="danger"
size="small"
:disabled="!checkPermission(['project_delete'])"
@click="handleDetailProject(scope)"
>详情</el-button>
</el-button-group>
</template>
</el-table-column>
</el-table>
<pagination
v-show="projectData.count>0"
:total="projectData.count"
:page.sync="listQuery_project.page"
:limit.sync="listQuery_project.page_size"
@pagination="getProjectList_"
/>
</div>
</el-card>
</div>
</template>
<script>
import { getCertappList } from "@/api/certapp";
import { getProjectList, createProject, assginProject } from "@/api/project";
import Pagination from "@/components/Pagination";
import checkPermission from "@/utils/permission";
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import { genTree } from "../../utils";
import router from '@/router';
export default {
components: { Pagination, Treeselect },
data() {
return {
listLoading: true,
listQuery: {
status: "已受理",
},
listQuery_project: {
page: 1,
page_size: 20,
status:"待派差"
},
projectData: { count: 0, results: [] },
};
},
watch: {
},
created() {
this.getProjectList_();
},
methods: {
checkPermission,
getProjectList_() {
this.listLoading = true;
getProjectList(this.listQuery_project).then((response) => {
if (response.data) {
this.projectData = response.data;
}
this.listLoading = false;
});
},
resetFilter() {
this.listQuery = {
status: "已受理",
};
this.getCertappList_();
},
handleFilter() {
this.getCertappList_();
},
contactCompany(scope) {
this.$router.push({name:"Contact", query:{auditee:scope.row.auditee, project:scope.row.id}})
},
handleCreatePlan(){
},
handleUpdatePlan(){
},
handleDeletePlan(){
},
handleDetailProject(){
}
},
};
</script>

View File

@ -1,265 +1,290 @@
<template>
<div class="app-container">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>月计划</span>
</div>
<div>
<el-row :gutter="6">
<el-col :xs="24" :md="8">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>月计划</span>
(当前选择:
<span style="color:darkblue;font-weight:bold">
{{nowPlan.name}}</span>
)
</div>
<div>
<div>
<el-button type="primary" @click="handleCreatePlan" size="mini">新建计划</el-button>
</div>
<el-table
v-loading="listLoadingplan"
:data="planData.results"
style="width: 100%;margin-top:2px;"
border
fit
stripe
highlight-current-row
height="300"
@row-click="planClick"
>
<el-table-column label="计划名称">
<template slot-scope="scope" v-if="scope.row.name">{{ scope.row.name }}</template>
</el-table-column>
<el-table-column label="操作" width="120">
<template slot-scope="scope">
<el-button-group>
<el-button
type="primary"
size="small"
:disabled="!checkPermission(['plan_update'])"
@click="handleUpdatePlan(scope)"
icon="el-icon-edit"
></el-button>
<el-button
type="danger"
size="small"
:disabled="!checkPermission(['plan_delete'])"
@click="handleDeletePlan(scope)"
icon="el-icon-delete"
></el-button>
</el-button-group>
</template>
</el-table-column>
</el-table>
<pagination
v-show="planData.count>0"
:total="planData.count"
:page.sync="listQuery_plan.page"
:limit.sync="listQuery_plan.page_size"
@pagination="getPlanList_"
/>
</div>
</el-card>
</el-col>
<el-col :xs="24" :md="16">
<el-card class="box-card" style="margin-top:2px">
<div slot="header" class="clearfix">
<span>待处理项目</span>
</div>
<div>
<div style="margin-bottom:2px">
<el-button type="primary" @click="handleAppend" size="mini">添加到计划</el-button>
</div>
<el-table
v-loading="listLoading"
:data="projectData.results"
style="width: 100%;"
border
fit
stripe
highlight-current-row
height="300"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="项目号">
<template slot-scope="scope" v-if="scope.row.number">{{ scope.row.number }}</template>
</el-table-column>
<el-table-column label="受审核方" width="300px">
<template slot-scope="scope">{{ scope.row.auditee_v.name }}</template>
</el-table-column>
<el-table-column label="项目信息" width="300px" :show-overflow-tooltip="true">
<template slot-scope="scope" v-if="scope.row.certapps">
<el-tag
v-for="(item, index) in scope.row.certapps"
:key="index"
style="margin:2px"
>{{item}}</el-tag>
</template>
</el-table-column>
<el-table-column label="当前状态">
<template slot-scope="scope">{{ scope.row.status}}</template>
</el-table-column>
<el-table-column label="是否可派差">
<template slot-scope="scope">
<el-switch v-model="scope.row.can_paichai" disabled></el-switch>
</template>
</el-table-column>
<el-table-column label="下达人">
<template slot-scope="scope">{{ scope.row.assign_by_.name}}</template>
</el-table-column>
<el-table-column label="创建日期" width="190">
<template slot-scope="scope">
<span>{{ scope.row.create_time }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="200" fixed="right">
<template slot-scope="scope">
<el-button-group>
<el-button
type="primary"
size="small"
:disabled="!checkPermission(['project_update'])"
@click="contactCompany(scope)"
>联系企业</el-button>
<el-button
type="danger"
size="small"
:disabled="!checkPermission(['project_delete'])"
@click="handleDetailProject(scope)"
>详情</el-button>
</el-button-group>
</template>
</el-table-column>
</el-table>
<pagination
v-show="projectData.count>0"
:total="projectData.count"
:page.sync="listQuery_project.page"
:limit.sync="listQuery_project.page_size"
@pagination="getProjectList_"
/>
</div>
</el-card>
</el-col>
</el-row>
<el-row>
<el-card class="box-card" style="margin-top:2px">
<div slot="header" class="clearfix">
<span>月计划项目</span>
</div>
<div>
<el-button type="primary" @click="genProject0" size="mini">新建计划</el-button>
<el-table
v-loading="listLoadingplan2"
:data="projectData2.results"
style="width: 100%;"
border
fit
stripe
highlight-current-row
height="300"
>
<el-table-column label="项目号">
<template slot-scope="scope" v-if="scope.row.number">{{ scope.row.number }}</template>
</el-table-column>
<el-table-column label="受审核方" width="300px">
<template slot-scope="scope">{{ scope.row.auditee_v.name }}</template>
</el-table-column>
<el-table-column label="项目信息" width="300px" :show-overflow-tooltip="true">
<template slot-scope="scope" v-if="scope.row.certapps">
<el-tag
v-for="(item, index) in scope.row.certapps"
:key="index"
style="margin:2px"
>{{item}}</el-tag>
</template>
</el-table-column>
<el-table-column label="当前状态">
<template slot-scope="scope">{{ scope.row.status}}</template>
</el-table-column>
<el-table-column label="是否可派差">
<template slot-scope="scope">
<el-switch v-model="scope.row.can_paichai" disabled></el-switch>
</template>
</el-table-column>
<el-table-column label="下达人">
<template slot-scope="scope">{{ scope.row.assign_by_.name}}</template>
</el-table-column>
<el-table-column label="创建日期" width="190">
<template slot-scope="scope">
<span>{{ scope.row.create_time }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="200" fixed="right">
<template slot-scope="scope">
<el-button-group>
<el-button
type="primary"
size="small"
:disabled="!checkPermission(['project_update'])"
@click="contactCompany(scope)"
>计划</el-button>
<el-button
type="danger"
size="small"
:disabled="!checkPermission(['project_delete'])"
@click="handleDetailProject(scope)"
>详情</el-button>
</el-button-group>
</template>
</el-table-column>
</el-table>
<pagination
v-show="projectData2.count>0"
:total="projectData2.count"
:page.sync="listQuery2.page"
:limit.sync="listQuery2.page_size"
@pagination="getProjectList_2"
/>
</div>
<el-table
v-loading="listLoading"
:data="projectData.results"
style="width: 100%;margin-top:10px;"
border
fit
stripe
highlight-current-row
height="240"
>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="项目号">
<template slot-scope="scope" v-if="scope.row.number">{{ scope.row.number }}</template>
</el-table-column>
<el-table-column label="受审核方" width="300px">
<template slot-scope="scope">{{ scope.row.auditee_v.name }}</template>
</el-table-column>
<el-table-column label="项目信息" width="300px" :show-overflow-tooltip="true">
<template slot-scope="scope" v-if="scope.row.certapps">
<el-tag
v-for="(item, index) in scope.row.certapps"
:key="index"
style="margin:2px"
>{{item}}</el-tag>
</template>
</el-table-column>
<el-table-column label="当前状态">
<template slot-scope="scope">{{ scope.row.status}}</template>
</el-table-column>
<el-table-column label="创建人">
<template slot-scope="scope">{{ scope.row.create_by_.name}}</template>
</el-table-column>
<el-table-column label="创建日期">
<template slot-scope="scope">
<span>{{ scope.row.create_time }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="300">
<template slot-scope="scope">
<el-button-group>
<el-button
v-if="scope.row.status == '待下达'"
type="warning"
size="small"
:disabled="!checkPermission(['project_assign'])"
@click="handleAssign(scope)"
>下达</el-button>
<el-button
type="primary"
size="small"
:disabled="!checkPermission(['project_update'])"
@click="handleUpdate(scope)"
>编辑</el-button>
<el-button
type="danger"
size="small"
:disabled="!checkPermission(['project_delete'])"
@click="handleDelete(scope)"
>删除</el-button>
</el-button-group>
</template>
</el-table-column>
</el-table>
<pagination
v-show="projectData.count>0"
:total="projectData.count"
:page.sync="listQuery_project.page"
:limit.sync="listQuery_project.page_size"
@pagination="getProjectList_"
/>
</div>
</el-card>
<el-card class="box-card" style="margin-top:2px">
<div slot="header" class="clearfix">
<span>待处理项目</span>
</div>
<div>
<el-table
v-loading="listLoading"
:data="projectData.results"
style="width: 100%;"
border
fit
stripe
highlight-current-row
height="280"
>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="项目号">
<template slot-scope="scope" v-if="scope.row.number">{{ scope.row.number }}</template>
</el-table-column>
<el-table-column label="受审核方" width="300px">
<template slot-scope="scope">{{ scope.row.auditee_v.name }}</template>
</el-table-column>
<el-table-column label="项目信息" width="300px" :show-overflow-tooltip="true">
<template slot-scope="scope" v-if="scope.row.certapps">
<el-tag
v-for="(item, index) in scope.row.certapps"
:key="index"
style="margin:2px"
>{{item}}</el-tag>
</template>
</el-table-column>
<el-table-column label="当前状态">
<template slot-scope="scope">{{ scope.row.status}}</template>
</el-table-column>
<el-table-column label="创建人">
<template slot-scope="scope">{{ scope.row.create_by_.name}}</template>
</el-table-column>
<el-table-column label="创建日期">
<template slot-scope="scope">
<span>{{ scope.row.create_time }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="300">
<template slot-scope="scope">
<el-button-group>
<el-button
type="primary"
size="small"
:disabled="!checkPermission(['project_update'])"
@click="handleUpdate(scope)"
>联系企业</el-button>
<el-button
type="danger"
size="small"
:disabled="!checkPermission(['project_delete'])"
@click="handleDelete(scope)"
>详情</el-button>
</el-button-group>
</template>
</el-table-column>
</el-table>
<pagination
v-show="projectData.count>0"
:total="projectData.count"
:page.sync="listQuery_project.page"
:limit.sync="listQuery_project.page_size"
@pagination="getProjectList_"
/>
</div>
</el-card>
<el-dialog :visible.sync="dialogvisible_project" title="创建项目">
<el-form
ref="elForm"
:model="formData"
label-width="80px"
label-position="right"
:rules="rules"
>
<div v-if="certapps_data.length > 0">
已选择
<span style="color:red;font-weight:bold">{{certapps_data.length}}</span>条已受理业务
</div>
<el-form-item label="受审核方" prop="auditee">
<el-input placeholder="请选择受审核方" readonly clearable v-model="formData.auditee_v.name">
<el-button
slot="append"
icon="el-icon-search"
@click="choose(0)"
v-if="certapps_data.length == 0"
></el-button>
</el-input>
</el-form-item>
<el-form-item label="联系人" prop="auditee_v.linkman_name">
<el-input v-model="formData.auditee_v.linkman_name"></el-input>
</el-form-item>
<el-form-item label="联系方式" prop="auditee_v.linkman_mobile">
<el-input v-model="formData.auditee_v.linkman_mobile"></el-input>
</el-form-item>
<el-form-item label="备注" prop="username">
<el-input
v-model="formData.remark"
type="textarea"
:autosize="{ minRows: 6, maxRows: 10}"
></el-input>
</el-card>
</el-row>
<el-dialog :visible.sync="dialogVisible" :title="dialogType==='update'?'编辑':'新增'" >
<el-form ref="elForm" :model="formData" label-width="80px" label-position="right" :rules="rules">
<el-form-item label="计划名称" prop="name">
<el-input v-model="formData.name" placeholder="名称" />
</el-form-item>
</el-form>
<div style="text-align:right;">
<el-button type="danger" @click="dialogvisible_project=false">取消</el-button>
<el-button type="primary" @click="confirm('Form')">确认</el-button>
<el-button type="danger" @click="dialogVisible=false">取消</el-button>
<el-button type="primary" @click="confirmPlan('Form')">确认</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { getCertappList } from "@/api/certapp";
import { getProjectList, createProject, assginProject } from "@/api/project";
import { getPlanList, createPlan, updatePlan, deletePlan} from "@/api/plan"
import { getProjectList, createProject, assginProject, planProject } from "@/api/project";
import Pagination from "@/components/Pagination";
import checkPermission from "@/utils/permission";
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import { genTree } from "../../utils";
import router from "@/router";
export default {
components: { Pagination, Treeselect },
data() {
return {
certapps_data: [],
certappData: [],
listLoading: true,
listQuery: {
status: "已受理",
listLoading: false,
listLoadingplan:false,
listLoadingplan2:false,
listQuery_plan: {
page: 1,
page_size: 20,
},
listQuery_project: {
page: 1,
page_size: 20,
status:"待派差"
status: "待派差",
planoff:true
},
deptOptions: [],
field_list: [],
listQuery2:{
page: 1,
page_size: 20,
plan:''
},
planData: { count: 0, results: [] },
projectData: { count: 0, results: [] },
formData: {
certapps: [],
auditee_v: {},
auditee: null,
projectData2: { count: 0, results: [] },
dialogVisible:false,
dialogType:'create',
formData:{
},
dialogvisible_project: false,
nowPlan:{id:0},
rules: {
auditee: [
{
required: true,
message: "请选择受审核方",
trigger: "change",
},
],
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
},
multipleSelection:[],
multiprojects:[]
};
},
watch: {
certapps_data: function (val) {
let certapps = [];
for (let i = 0; i < val.length; i++) {
certapps.push(val[i].id);
}
this.formData.certapps = certapps;
},
},
watch: {},
created() {
this.getCertappList_();
this.getProjectList_();
this.getPlanList_()
},
methods: {
checkPermission,
getCertappList_() {
this.listLoading = true;
getCertappList(this.listQuery).then((response) => {
if (response.data) {
this.certappData = response.data;
}
this.listLoading = false;
});
},
getProjectList_() {
this.listLoading = true;
getProjectList(this.listQuery_project).then((response) => {
@ -269,10 +294,12 @@ export default {
this.listLoading = false;
});
},
getdeptOptions() {
getOrgList().then((res) => {
this.deptOptions = genTree(res.data);
});
getPlanList_() {
this.listLoadingplan = true
getPlanList(this.listQuery_plan).then(res=>{
this.planData = res.data
this.listLoadingplan = false
}).catch(e=>{this.listLoadingplan = false})
},
resetFilter() {
this.listQuery = {
@ -283,50 +310,104 @@ export default {
handleFilter() {
this.getCertappList_();
},
genProject() {
if (this.certapps_data.length > 0) {
this.dialogvisible_project = true;
this.formData.auditee = this.certapps_data[0].applicant;
this.formData.auditee_v = this.certapps_data[0].applicant_v;
} else {
this.$message.warning("请先选择已受理业务");
}
},
genProject0() {
this.$refs["projectTable"].clearSelection();
this.dialogvisible_project = true;
},
handleSelectionChange(val) {
this.certapps_data = val;
},
confirm() {
this.$refs["elForm"].validate((valid) => {
if (!valid) return;
// TODO 提交表单
createProject(this.formData).then((res) => {
this.getCertappList_();
this.getProjectList_();
this.dialogvisible_project = false;
this.$message.success("成功");
});
contactCompany(scope) {
this.$router.push({
name: "HandleProject",
query: { project: scope.row.id },
});
},
handleAssign(scope) {
if (scope.row.certapps.length == 0) {
this.$message.error("该项目不包含业务,无法下达!");
} else {
this.$confirm("确定下达并转入策划派差吗?", "提示", {
type: "warning",
})
.then(() => {
assginProject(scope.row.id, {}).then((res) => {
this.$message.success("下达成功");
this.getProjectList_();
});
})
.catch(() => {});
}
handleCreatePlan() {
this.dialogVisible=true
this.dialogType = 'create'
},
handleUpdatePlan(scope) {
this.formData = Object.assign({}, scope.row)
this.dialogType = 'update'
this.dialogVisible=true
this.$nextTick(() => {
this.$refs['elForm'].clearValidate()
})
},
handleDeletePlan(scope) {
this.$confirm('确定删除该计划?','警告',{type:'warning'}).then(()=>{
deletePlan(scope.row.id).then(res=>{
this.$message.success('成功')
})
}).catch(res=>{
})
},
handleDetailProject() {},
confirmPlan(){
this.$refs['elForm'].validate(valid => {
if (valid) {
const isEdit = this.dialogType === 'update'
if (isEdit) {
updatePlan(this.formData.id, this.formData).then(() => {
this.getPlanList_()
this.dialogVisible = false
this.$message.success('成功')
})
} else {
createPlan(this.formData).then(res => {
// this.org = res.data
// this.tableData.unshift(this.org)
this.getPlanList_()
this.dialogVisible = false
this.$message.success('成功')
})
}
} else {
return false
}
})
},
handleSelectionChange(val) {
var ddd = []
for(var i=0;i<val.length;i++){
ddd.push(val[i].id)
}
this.multiprojects = ddd
},
handleAppend(){
if(this.multiprojects.length>0){
if(this.nowPlan.id!=0){
this.$confirm('是否将该项目添加至('+this.nowPlan.name+')中','提示',{}).then(()=>{
planProject({'plan':this.nowPlan.id, 'projects':this.multiprojects}).then(res=>{
this.$message.success('成功')
this.getProjectList_()
})
}).catch(res=>{
})
}else{
this.$message.warning('请先选择一个计划')
}
}else{
this.$message.warning('请先选择待处理项目')
}
},
planClick(row, column, event){
if(this.nowPlan.id != row.id){
this.nowPlan = row
this.listQuery2.plan = row.id
this.listQuery2.page = 1
this.getProjectList_2()
}else{
this.getProjectList_2()
}
},
getProjectList_2(){
this.listLoadingplan2 = true
getProjectList(this.listQuery2).then(res=>{
this.listLoadingplan2 = false
this.projectData2 = res.data
}).catch(e=>{
this.listLoadingplan2 = false
})
}
},
};
</script>

View File

@ -87,7 +87,7 @@
<el-table
ref="projectTable"
v-loading="listLoading"
:data="certappData"
:data="certappData.results"
style="width: 100%;margin-top:10px;"
border
fit
@ -139,6 +139,13 @@
</el-table-column>
</el-table>
<pagination
v-show="certappData.count>0"
:total="certappData.count"
:page.sync="listQuery.page"
:limit.sync="listQuery.page_size"
@pagination="getCertappList_"
/>
</el-tab-pane>
</el-tabs>
<el-dialog :visible.sync="dialogvisible_project" title="创建项目">
@ -184,6 +191,8 @@ export default {
certappData: [],
listLoading: true,
listQuery: {
page:1,
page_size:20,
status: "已受理",
},
listQuery_project: {

View File

@ -89,14 +89,14 @@
icon="el-icon-edit"
@click="handleEdit(scope)"
/>
<!-- <el-button
<el-button
v-if="!scope.row.is_superuser"
:disabled="!checkPermission(['dict_delete'])"
type="danger"
size="small"
icon="el-icon-delete"
@click="handleDelete(scope)"
/> -->
/>
</template>
</el-table-column>
</el-table>
@ -297,7 +297,7 @@ export default {
.then(async() => {
const { code } = await deleteDict(scope.row.id)
if (code>=200){
this.dictList.splice(scope.row.index, 1)
this.getList()
this.$message({
type: 'success',
message: '成功删除!'

View File

@ -4,13 +4,18 @@ from .models import Enterprise,EnterpriseAddress
from apps.system.serializers import DictSerializer
class EnterpriseSerializer(serializers.ModelSerializer):
class EnterpriseAddressSerializer(serializers.ModelSerializer):
class Meta:
model = Enterprise
model = EnterpriseAddress
fields = '__all__'
class EnterpriseListSerializer(serializers.ModelSerializer):
type = DictSerializer()
economy_class = DictSerializer()
class Meta:
model = Enterprise
fields = ['id','query_code', 'code', 'name','ename','type','legal','build_time','person_count','ceramics_output','gassets','linkman1_name','linkman1_tel','linkman1_mobile','country_code','parent','credit_code','professional','all_person','economy_class','economy_type','linkman1_duty','business_type']
@ -18,14 +23,16 @@ class EnterpriseListSerializer(serializers.ModelSerializer):
def setup_eager_loading(queryset):
""" Perform necessary eager loading of data. """
queryset = queryset.select_related('type','economy_class')
queryset = queryset.prefetch_related('enterpriseaddress_enterprise',)
return queryset
def get_cert_type(self, obj):
return obj.get_cert_type_display()
class EnterpriseAddressSerializer(serializers.ModelSerializer):
class EnterpriseSerializer(serializers.ModelSerializer):
address_ = EnterpriseAddressSerializer(source='enterpriseaddress_enterprise', many=True)
class Meta:
model = EnterpriseAddress
model = Enterprise
fields = '__all__'
def setup_eager_loading(queryset):
""" Perform necessary eager loading of data. """
# queryset = queryset.select_related('type','economy_class')
queryset = queryset.prefetch_related('enterpriseaddress_enterprise',)
return queryset

View File

@ -1,3 +1,4 @@
from utils import serializer
from rest_framework import serializers
from .models import *
@ -5,6 +6,8 @@ from .models import *
from apps.system.serializers import DictSerializer, UserListSerializer
from apps.certset.serializers import ImplementRuleSerializer
class EmployeeSerializer(serializers.ModelSerializer):
"""
普通序列化
@ -24,6 +27,41 @@ class EmployeeSerializer(serializers.ModelSerializer):
return queryset
class TeamMemberSerializer(serializers.ModelSerializer):
"""
选人序列化
"""
user_ = UserListSerializer(source='user', read_only=True)
majors = serializers.SerializerMethodField()
class Meta:
model = Employee
fields = ['code', 'user', 'user_', 'photo', 'fields', 'majors']
def get_majors(self, obj):
majors = obj.ability_employee.all()
m = []
for i in majors:
n = {'major':'', 'abilitys':''}
if not i.is_paused:
if i.major:
n['major'] = i.major.code
n['abilitys'] = i.auditor_abilitys.values_list('name', flat=True)
m.append(n)
elif i.major_rule:
n['major'] = i.major_rule.code
n['abilitys'] = i.auditor_abilitys.values_list('name', flat=True)
m.append(n)
return m
@staticmethod
def setup_eager_loading(queryset):
""" Perform necessary eager loading of data. """
queryset = queryset.select_related('user')
return queryset
class QualificationSerializer(serializers.ModelSerializer):
"""
普通序列化

View File

@ -9,5 +9,7 @@ router.register('ability', AbilityViewSet, basename="ability")
router.register('education', EducationViewSet, basename="education")
router.register('train', TrainViewSet, basename="train")
urlpatterns = [
path('employee/team/', TeamMemberView.as_view()),
path('', include(router.urls))
]

View File

@ -1,4 +1,5 @@
from django.shortcuts import render
from rest_framework.generics import ListAPIView
from rest_framework.viewsets import ModelViewSet
from rest_framework.response import Response
from rest_framework import status
@ -7,6 +8,17 @@ from .serializers import *
from apps.system.permission_data import RbacFilterSet
from apps.system.mixins import CreateUpdateCustomMixin, OptimizationMixin
# Create your views here.
class TeamMemberView(ListAPIView):
perms_map = {'get': '*'}
queryset = Employee.objects.all()
serializer_class = TeamMemberSerializer
filterset_fields = ['is_onjob', 'is_fulltime', 'user__dept']
search_fields = ['code', 'remember_code', 'user__name', 'fields', 'ability_employee__major__code', 'ability_employee__major_rule__code']
ordering = ['-pk']
class EmployeeViewSet(CreateUpdateCustomMixin, OptimizationMixin, ModelViewSet):
"""
详细信息-增删改查
@ -17,7 +29,7 @@ class EmployeeViewSet(CreateUpdateCustomMixin, OptimizationMixin, ModelViewSet):
serializer_class = EmployeeSerializer
search_fields = ['code', 'remember_code', 'user__name', 'fields']
filterset_fields = ['is_onjob', 'is_fulltime', 'user__dept']
ordering = ['-create_time']
ordering = ['-pk']
class QualificationViewSet(CreateUpdateCustomMixin, OptimizationMixin, ModelViewSet):

View File

View File

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

5
server/apps/plan/apps.py Normal file
View File

@ -0,0 +1,5 @@
from django.apps import AppConfig
class PlanConfig(AppConfig):
name = 'plan'

View File

View File

@ -0,0 +1,58 @@
# Generated by Django 3.0.7 on 2020-08-25 08:36
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),
('system', '0031_delete_bscodeset'),
('project', '0026_merge_20200825_1636'),
]
operations = [
migrations.CreateModel(
name='Plan',
fields=[
('id', models.AutoField(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='删除标记')),
('name', models.CharField(max_length=1000, verbose_name='计划名称')),
('month', models.DateField(blank=True, null=True, verbose_name='计划审核月份')),
('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='plan_belong_dept', to='system.Organization', verbose_name='所属部门')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='plan_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='plan_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
],
options={
'verbose_name': '审核计划',
'verbose_name_plural': '审核计划',
},
),
migrations.CreateModel(
name='ContactRecord',
fields=[
('id', models.AutoField(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='删除标记')),
('contact_date', models.DateField(verbose_name='联系时间')),
('content', models.TextField(verbose_name='内容')),
('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='contactrecord_belong_dept', to='system.Organization', verbose_name='所属部门')),
('certapp', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='contactrecord_certapp', to='project.CertApp', verbose_name='关联申请')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='contactrecord_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='contactrecord_project', to='project.Project', verbose_name='所属项目')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='contactrecord_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
],
options={
'verbose_name': '联系记录',
'verbose_name_plural': '联系记录',
},
),
]

View File

@ -0,0 +1,43 @@
# Generated by Django 3.0.7 on 2020-09-01 07:11
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('system', '0031_delete_bscodeset'),
('project', '0027_auto_20200825_1636'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('plan', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='plan',
name='name',
field=models.CharField(max_length=1000, unique=True, verbose_name='计划名称'),
),
migrations.CreateModel(
name='Team',
fields=[
('id', models.AutoField(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='删除标记')),
('is_leader', models.BooleanField(default=False, verbose_name='是否是组长')),
('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='team_belong_dept', to='system.Organization', verbose_name='所属部门')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='team_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('identity', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='system.Dict', verbose_name='身份')),
('member', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='成员')),
('project', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='project.Project', verbose_name='所属项目')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='team_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
],
options={
'abstract': False,
},
),
]

View File

@ -0,0 +1,42 @@
# Generated by Django 3.0.7 on 2020-09-01 07:55
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('system', '0031_delete_bscodeset'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('project', '0027_auto_20200825_1636'),
('plan', '0002_auto_20200901_1511'),
]
operations = [
migrations.CreateModel(
name='Member',
fields=[
('id', models.AutoField(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='删除标记')),
('is_leader', models.BooleanField(default=False, verbose_name='是否是组长')),
('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='member_belong_dept', to='system.Organization', verbose_name='所属部门')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='member_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('identity', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='member_identity', to='system.Dict', verbose_name='身份')),
('project', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='member_project', to='project.Project', verbose_name='所属项目')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='member_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='member_user', to=settings.AUTH_USER_MODEL, verbose_name='成员')),
],
options={
'verbose_name': '审核组成员',
'verbose_name_plural': '审核组成员',
},
),
migrations.DeleteModel(
name='Team',
),
]

View File

View File

@ -0,0 +1,57 @@
from utils import model
from django.contrib.postgres.fields import JSONField
from django.db import models
from rest_framework.exceptions import ParseError
from simple_history.models import HistoricalRecords
from apps.system.models import CommonAModel, CommonBModel, Dict, User
from apps.project.models import Project, CertApp
# Create your models here.
class Plan(CommonBModel):
"""
计划(项目组)
"""
name = models.CharField('计划名称', max_length = 1000, unique=True)
month = models.DateField('计划审核月份', null=True, blank=True)
class Meta:
verbose_name = '审核计划'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
class ContactRecord(CommonBModel):
"""
联系记录
"""
project = models.ForeignKey(Project, on_delete=models.CASCADE, verbose_name='所属项目', related_name='contactrecord_project')
certapp = models.ForeignKey(CertApp, on_delete=models.CASCADE, verbose_name='关联申请', null=True, blank=True, related_name='contactrecord_certapp')
contact_date = models.DateField('联系时间')
content = models.TextField('内容')
class Meta:
verbose_name = '联系记录'
verbose_name_plural = verbose_name
def __str__(self):
return self.content
class Member(CommonBModel):
"""
审核组成员
"""
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='成员', related_name='member_user')
is_leader = models.BooleanField('是否是组长', default=False)
project = models.ForeignKey(Project, on_delete=models.SET_NULL, null=True, blank=True, verbose_name='所属项目', related_name='member_project')
identity = models.ForeignKey(Dict, on_delete=models.SET_NULL, null=True, blank=True, verbose_name='身份', related_name='member_identity')
class Meta:
verbose_name = '审核组成员'
verbose_name_plural = verbose_name
def __str__(self):
return self.member.name

View File

@ -0,0 +1,24 @@
from rest_framework import serializers
from .models import *
from apps.system.serializers import DictSerializer, UserListSerializer
from apps.certset.serializers import StandardSerializer
class ContactRecordSerializer(serializers.ModelSerializer):
create_by_=UserListSerializer(source='create_by', read_only=True)
class Meta:
model = ContactRecord
fields = '__all__'
class PlanSerializer(serializers.ModelSerializer):
class Meta:
model = Plan
fields = '__all__'
class MemberSerializer(serializers.ModelSerializer):
user_ = UserListSerializer(source='user', read_only=True)
identity_ = DictSerializer(source='identity', read_only=True)
class Meta:
model = Member
fields = '__all__'

View File

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

11
server/apps/plan/urls.py Normal file
View File

@ -0,0 +1,11 @@
from django.urls import path, include
from .views import *
from rest_framework import routers
router = routers.DefaultRouter()
router.register('contactrecord', ContactRecordViewSet, basename="contactrecord")
router.register('plan', PlanViewSet, basename='plan')
router.register('member', MemberViewSet, basename='member')
urlpatterns = [
path('', include(router.urls))
]

55
server/apps/plan/views.py Normal file
View File

@ -0,0 +1,55 @@
from django.shortcuts import render
import rest_framework
from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import ModelViewSet, GenericViewSet
from rest_framework.response import Response
from rest_framework import status
from .models import *
from .serializers import *
from apps.system.models import Dict
from apps.system.permission_data import RbacFilterSet
from apps.system.mixins import CreateUpdateCustomMixin, OptimizationMixin
import random
from rest_framework.decorators import action
from .filters import *
from utils.pagination import PageOrNot
# Create your views here.
class ContactRecordViewSet(CreateUpdateCustomMixin, PageOrNot, ModelViewSet):
"""
联系记录
"""
perms_map = {'get': 'contactrecord_view', 'post':'contactrecord_create', 'put':'contactrecord_update','delete': 'contactrecord_delete'}
queryset = ContactRecord.objects.all()
serializer_class = ContactRecordSerializer
ordering = ['pk']
filterset_fields = ['project', 'certapp']
class PlanViewSet(RbacFilterSet, PageOrNot, ModelViewSet):
"""
计划
"""
perms_map = {'get': 'plan_view', 'post':'plan_create', 'put':'plan_update','delete': 'plan_delete'}
queryset = Plan.objects.all()
serializer_class = PlanSerializer
ordering = ['pk']
# filterset_fields = ['project', 'certapp']
class MemberViewSet(CreateUpdateCustomMixin, PageOrNot, ModelViewSet):
"""
审核组成员
"""
perms_map = {'get': '*', 'post':'member_create', 'put':'member_update','delete': 'member_delete'}
queryset = Member.objects.all()
serializer_class = MemberSerializer
ordering = ['pk']
filterset_fields = ['project']
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
if Member.objects.filter(user = request.data['user'], project=request.data['project'], is_deleted=False).exists():
return Response('已存在该成员', status= status.HTTP_400_BAD_REQUEST)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

View File

@ -5,4 +5,10 @@ class CertAppFilter(filters.FilterSet):
noproject = filters.BooleanFilter(field_name='project', lookup_expr='isnull')
class Meta:
model = CertApp
fields = ['status', 'noproject']
fields = ['status', 'noproject']
class ProjectFilter(filters.FilterSet):
planoff = filters.BooleanFilter(field_name='plan', lookup_expr='isnull')
class Meta:
model = Project
fields = ['plan', 'planoff']

View File

@ -0,0 +1,14 @@
# Generated by Django 3.0.7 on 2020-08-25 08:36
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('project', '0022_auto_20200821_1435'),
('project', '0025_auto_20200821_1541'),
]
operations = [
]

View File

@ -0,0 +1,30 @@
# Generated by Django 3.0.7 on 2020-08-25 08:36
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),
('plan', '0001_initial'),
('project', '0026_merge_20200825_1636'),
]
operations = [
migrations.AddField(
model_name='certapp',
name='accept_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='受理人'),
),
migrations.AlterField(
model_name='project',
name='plan',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='plan.Plan', verbose_name='所属计划'),
),
migrations.DeleteModel(
name='Plan',
),
]

View File

@ -7,23 +7,10 @@ from simple_history.models import HistoricalRecords
from apps.certset.models import ImplementRule, UnitType, EvaluationItem, Standard
from apps.crm.models import Enterprise
from apps.system.models import CommonAModel, CommonBModel, Dict, User
# from apps.plan.models import Plan
# Create your models here.
class Plan(CommonBModel):
"""
计划(项目组)
"""
name = models.CharField('计划名称', max_length = 1000)
month = models.DateField('计划审核月份', null=True, blank=True)
class Meta:
verbose_name = '审核计划'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
class Project(CommonBModel):
"""
认证项目
@ -43,7 +30,7 @@ class Project(CommonBModel):
assign_date = models.DateField('下达日期', null=True, blank=True)
assign_by = models.ForeignKey(User, verbose_name='下达人', on_delete=models.SET_NULL, null=True, blank=True)
can_paichai = models.BooleanField('是否可派差', default = False)
plan = models.ForeignKey(Plan, verbose_name='所属计划', on_delete=models.SET_NULL, null=True, blank=True)
plan = models.ForeignKey('plan.Plan', verbose_name='所属计划', on_delete=models.SET_NULL, null=True, blank=True)
class Meta:
@ -53,6 +40,7 @@ class Project(CommonBModel):
def __str__(self):
return self.number
class CertApp(CommonBModel):
"""
认证受理
@ -74,7 +62,7 @@ class CertApp(CommonBModel):
number = models.CharField('受理编号', max_length = 100, null=True, blank=True)
apply_date = models.DateField('申请日期', null=True, blank=True)
accept_date = models.DateField('受理日期', null=True, blank=True)
accept_by = models.ForeignKey(User, verbose_name='受理人', on_delete=models.SET_NULL, null=True, blank=True)
applicant_v = JSONField(verbose_name='申请方')
applicant = models.ForeignKey(Enterprise, related_name='certapp_applicant', on_delete=models.DO_NOTHING)

View File

@ -1,9 +1,11 @@
from apps.plan.models import Plan
from rest_framework import serializers
from .models import *
from apps.system.serializers import DictSerializer, UserListSerializer
from apps.certset.serializers import StandardSerializer
from apps.plan.serializers import PlanSerializer
class ApplicationCreateSerializer(serializers.ModelSerializer):
number = serializers.CharField(required=False)
@ -41,9 +43,17 @@ class CertappSerializer(serializers.ModelSerializer):
cccpv_class_ = DictSerializer(source='cccpv_class' , read_only=True)
cnas_scopes_ = DictSerializer(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)
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',)
return queryset
class UnitSerializer(serializers.ModelSerializer):
standard_ = StandardSerializer(source='standard', read_only=True)
@ -53,7 +63,10 @@ class UnitSerializer(serializers.ModelSerializer):
class ProjectSerializer(serializers.ModelSerializer):
create_by_ = UserListSerializer(source='create_by', read_only=True)
assign_by_ = UserListSerializer(source='assign_by', read_only=True)
certapps = serializers.SerializerMethodField()
plan_ = PlanSerializer(source='plan', read_only=True)
class Meta:
model = Project
fields = '__all__'
@ -62,4 +75,16 @@ class ProjectSerializer(serializers.ModelSerializer):
certapps = []
for i in CertApp.objects.filter(is_deleted=False, project=obj):
certapps.append(i.cert_field.code +'(' + i.cccpv_class.name +')')
return certapps
return certapps
@staticmethod
def setup_eager_loading(queryset):
""" Perform necessary eager loading of data. """
queryset = queryset.select_related('create_by', 'assign_by', 'plan')
return queryset
class ProjectUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = Project
fields = ['remark', 'can_paichai']

View File

@ -1,5 +1,6 @@
from rest_framework.views import APIView
from apps import project
from django.shortcuts import render
import rest_framework
from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import ModelViewSet, GenericViewSet
from rest_framework.response import Response
@ -12,8 +13,10 @@ from apps.system.mixins import CreateUpdateCustomMixin, OptimizationMixin
import random
from rest_framework.decorators import action
from .filters import *
from utils.pagination import PageOrNot
from rest_framework.exceptions import ParseError, NotAuthenticated
# Create your views here.
class ApplicationViewSet(CreateUpdateCustomMixin, RbacFilterSet, ModelViewSet):
class ApplicationViewSet(RbacFilterSet, ModelViewSet):
"""
认证申请
"""
@ -31,7 +34,7 @@ class ApplicationViewSet(CreateUpdateCustomMixin, RbacFilterSet, ModelViewSet):
def perform_create(self, serializer):
serializer.save(create_by = self.request.user, belong_dept=self.request.user.dept, number=random.randrange(1000,2000))
class SubApplicationViewSet(CreateUpdateCustomMixin, RbacFilterSet, ModelViewSet):
class SubApplicationViewSet(RbacFilterSet, ModelViewSet):
"""
子认证申请
"""
@ -62,7 +65,7 @@ class SubApplicationViewSet(CreateUpdateCustomMixin, RbacFilterSet, ModelViewSet
return None
return self.paginator.paginate_queryset(queryset, self.request, view=self)
class CertappViewset(CreateUpdateCustomMixin, RbacFilterSet, ModelViewSet):
class CertappViewset(PageOrNot, RbacFilterSet, ModelViewSet):
"""
申请受理
"""
@ -72,14 +75,8 @@ class CertappViewset(CreateUpdateCustomMixin, RbacFilterSet, ModelViewSet):
ordering = ['-create_time']
filterset_fields = ['status', 'project']
# filterset_class = CertAppFilter
def paginate_queryset(self, queryset):
if ((not self.request.query_params.get('page', None)) and (self.request.query_params.get('status', None))) or (self.paginator is None):
return None
return self.paginator.paginate_queryset(queryset, self.request, view=self)
return queryset
def create(self, request, *args, **kwargs):
postdata = request.data
postdata['number'] = random.randrange(1000,2000)
@ -102,7 +99,7 @@ class CertappViewset(CreateUpdateCustomMixin, RbacFilterSet, ModelViewSet):
obj.save()
return Response(status=status.HTTP_200_OK)
class UnitViewSet(CreateUpdateCustomMixin, RbacFilterSet, ModelViewSet):
class UnitViewSet(RbacFilterSet, ModelViewSet):
"""
产品单元
"""
@ -112,22 +109,33 @@ class UnitViewSet(CreateUpdateCustomMixin, RbacFilterSet, ModelViewSet):
ordering = ['pk']
filterset_fields = ['certapp']
class ProjectViewSet(CreateUpdateCustomMixin, RbacFilterSet, ModelViewSet):
class ProjectViewSet(RbacFilterSet, ModelViewSet):
perms_map = {'get': 'project_view', 'post':'project_create', 'put':'project_update','delete': 'project_delete'}
queryset = Project.objects.all()
serializer_class = ProjectSerializer
ordering = ['pk']
filterset_class = ProjectFilter
def get_serializer_class(self):
if self.action == 'update':
return ProjectUpdateSerializer
return ProjectSerializer
def create(self, request, *args, **kwargs):
postdata = request.data
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)
if 'certapps' in postdata and postdata['certapps']:
CertApp.objects.filter(pk__in = postdata['certapps']).update(project=instance, status='进行中')
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
if self.request.user is not None:
instance = 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, status='进行中')
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
else:
return NotAuthenticated()
@action(methods=['put'], detail=True, perms_map={'put':'project_assgin'},
url_name='project_assgin')
@ -138,7 +146,20 @@ class ProjectViewSet(CreateUpdateCustomMixin, RbacFilterSet, ModelViewSet):
obj = self.get_object()
if obj.status == '待下达':
obj.status = '待派差'
obj.assgin_by = request.user
obj.save()
return Response(status=status.HTTP_200_OK)
else:
return Response('状态有误', status=status.HTTP_400_BAD_REQUEST)
return Response('状态有误', status=status.HTTP_400_BAD_REQUEST)
@action(methods=['put'], detail=False, perms_map={'put':'project_plan'},
url_name='project_plan')
def plan(self, request, *args, **kwargs):
"""
项目计划
"""
projects = request.data['projects']
plan = request.data['plan']
if projects:
Project.objects.filter(pk__in=projects).update(plan=plan)
return Response(status=status.HTTP_200_OK)

View File

@ -1,11 +1,11 @@
from django.db.models import Q
from django.db.models.query import QuerySet
from rest_framework.generics import GenericAPIView
from apps.system.mixins import CreateUpdateModelBMixin
from apps.system.mixins import CreateUpdateModelBMixin, CreateUpdateCustomMixin
from utils.queryset import get_child_queryset2
class RbacFilterSet(CreateUpdateModelBMixin, object):
class RbacFilterSet(CreateUpdateCustomMixin, object):
"""
数据权限控权返回的queryset
在必须的View下继承
@ -21,8 +21,6 @@ class RbacFilterSet(CreateUpdateModelBMixin, object):
)
queryset = self.queryset
if hasattr(self.get_serializer_class(), 'setup_eager_loading'):
queryset = self.get_serializer_class().setup_eager_loading(queryset) # 性能优化
if isinstance(queryset, QuerySet):
# Ensure queryset is re-evaluated on each request.
queryset = queryset.all()
@ -51,6 +49,8 @@ class RbacFilterSet(CreateUpdateModelBMixin, object):
elif '仅本人' in data_range:
queryset = queryset.filter(Q(create_by=user)|Q(update_by=user))
return queryset
if hasattr(self.get_serializer_class(), 'setup_eager_loading'):
queryset = self.get_serializer_class().setup_eager_loading(queryset) # 性能优化
return queryset

View File

@ -49,7 +49,8 @@ INSTALLED_APPS = [
'apps.certset',
'apps.employee',
'apps.project',
'apps.laboratory'
'apps.laboratory',
'apps.plan'
]
MIDDLEWARE = [

View File

@ -36,6 +36,7 @@ urlpatterns = [
path('crm/', include('apps.crm.urls')),
path('employee/', include('apps.employee.urls')),
path('project/', include('apps.project.urls')),
path('plan/', include('apps.plan.urls')),
path('laboratory/', include('apps.laboratory.urls')),
path('docs/', include_docs_urls(title="接口文档",
authentication_classes=[], permission_classes=[])),

View File

@ -1,6 +1,16 @@
from rest_framework.pagination import PageNumberPagination
from rest_framework.exceptions import ParseError
class MyPagination(PageNumberPagination):
page_size = 10
page_size_query_param = 'page_size'
class PageOrNot:
def paginate_queryset(self, queryset):
if (self.paginator is None):
return None
elif self.request.query_params.get('pageoff', None) and self.get_queryset().count()<500:
return None
elif self.request.query_params.get('pageoff', None) and self.get_queryset().count()>=500:
return ParseError('单次请求数据量大,请求中止')
return self.paginator.paginate_queryset(queryset, self.request, view=self)