创建正式考试
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({
|
||||
url: '/examtest/workscope/',
|
||||
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',
|
||||
component: Layout,
|
||||
|
@ -268,6 +283,7 @@ export const asyncRoutes = [
|
|||
},
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: '/qtest',
|
||||
component: Layout,
|
||||
|
|
|
@ -64,9 +64,61 @@ div:focus {
|
|||
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 {
|
||||
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{
|
||||
// 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"
|
||||
>
|
||||
<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>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="所属学科">
|
||||
<el-table-column label="所属学科">
|
||||
<template slot-scope="scope">
|
||||
<el-tag type="success" >{{scope.row.subject_name}}</el-tag>
|
||||
</template>
|
||||
</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="创建日期">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.create_time }}</span>
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
<el-form-item label="工作类别" prop="name">
|
||||
<el-input v-model="Form.name" style="width:400px"></el-input>
|
||||
</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-select v-model="Form.subject" placeholder="请选择所属学科" style="width:400px">
|
||||
<el-option
|
||||
|
@ -57,6 +60,7 @@ export default {
|
|||
return {
|
||||
Form: {
|
||||
name: "",
|
||||
can_exam:false,
|
||||
subject: null,
|
||||
questioncat: [],
|
||||
},
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
<el-form-item label="工作类别" prop="name">
|
||||
<el-input v-model="Form.name" style="width:400px"></el-input>
|
||||
</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-select v-model="Form.subject" placeholder="请选择所属学科" style="width:400px">
|
||||
<el-option
|
||||
|
@ -57,6 +60,7 @@ export default {
|
|||
return {
|
||||
Form: {
|
||||
name: "",
|
||||
can_exam:false,
|
||||
subject: null,
|
||||
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 rbac.models import SoftCommonModel, CommonModel
|
||||
from rbac.models import SoftCommonModel, CommonModel, UserProfile
|
||||
from django.contrib.postgres.fields import JSONField, ArrayField
|
||||
from question.models import Questioncat, Question
|
||||
from crm.models import Consumer
|
||||
|
@ -7,7 +7,20 @@ from .models_paper import WorkScope, Paper
|
|||
|
||||
|
||||
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):
|
||||
|
@ -17,6 +30,7 @@ class ExamTest(CommonModel):
|
|||
type_choices = (
|
||||
('自助模考', '自助模考'),
|
||||
('押卷模考', '押卷模考'),
|
||||
('正式考试', '正式考试')
|
||||
)
|
||||
name = models.CharField(max_length=200, 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='结束答题时间')
|
||||
detail = models.ManyToManyField(Question, related_name='答题记录', through='AnswerDetail')
|
||||
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:
|
||||
verbose_name = '模拟考试'
|
||||
verbose_name_plural = verbose_name
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from django.db import models
|
||||
from django.template.defaultfilters import default
|
||||
from rbac.models import SoftCommonModel, CommonModel
|
||||
from django.contrib.postgres.fields import JSONField, ArrayField
|
||||
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')
|
||||
questioncat = models.ManyToManyField(Questioncat, verbose_name='所选科目')
|
||||
rule = models.ForeignKey(TestRule, on_delete=models.CASCADE, verbose_name='试卷结构')
|
||||
can_exam = models.BooleanField('是否可组织考试', default=False)
|
||||
|
||||
class Meta:
|
||||
verbose_name = '工作类别'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from rest_framework import serializers
|
||||
from question.models import Questioncat
|
||||
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 question.serializers import QuestionSerializer
|
||||
|
||||
|
@ -163,3 +163,14 @@ class PaperQuestionsCreateSerializer(serializers.ModelSerializer):
|
|||
model = PaperQuestions
|
||||
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 .views import TestRuleViewSet, AnswerDetailView, WorkScopeViewSet, BannerViewSet, ExamTestViewSet, PaperViewSet
|
||||
from .views import TestRuleViewSet, AnswerDetailView, WorkScopeViewSet, BannerViewSet, ExamTestViewSet, PaperViewSet, ExamViewSet
|
||||
from rest_framework import routers
|
||||
|
||||
|
||||
|
@ -9,6 +9,7 @@ router.register('workscope', WorkScopeViewSet, basename="workscope")
|
|||
router.register('banner', BannerViewSet, basename='banner')
|
||||
router.register('examtest', ExamTestViewSet, basename='examtest')
|
||||
router.register('paper', PaperViewSet, basename='paper')
|
||||
router.register('exam', ExamViewSet, basename='exam')
|
||||
|
||||
urlpatterns = [
|
||||
path('answerdetail/', AnswerDetailView.as_view()),
|
||||
|
|
|
@ -18,18 +18,59 @@ from question.models import Question
|
|||
from question.serializers import QuestionSerializer
|
||||
from server import settings
|
||||
from utils.custom import CommonPagination
|
||||
from utils.mixins import OptimizationMixin
|
||||
|
||||
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 .serializers import (
|
||||
AnswerDetailCreateSerializer, AnswerDetailSerializer, BannerSerializer,
|
||||
ExamTestListSerializer, MoniTestSerializer, PaperDetailSerializer,
|
||||
PaperQuestionsCreateSerializer, PaperSerializer, TestRuleSerializer,
|
||||
WorkScopeSerializer)
|
||||
WorkScopeSerializer, ExamCreateUpdateSerializer, ExamListSerializer)
|
||||
|
||||
# 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):
|
||||
authentication_classes = []
|
||||
|
@ -56,8 +97,8 @@ class WorkScopeViewSet(ModelViewSet):
|
|||
ordering_fields = ('id',)
|
||||
ordering = ['id']
|
||||
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
||||
filterset_fields = ['subject']
|
||||
search_fields = ('^name',)
|
||||
filterset_fields = ['subject', 'can_exam']
|
||||
search_fields = ('name',)
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = self.queryset
|
||||
|
@ -102,6 +143,7 @@ class WorkScopeViewSet(ModelViewSet):
|
|||
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
|
||||
elif workscope.name == '辐射安全管理':
|
||||
# 辐射安全管理出卷规则
|
||||
queryset = Question.objects.filter(is_delete=0)
|
||||
a1_set = queryset.filter(questioncat=questioncats[0], type='单选').order_by('?')[:16]
|
||||
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]
|
||||
question_queryset = question_queryset|a1_set|a2_set|b1_set|b2_set
|
||||
elif workscope.name == '科研、生产及其他':
|
||||
# 科研、生产及其他出卷规则
|
||||
queryset = Question.objects.filter(is_delete=0)
|
||||
a1_set = queryset.filter(questioncat=questioncats[0], type='单选').order_by('?')[:24]
|
||||
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