创建正式考试
This commit is contained in:
parent
b920e6f701
commit
9554132a66
|
@ -0,0 +1,29 @@
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function getexamlist(query) {
|
||||||
|
return request({
|
||||||
|
url: '/examtest/exam/',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
export function createexam(data) {
|
||||||
|
return request({
|
||||||
|
url: '/examtest/exam/',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
export function updateexam(id, data) {
|
||||||
|
return request({
|
||||||
|
url: `/examtest/exam/${id}/`,
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
export function deleteexam(id) {
|
||||||
|
return request({
|
||||||
|
url: `/examtest/exam/${id}/`,
|
||||||
|
method: 'delete',
|
||||||
|
})
|
||||||
|
}
|
|
@ -35,10 +35,11 @@ export function deleteTestRule(id) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getWorkScopeAll() {
|
export function getWorkScopeAll(query) {
|
||||||
return request({
|
return request({
|
||||||
url: '/examtest/workscope/',
|
url: '/examtest/workscope/',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
|
params: query
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -247,6 +247,21 @@ export const asyncRoutes = [
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/exammanage',
|
||||||
|
component: Layout,
|
||||||
|
redirect: '/exammanage/index',
|
||||||
|
name: 'Exammanage',
|
||||||
|
meta: { title: '考试管理', icon: '', perms: []},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'index',
|
||||||
|
name: 'exam',
|
||||||
|
component: () => import('@/views/exam/index.vue'),
|
||||||
|
meta: { title: '考试管理', icon: 'component', perms: ['exam_view'] }
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/analyse',
|
path: '/analyse',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
|
@ -268,6 +283,7 @@ export const asyncRoutes = [
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
path: '/qtest',
|
path: '/qtest',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
|
|
|
@ -64,9 +64,61 @@ div:focus {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-table--medium td, .el-table--medium th {
|
||||||
|
padding: 2px 0;
|
||||||
|
}
|
||||||
|
.el-form-item {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.el-card, .el-message {
|
||||||
|
border-radius: 0px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
.el-card__body {
|
.el-card__body {
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
}
|
}
|
||||||
.el-card__header {
|
.el-card__header {
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
}
|
}
|
||||||
|
.el-tabs--border-card>.el-tabs__content {
|
||||||
|
padding: 6px;
|
||||||
|
}
|
||||||
|
.el-dialog__header {
|
||||||
|
padding: 10px 10px 6px;
|
||||||
|
}
|
||||||
|
// .el-dialog{
|
||||||
|
// display: flex;
|
||||||
|
// flex-direction: column;
|
||||||
|
// margin:0 !important;
|
||||||
|
// position:absolute;
|
||||||
|
// top:50%;
|
||||||
|
// left:50%;
|
||||||
|
// transform:translate(-50%,-50%);
|
||||||
|
// /*height:600px;*/
|
||||||
|
// max-height:calc(100% - 30px);
|
||||||
|
// max-width:calc(100% - 30px);
|
||||||
|
// }
|
||||||
|
.el-dialog .el-dialog__body{
|
||||||
|
// flex:1;
|
||||||
|
// overflow: auto;
|
||||||
|
padding: 8px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form--label-top .el-form-item__label {
|
||||||
|
line-height: 16px;
|
||||||
|
}
|
||||||
|
.el-button+.el-button {
|
||||||
|
margin-left: 1px;
|
||||||
|
}
|
||||||
|
.el-tabs__header {
|
||||||
|
margin: 0 0 6px;
|
||||||
|
}
|
||||||
|
.pagination-container {
|
||||||
|
padding: 0px 0px;
|
||||||
|
}
|
||||||
|
body .el-table th.gutter{
|
||||||
|
display: table-cell!important;
|
||||||
|
}
|
||||||
|
.el-dialog__footer{
|
||||||
|
padding: 6px 6px 6px;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,273 @@
|
||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
<div style="margin-top:10px">
|
||||||
|
<el-input
|
||||||
|
v-model="listQuery.search"
|
||||||
|
placeholder="输入考试名称进行搜索"
|
||||||
|
style="width: 300px;"
|
||||||
|
class="filter-item"
|
||||||
|
@keyup.enter.native="handleFilter"
|
||||||
|
/>
|
||||||
|
<el-button type="primary" @click="handleAdd" icon="el-icon-plus" v-if ="checkPermission(['exam_create'])">新增</el-button>
|
||||||
|
<el-button
|
||||||
|
class="filter-item"
|
||||||
|
type="primary"
|
||||||
|
icon="el-icon-refresh-left"
|
||||||
|
@click="resetFilter"
|
||||||
|
>刷新重置</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-table
|
||||||
|
:data="tableData.results"
|
||||||
|
style="width: 100%;margin-top:10px;"
|
||||||
|
border
|
||||||
|
fit
|
||||||
|
v-loading="listLoading"
|
||||||
|
highlight-current-row
|
||||||
|
max-height="600"
|
||||||
|
row-key="id"
|
||||||
|
default-expand-all
|
||||||
|
>
|
||||||
|
<el-table-column label="考试名称">
|
||||||
|
<template slot-scope="scope">{{ scope.row.name }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="考试编号">
|
||||||
|
<template slot-scope="scope">{{ scope.row.code }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="考试地点">
|
||||||
|
<template slot-scope="scope">{{ scope.row.place }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="工作类别">
|
||||||
|
<template slot-scope="scope">{{ scope.row.workscope }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="开启时间">
|
||||||
|
<template slot-scope="scope">{{ scope.row.opentime }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="关闭时间">
|
||||||
|
<template slot-scope="scope">{{ scope.row.closetime }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="创建人">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span>{{ scope.row.create_admin_name }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="center" label="操作" fixed="right">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
@click="handleView(scope)"
|
||||||
|
:disabled="!checkPermission(['exam_view'])"
|
||||||
|
>详情</el-button>
|
||||||
|
<el-button
|
||||||
|
size="small"
|
||||||
|
@click="handleEdit(scope)"
|
||||||
|
:disabled="!checkPermission(['exam_update'])"
|
||||||
|
>编辑</el-button>
|
||||||
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
size="small"
|
||||||
|
@click="handleDelete(scope)"
|
||||||
|
:disabled="!checkPermission(['exam_delete'])"
|
||||||
|
>删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<pagination
|
||||||
|
v-show="tableData.count>0"
|
||||||
|
:total="tableData.count"
|
||||||
|
:page.sync="listQuery.page"
|
||||||
|
:limit.sync="listQuery.limit"
|
||||||
|
@pagination="getList"
|
||||||
|
/>
|
||||||
|
<el-dialog :visible.sync="dialogVisible" :title="dialogType==='edit'?'编辑考试':'新增考试'" >
|
||||||
|
<el-form :model="exam" label-width="80px" :rules="rule1" ref="examForm">
|
||||||
|
<el-form-item label="名称" prop="name">
|
||||||
|
<el-input v-model="exam.name" placeholder="名称" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="考试地点" prop="place">
|
||||||
|
<el-input v-model="exam.place" placeholder="考试地点" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="工作类别" prop="workscope" >
|
||||||
|
<el-select v-model="exam.workscope" placeholder="请选择工作类别" style="width:100%">
|
||||||
|
<el-option
|
||||||
|
v-for="item in workscopeOptions"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="开启时间" prop="opentime">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="exam.opentime"
|
||||||
|
type="datetime"
|
||||||
|
placeholder="开启时间"
|
||||||
|
style="width:100%">
|
||||||
|
</el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="关闭时间" prop="closetime">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="exam.closetime"
|
||||||
|
type="datetime"
|
||||||
|
placeholder="关闭时间"
|
||||||
|
style="width:100%"
|
||||||
|
></el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="监考人姓名" prop="proctor_name" label-width="120px">
|
||||||
|
<el-input v-model="exam.proctor_name" placeholder="监考人姓名" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="监考人联系方式" prop="proctor_phone" label-width="120px">
|
||||||
|
<el-input v-model="exam.proctor_phone" placeholder="监考人联系方式" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<div style="text-align:right;">
|
||||||
|
<el-button type="danger" @click="dialogVisible=false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="confirmexam('examForm')">确认</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getexamlist, createexam, deleteexam, updateexam} from "@/api/exam";
|
||||||
|
import { getWorkScopeAll } from "@/api/examtest"
|
||||||
|
import { deepClone } from "@/utils";
|
||||||
|
import checkPermission from "@/utils/permission";
|
||||||
|
import Pagination from "@/components/Pagination"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const defaultexam = {
|
||||||
|
id: "",
|
||||||
|
name: "",
|
||||||
|
place: "",
|
||||||
|
opentime: null,
|
||||||
|
closetime: null,
|
||||||
|
};
|
||||||
|
const listQuery = {
|
||||||
|
page: 1,
|
||||||
|
limit: 20,
|
||||||
|
search: ""
|
||||||
|
}
|
||||||
|
export default {
|
||||||
|
components: { Pagination },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
selects:[],
|
||||||
|
exam: {
|
||||||
|
id: "",
|
||||||
|
name: "",
|
||||||
|
},
|
||||||
|
listQuery:listQuery,
|
||||||
|
tableData: {count:0},
|
||||||
|
listLoading: true,
|
||||||
|
dialogVisible: false,
|
||||||
|
dialogType: "new",
|
||||||
|
workscopeOptions:[],
|
||||||
|
rule1: {
|
||||||
|
name: [{ required: true, message: "请输入", trigger: "blur" }],
|
||||||
|
place: [{ required: true, message: "请输入", trigger: "change" }],
|
||||||
|
workscope: [{ required: true, message: "请选择", trigger: "change" }],
|
||||||
|
opentime: [{ required: true, message: "请选择", trigger: "change" }],
|
||||||
|
closetime: [{ required: true, message: "请选择", trigger: "change" }],
|
||||||
|
proctor_name: [{ required: true, message: "请输入", trigger: "change" }],
|
||||||
|
proctor_phone: [{ required: true, message: "请输入", trigger: "change" }]
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {},
|
||||||
|
created() {
|
||||||
|
this.getList();
|
||||||
|
this.getworkscopeOptions();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
checkPermission,
|
||||||
|
getworkscopeOptions(){
|
||||||
|
getWorkScopeAll({can_exam:true}).then(res=>{
|
||||||
|
this.workscopeOptions = res.data
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getList() {
|
||||||
|
this.listLoading = true
|
||||||
|
getexamlist(this.listQuery).then(response => {
|
||||||
|
this.tableData = response.data
|
||||||
|
this.listLoading = false
|
||||||
|
});
|
||||||
|
},
|
||||||
|
resetFilter() {
|
||||||
|
this.listQuery = {
|
||||||
|
page: 1,
|
||||||
|
limit: 20,
|
||||||
|
search: ""
|
||||||
|
};
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
handleFilter() {
|
||||||
|
this.listQuery.page = 1;
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
handleAdd() {
|
||||||
|
this.exam = Object.assign({}, defaultexam);
|
||||||
|
this.dialogType = "new";
|
||||||
|
this.dialogVisible = true;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs["examForm"].clearValidate();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleEdit(scope) {
|
||||||
|
this.exam = Object.assign({}, scope.row); // copy obj
|
||||||
|
this.dialogType = "edit";
|
||||||
|
this.dialogVisible = true;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs["examForm"].clearValidate();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleDelete(scope) {
|
||||||
|
this.$confirm("确认删除该考试吗?将丢失数据!", "警告", {
|
||||||
|
confirmButtonText: "确认",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "error"
|
||||||
|
})
|
||||||
|
.then(async () => {
|
||||||
|
await deleteexam(scope.row.id);
|
||||||
|
this.getList()
|
||||||
|
this.$message({
|
||||||
|
type: "success",
|
||||||
|
message: "成功删除!"
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
// console.error(err);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleView(scope){
|
||||||
|
|
||||||
|
},
|
||||||
|
async confirmexam(form) {
|
||||||
|
this.$refs[form].validate(valid => {
|
||||||
|
if (valid) {
|
||||||
|
const isEdit = this.dialogType === "edit";
|
||||||
|
if (isEdit) {
|
||||||
|
updateexam(this.exam.id, this.exam).then(() => {
|
||||||
|
this.getList();
|
||||||
|
this.dialogVisible = false;
|
||||||
|
this.$message.success('成功')
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
createexam(this.exam).then(res => {
|
||||||
|
// this.exam = res.data
|
||||||
|
// this.tableData.unshift(this.exam)
|
||||||
|
this.getList();
|
||||||
|
this.dialogVisible = false;
|
||||||
|
this.$message.success('成功')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
|
@ -20,14 +20,20 @@
|
||||||
row-key="id"
|
row-key="id"
|
||||||
>
|
>
|
||||||
<el-table-column type="index" width="50"></el-table-column>
|
<el-table-column type="index" width="50"></el-table-column>
|
||||||
<el-table-column align="center" label="名称">
|
<el-table-column label="名称">
|
||||||
<template slot-scope="scope">{{ scope.row.name }}</template>
|
<template slot-scope="scope">{{ scope.row.name }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="center" label="所属学科">
|
<el-table-column label="所属学科">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-tag type="success" >{{scope.row.subject_name}}</el-tag>
|
<el-tag type="success" >{{scope.row.subject_name}}</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<el-table-column label="是否可组织考试">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-tag v-if="scope.row.can_exam">是</el-tag>
|
||||||
|
<el-tag type="warning" v-else>否</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column label="创建日期">
|
<el-table-column label="创建日期">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<span>{{ scope.row.create_time }}</span>
|
<span>{{ scope.row.create_time }}</span>
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
<el-form-item label="工作类别" prop="name">
|
<el-form-item label="工作类别" prop="name">
|
||||||
<el-input v-model="Form.name" style="width:400px"></el-input>
|
<el-input v-model="Form.name" style="width:400px"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="是否可组织考试" prop="can_exam" label-width="120px">
|
||||||
|
<el-switch v-model="Form.can_exam"></el-switch>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="所属学科" prop="subject">
|
<el-form-item label="所属学科" prop="subject">
|
||||||
<el-select v-model="Form.subject" placeholder="请选择所属学科" style="width:400px">
|
<el-select v-model="Form.subject" placeholder="请选择所属学科" style="width:400px">
|
||||||
<el-option
|
<el-option
|
||||||
|
@ -57,6 +60,7 @@ export default {
|
||||||
return {
|
return {
|
||||||
Form: {
|
Form: {
|
||||||
name: "",
|
name: "",
|
||||||
|
can_exam:false,
|
||||||
subject: null,
|
subject: null,
|
||||||
questioncat: [],
|
questioncat: [],
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
<el-form-item label="工作类别" prop="name">
|
<el-form-item label="工作类别" prop="name">
|
||||||
<el-input v-model="Form.name" style="width:400px"></el-input>
|
<el-input v-model="Form.name" style="width:400px"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="是否可组织考试" prop="can_exam" label-width="120px">
|
||||||
|
<el-switch v-model="Form.can_exam"></el-switch>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="所属学科" prop="subject">
|
<el-form-item label="所属学科" prop="subject">
|
||||||
<el-select v-model="Form.subject" placeholder="请选择所属学科" style="width:400px">
|
<el-select v-model="Form.subject" placeholder="请选择所属学科" style="width:400px">
|
||||||
<el-option
|
<el-option
|
||||||
|
@ -57,6 +60,7 @@ export default {
|
||||||
return {
|
return {
|
||||||
Form: {
|
Form: {
|
||||||
name: "",
|
name: "",
|
||||||
|
can_exam:false,
|
||||||
subject: null,
|
subject: null,
|
||||||
questioncat: [],
|
questioncat: [],
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
# Generated by Django 3.0.4 on 2021-03-14 09:16
|
||||||
|
|
||||||
|
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 = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
('examtest', '0024_auto_20200402_2353'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='workscope',
|
||||||
|
name='can_exam',
|
||||||
|
field=models.BooleanField(default=False, verbose_name='是否可组织考试'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='examtest',
|
||||||
|
name='type',
|
||||||
|
field=models.CharField(choices=[('自助模考', '自助模考'), ('押卷模考', '押卷模考'), ('正式考试', '正式考试')], default='自助模考', max_length=50, verbose_name='考试类型'),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Exam',
|
||||||
|
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_delete', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
|
||||||
|
('code', models.CharField(blank=True, max_length=100, null=True, verbose_name='考试编号')),
|
||||||
|
('name', models.CharField(max_length=100, verbose_name='名称')),
|
||||||
|
('place', models.CharField(blank=True, max_length=100, null=True, verbose_name='考试地点')),
|
||||||
|
('opentime', models.DateTimeField(blank=True, null=True, verbose_name='开启时间')),
|
||||||
|
('closetime', models.DateTimeField(blank=True, null=True, verbose_name='关闭时间')),
|
||||||
|
('proctor_name', models.CharField(max_length=100, verbose_name='监考人姓名')),
|
||||||
|
('proctor_phone', models.CharField(max_length=100, verbose_name='监考人联系方式')),
|
||||||
|
('create_admin', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='exam_create_admin', to=settings.AUTH_USER_MODEL)),
|
||||||
|
('workscope', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='examtest.WorkScope', verbose_name='工作类别')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='examtest',
|
||||||
|
name='exam',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='examtest_exam', to='examtest.Exam', verbose_name='关联的正式考试'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,5 +1,5 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from rbac.models import SoftCommonModel, CommonModel
|
from rbac.models import SoftCommonModel, CommonModel, UserProfile
|
||||||
from django.contrib.postgres.fields import JSONField, ArrayField
|
from django.contrib.postgres.fields import JSONField, ArrayField
|
||||||
from question.models import Questioncat, Question
|
from question.models import Questioncat, Question
|
||||||
from crm.models import Consumer
|
from crm.models import Consumer
|
||||||
|
@ -7,7 +7,20 @@ from .models_paper import WorkScope, Paper
|
||||||
|
|
||||||
|
|
||||||
class Exam(CommonModel):
|
class Exam(CommonModel):
|
||||||
pass
|
"""
|
||||||
|
组织的正式考试
|
||||||
|
"""
|
||||||
|
code = models.CharField('考试编号', max_length=100, null=True, blank=True)
|
||||||
|
name = models.CharField('名称', max_length=100)
|
||||||
|
place = models.CharField('考试地点', max_length=100, null=True, blank=True)
|
||||||
|
workscope = models.ForeignKey(WorkScope, verbose_name='工作类别', on_delete= models.DO_NOTHING)
|
||||||
|
opentime = models.DateTimeField('开启时间', null=True, blank=True)
|
||||||
|
closetime = models.DateTimeField('关闭时间', null=True, blank=True)
|
||||||
|
proctor_name = models.CharField('监考人姓名', max_length=100)
|
||||||
|
proctor_phone = models.CharField('监考人联系方式', max_length=100)
|
||||||
|
create_admin = models.ForeignKey(UserProfile, on_delete=models.SET_NULL, null=True, blank=True, related_name='exam_create_admin')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ExamTest(CommonModel):
|
class ExamTest(CommonModel):
|
||||||
|
@ -17,6 +30,7 @@ class ExamTest(CommonModel):
|
||||||
type_choices = (
|
type_choices = (
|
||||||
('自助模考', '自助模考'),
|
('自助模考', '自助模考'),
|
||||||
('押卷模考', '押卷模考'),
|
('押卷模考', '押卷模考'),
|
||||||
|
('正式考试', '正式考试')
|
||||||
)
|
)
|
||||||
name = models.CharField(max_length=200, verbose_name='名称')
|
name = models.CharField(max_length=200, verbose_name='名称')
|
||||||
type = models.CharField(max_length=50, default='自助模考',choices = type_choices, verbose_name='考试类型')
|
type = models.CharField(max_length=50, default='自助模考',choices = type_choices, verbose_name='考试类型')
|
||||||
|
@ -31,6 +45,8 @@ class ExamTest(CommonModel):
|
||||||
end_time = models.DateTimeField(verbose_name='结束答题时间')
|
end_time = models.DateTimeField(verbose_name='结束答题时间')
|
||||||
detail = models.ManyToManyField(Question, related_name='答题记录', through='AnswerDetail')
|
detail = models.ManyToManyField(Question, related_name='答题记录', through='AnswerDetail')
|
||||||
is_pass = models.BooleanField(default=True, verbose_name='是否通过')
|
is_pass = models.BooleanField(default=True, verbose_name='是否通过')
|
||||||
|
|
||||||
|
exam = models.ForeignKey(Exam, verbose_name='关联的正式考试', null=True, blank=True, related_name='examtest_exam', on_delete= models.SET_NULL)
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = '模拟考试'
|
verbose_name = '模拟考试'
|
||||||
verbose_name_plural = verbose_name
|
verbose_name_plural = verbose_name
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.template.defaultfilters import default
|
||||||
from rbac.models import SoftCommonModel, CommonModel
|
from rbac.models import SoftCommonModel, CommonModel
|
||||||
from django.contrib.postgres.fields import JSONField, ArrayField
|
from django.contrib.postgres.fields import JSONField, ArrayField
|
||||||
from question.models import Questioncat, Question
|
from question.models import Questioncat, Question
|
||||||
|
@ -31,6 +32,7 @@ class WorkScope(CommonModel):
|
||||||
subject = models.ForeignKey(Questioncat, verbose_name='所属学科', on_delete=models.CASCADE , related_name='workscope_subject')
|
subject = models.ForeignKey(Questioncat, verbose_name='所属学科', on_delete=models.CASCADE , related_name='workscope_subject')
|
||||||
questioncat = models.ManyToManyField(Questioncat, verbose_name='所选科目')
|
questioncat = models.ManyToManyField(Questioncat, verbose_name='所选科目')
|
||||||
rule = models.ForeignKey(TestRule, on_delete=models.CASCADE, verbose_name='试卷结构')
|
rule = models.ForeignKey(TestRule, on_delete=models.CASCADE, verbose_name='试卷结构')
|
||||||
|
can_exam = models.BooleanField('是否可组织考试', default=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = '工作类别'
|
verbose_name = '工作类别'
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from question.models import Questioncat
|
from question.models import Questioncat
|
||||||
from crm.models import Consumer
|
from crm.models import Consumer
|
||||||
from .models import ExamTest, AnswerDetail, Banner
|
from .models import Exam, ExamTest, AnswerDetail, Banner
|
||||||
from .models_paper import TestRule, WorkScope, Paper, PaperQuestions
|
from .models_paper import TestRule, WorkScope, Paper, PaperQuestions
|
||||||
from question.serializers import QuestionSerializer
|
from question.serializers import QuestionSerializer
|
||||||
|
|
||||||
|
@ -163,3 +163,14 @@ class PaperQuestionsCreateSerializer(serializers.ModelSerializer):
|
||||||
model = PaperQuestions
|
model = PaperQuestions
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
|
class ExamCreateUpdateSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Exam
|
||||||
|
fields = ['name', 'place', 'opentime', 'closetime', 'proctor_name', 'proctor_phone', 'workscope']
|
||||||
|
|
||||||
|
class ExamListSerializer(serializers.ModelSerializer):
|
||||||
|
create_admin_username = serializers.StringRelatedField(source='create_admin')
|
||||||
|
workscope_name = serializers.StringRelatedField(source='workscope')
|
||||||
|
class Meta:
|
||||||
|
model = Exam
|
||||||
|
fields = '__all__'
|
|
@ -1,5 +1,5 @@
|
||||||
from django.urls import path,include
|
from django.urls import path,include
|
||||||
from .views import TestRuleViewSet, AnswerDetailView, WorkScopeViewSet, BannerViewSet, ExamTestViewSet, PaperViewSet
|
from .views import TestRuleViewSet, AnswerDetailView, WorkScopeViewSet, BannerViewSet, ExamTestViewSet, PaperViewSet, ExamViewSet
|
||||||
from rest_framework import routers
|
from rest_framework import routers
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ router.register('workscope', WorkScopeViewSet, basename="workscope")
|
||||||
router.register('banner', BannerViewSet, basename='banner')
|
router.register('banner', BannerViewSet, basename='banner')
|
||||||
router.register('examtest', ExamTestViewSet, basename='examtest')
|
router.register('examtest', ExamTestViewSet, basename='examtest')
|
||||||
router.register('paper', PaperViewSet, basename='paper')
|
router.register('paper', PaperViewSet, basename='paper')
|
||||||
|
router.register('exam', ExamViewSet, basename='exam')
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('answerdetail/', AnswerDetailView.as_view()),
|
path('answerdetail/', AnswerDetailView.as_view()),
|
||||||
|
|
|
@ -18,18 +18,59 @@ from question.models import Question
|
||||||
from question.serializers import QuestionSerializer
|
from question.serializers import QuestionSerializer
|
||||||
from server import settings
|
from server import settings
|
||||||
from utils.custom import CommonPagination
|
from utils.custom import CommonPagination
|
||||||
|
from utils.mixins import OptimizationMixin
|
||||||
|
|
||||||
from .exports import export_test
|
from .exports import export_test
|
||||||
from .models import AnswerDetail, Banner, ExamTest
|
from .models import AnswerDetail, Banner, ExamTest, Exam
|
||||||
from .models_paper import Paper, PaperQuestions, TestRule, WorkScope
|
from .models_paper import Paper, PaperQuestions, TestRule, WorkScope
|
||||||
from .serializers import (
|
from .serializers import (
|
||||||
AnswerDetailCreateSerializer, AnswerDetailSerializer, BannerSerializer,
|
AnswerDetailCreateSerializer, AnswerDetailSerializer, BannerSerializer,
|
||||||
ExamTestListSerializer, MoniTestSerializer, PaperDetailSerializer,
|
ExamTestListSerializer, MoniTestSerializer, PaperDetailSerializer,
|
||||||
PaperQuestionsCreateSerializer, PaperSerializer, TestRuleSerializer,
|
PaperQuestionsCreateSerializer, PaperSerializer, TestRuleSerializer,
|
||||||
WorkScopeSerializer)
|
WorkScopeSerializer, ExamCreateUpdateSerializer, ExamListSerializer)
|
||||||
|
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
|
|
||||||
|
class ExamViewSet(ModelViewSet):
|
||||||
|
"""
|
||||||
|
正式考试增删改查
|
||||||
|
"""
|
||||||
|
perms_map = [
|
||||||
|
{'get': 'exam_view'}, {'post': 'exam_create'},
|
||||||
|
{'put': 'exam_update'}, {'delete': 'exam_delete'}]
|
||||||
|
pagination_class = CommonPagination
|
||||||
|
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
||||||
|
ordering = ['-id']
|
||||||
|
search_fields = ['name']
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
queryset = Exam.objects.all()
|
||||||
|
if not self.request.user.is_superuser:
|
||||||
|
queryset = queryset.filter(create_admin = self.request.user)
|
||||||
|
if hasattr(self.get_serializer_class(), 'setup_eager_loading'):
|
||||||
|
queryset = self.get_serializer_class().setup_eager_loading(queryset) # 性能优化
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
def get_serializer_class(self):
|
||||||
|
if self.action in ['create', 'update']:
|
||||||
|
return ExamCreateUpdateSerializer
|
||||||
|
return ExamListSerializer
|
||||||
|
|
||||||
|
def create(self, request, *args, **kwargs):
|
||||||
|
serializer = self.get_serializer(data=request.data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
instance = serializer.save(create_admin=request.user)
|
||||||
|
instance.code = instance.pk + 10000
|
||||||
|
instance.save()
|
||||||
|
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||||
|
|
||||||
|
def destroy(self, request, *args, **kwargs):
|
||||||
|
instance = self.get_object()
|
||||||
|
if ExamTest.objects.filter(exam=instance).exists():
|
||||||
|
return Response({'error':'存在考试记录,禁止删除'})
|
||||||
|
instance.delete()
|
||||||
|
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||||
|
|
||||||
|
|
||||||
class AnswerDetailView(APIView):
|
class AnswerDetailView(APIView):
|
||||||
authentication_classes = []
|
authentication_classes = []
|
||||||
|
@ -56,8 +97,8 @@ class WorkScopeViewSet(ModelViewSet):
|
||||||
ordering_fields = ('id',)
|
ordering_fields = ('id',)
|
||||||
ordering = ['id']
|
ordering = ['id']
|
||||||
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
||||||
filterset_fields = ['subject']
|
filterset_fields = ['subject', 'can_exam']
|
||||||
search_fields = ('^name',)
|
search_fields = ('name',)
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
queryset = self.queryset
|
queryset = self.queryset
|
||||||
|
@ -102,6 +143,7 @@ class WorkScopeViewSet(ModelViewSet):
|
||||||
b3_set = queryset.filter(questioncat=questioncats[2], type='多选').order_by('?')[:b3]
|
b3_set = queryset.filter(questioncat=questioncats[2], type='多选').order_by('?')[:b3]
|
||||||
question_queryset = question_queryset|a1_set|a2_set|a3_set|b1_set|b2_set|b3_set
|
question_queryset = question_queryset|a1_set|a2_set|a3_set|b1_set|b2_set|b3_set
|
||||||
elif workscope.name == '辐射安全管理':
|
elif workscope.name == '辐射安全管理':
|
||||||
|
# 辐射安全管理出卷规则
|
||||||
queryset = Question.objects.filter(is_delete=0)
|
queryset = Question.objects.filter(is_delete=0)
|
||||||
a1_set = queryset.filter(questioncat=questioncats[0], type='单选').order_by('?')[:16]
|
a1_set = queryset.filter(questioncat=questioncats[0], type='单选').order_by('?')[:16]
|
||||||
a2_set = queryset.filter(questioncat=questioncats[1], type='单选').order_by('?')[:24]
|
a2_set = queryset.filter(questioncat=questioncats[1], type='单选').order_by('?')[:24]
|
||||||
|
@ -109,6 +151,7 @@ class WorkScopeViewSet(ModelViewSet):
|
||||||
b2_set = queryset.filter(questioncat=questioncats[1], type='多选').order_by('?')[:6]
|
b2_set = queryset.filter(questioncat=questioncats[1], type='多选').order_by('?')[:6]
|
||||||
question_queryset = question_queryset|a1_set|a2_set|b1_set|b2_set
|
question_queryset = question_queryset|a1_set|a2_set|b1_set|b2_set
|
||||||
elif workscope.name == '科研、生产及其他':
|
elif workscope.name == '科研、生产及其他':
|
||||||
|
# 科研、生产及其他出卷规则
|
||||||
queryset = Question.objects.filter(is_delete=0)
|
queryset = Question.objects.filter(is_delete=0)
|
||||||
a1_set = queryset.filter(questioncat=questioncats[0], type='单选').order_by('?')[:24]
|
a1_set = queryset.filter(questioncat=questioncats[0], type='单选').order_by('?')[:24]
|
||||||
a2_set = queryset.filter(questioncat=questioncats[1], type='单选').order_by('?')[:16]
|
a2_set = queryset.filter(questioncat=questioncats[1], type='单选').order_by('?')[:16]
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
from django.db.models.query import QuerySet
|
||||||
|
|
||||||
|
class CreateUpdateModelAMixin:
|
||||||
|
"""
|
||||||
|
业务用基本表A用
|
||||||
|
"""
|
||||||
|
def perform_create(self, serializer):
|
||||||
|
serializer.save(create_by = self.request.user)
|
||||||
|
|
||||||
|
def perform_update(self, serializer):
|
||||||
|
serializer.save(update_by = self.request.user)
|
||||||
|
|
||||||
|
class CreateUpdateModelBMixin:
|
||||||
|
"""
|
||||||
|
业务用基本表B用
|
||||||
|
"""
|
||||||
|
def perform_create(self, serializer):
|
||||||
|
serializer.save(create_by = self.request.user, belong_dept=self.request.user.dept)
|
||||||
|
|
||||||
|
def perform_update(self, serializer):
|
||||||
|
serializer.save(update_by = self.request.user)
|
||||||
|
|
||||||
|
class CreateUpdateCustomMixin:
|
||||||
|
"""
|
||||||
|
整合
|
||||||
|
"""
|
||||||
|
def perform_create(self, serializer):
|
||||||
|
if hasattr(self.queryset.model, 'belong_dept'):
|
||||||
|
serializer.save(create_by = self.request.user, belong_dept=self.request.user.dept)
|
||||||
|
else:
|
||||||
|
serializer.save(create_by = self.request.user)
|
||||||
|
def perform_update(self, serializer):
|
||||||
|
serializer.save(update_by = self.request.user)
|
||||||
|
|
||||||
|
class OptimizationMixin:
|
||||||
|
"""
|
||||||
|
性能优化,需要在序列化器里定义setup_eager_loading,可在必要的View下继承
|
||||||
|
"""
|
||||||
|
def get_queryset(self):
|
||||||
|
queryset = self.queryset
|
||||||
|
if isinstance(queryset, QuerySet):
|
||||||
|
# Ensure queryset is re-evaluated on each request.
|
||||||
|
queryset = queryset.all()
|
||||||
|
if hasattr(self.get_serializer_class(), 'setup_eager_loading'):
|
||||||
|
queryset = self.get_serializer_class().setup_eager_loading(queryset) # 性能优化
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
from sympy import *
|
Loading…
Reference in New Issue