test part1

This commit is contained in:
caoqianming 2020-03-18 20:02:43 +08:00
parent abc1687ea2
commit e11d011c7f
29 changed files with 812 additions and 98 deletions

View File

@ -73,11 +73,11 @@ export function getQuestionList(query) {
})
}
export function getQuestionCount(query) {
export function getQuestionCount(data) {
return request({
url: '/question/question/count/',
method: 'get',
params: query
method: 'post',
data
})
}

View File

@ -26,6 +26,11 @@
<el-table-column align="center" label="简述">
<template slot-scope="scope">{{ scope.row.desc }}</template>
</el-table-column>
<el-table-column align="center" label="所属学科">
<template slot-scope="scope">
<el-tag type="success" v-if="scope.row.subject">{{scope.row.subject.name}}</el-tag>
</template>
</el-table-column>
<el-table-column label="创建日期">
<template slot-scope="scope">
<span>{{ scope.row.create_time }}</span>
@ -33,13 +38,13 @@
</el-table-column>
<el-table-column align="center" label="操作">
<template slot-scope="scope">
<el-button
<!-- <el-button
type="primary"
size="small"
@click="handleEdit(scope)"
icon="el-icon-edit"
:disabled="!checkPermission(['testrule_update'])"
></el-button>
></el-button> -->
<el-button
type="danger"
size="small"
@ -56,9 +61,7 @@
<script>
import {
getTestRuleAll,
createTestRule,
delteTestRule,
updateTestRule
deleteTestRule
} from "@/api/examtest";
import checkPermission from "@/utils/permission";
@ -94,21 +97,20 @@ export default {
},
handleDelete(scope) {
this.$confirm("确认删除该分类吗?将丢失数据!", "警告", {
confirmButtonText: "确认",
cancelButtonText: "取消",
type: "error"
})
.then(async () => {
await delteTestRule(scope.row.id);
this.getList();
this.$message({
type: "success",
message: "成功删除!"
});
})
.catch(err => {
// console.error(err);
this.$confirm('此操作将永久删除该规则, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
deleteTestRule(scope.row.id).then(response => {
this.$message({
type: 'success',
message: '删除成功!'
});
this.getList()
});
}).catch(() => {
});
},
}

View File

@ -1,20 +1,20 @@
<template>
<div class="app-container">
<el-form
:model="ruleForm"
:model="Form"
:rules="rules"
ref="ruleForm"
ref="Form"
label-width="100px"
class="demo-ruleForm"
status-icon
>
<el-form-item label="规则名称" prop="name">
<el-input v-model="ruleForm.name" style="width:400px"></el-input>
<el-input v-model="Form.name" style="width:400px"></el-input>
</el-form-item>
<el-form-item label="规则简述" prop="desc">
<el-input v-model="ruleForm.desc" style="width:400px" type="textarea"></el-input>
<el-input v-model="Form.desc" style="width:400px" type="textarea"></el-input>
</el-form-item>
<el-form-item label="所属学科" prop="subject">
<el-select v-model="ruleForm.subject" placeholder="请选择所属学科" style="width:400px" @change="getQuestioncatAll()">
<el-select v-model="Form.subject" placeholder="请选择所属学科" style="width:400px" @change="getQuestioncatAll">
<el-option
v-for="item in subjectData"
:key="item.value"
@ -25,8 +25,8 @@
</el-form-item>
<el-form-item label="题库范围" prop="questioncat">
<el-select
v-model="ruleForm.questioncat" multiple placeholder="请选择题库范围" style="width:400px"
@blur="getQuestionCount()">
v-model="Form.questioncat" multiple placeholder="请选择题库范围" style="width:400px"
@visible-change="getQuestionCount">
<el-option
v-for="item in questioncatData"
:key="item.value"
@ -36,32 +36,33 @@
</el-select>
</el-form-item>
<el-form-item label="单选题">
共有<span style="color:orange;font-weight:bold">{{typecount.danxuan}}</span>,选取
<el-input v-model="ruleForm.detail.danxuan.count" style="width:60px" @input="calScore()"></el-input>,每道
<el-input v-model="ruleForm.detail.danxuan.score" style="width:60px" @input="calScore()"></el-input>
共有<span style="color:darkred;font-weight:bold"> {{typecount.danxuan}} </span>,选取
<el-input-number v-model="Form.danxuan_count" @change="calScore" :min="0" :max="maxDanxuan()"></el-input-number>,每道
<el-input-number v-model="Form.danxuan_score" @change="calScore" :min="0"></el-input-number>
</el-form-item>
<el-form-item label="多选题">
共有<span style="color:orange;font-weight:bold">{{typecount.duoxuan}}</span>,选取
<el-input v-model="ruleForm.detail.duoxuan.count" style="width:60px" @input="calScore()"></el-input>,每道
<el-input v-model="ruleForm.detail.duoxuan.score" style="width:60px" @input="calScore()"></el-input>
共有<span style="color:darkred;font-weight:bold"> {{typecount.duoxuan}} </span>,选取
<el-input-number v-model="Form.duoxuan_count" @change="calScore" :min="0" :max="maxDuoxuan()"></el-input-number>,每道
<el-input-number v-model="Form.duoxuan_score" @change="calScore" :min="0"></el-input-number>
</el-form-item>
<el-form-item label="判断题">
共有<span style="color:orange;font-weight:bold">{{typecount.panduan}}</span>,选取
<el-input v-model="ruleForm.detail.panduan.count" style="width:60px" @input="calScore()"></el-input>,每道
<el-input v-model="ruleForm.detail.panduan.score" style="width:60px" @input="calScore()"></el-input>
共有<span style="color:darkred;font-weight:bold"> {{typecount.panduan}} </span>,选取
<el-input-number v-model="Form.panduan_count" @change="calScore" :min="0" :max="maxPanduan()"></el-input-number>,每道
<el-input-number v-model="Form.panduan_score" @change="calScore" :min="0"></el-input-number>
</el-form-item>
<el-form-item label="时间限制" prop="duration">
<el-input v-model="ruleForm.detail.panduan.duration" style="width:60px"></el-input>分钟
<el-form-item label="时间限制" prop="limit">
<el-input-number v-model="Form.limit" :min="0"></el-input-number>分钟
</el-form-item>
<el-form-item label="当前总分">
<span style="color:orange;font-weight:bold">{{ruleForm.detail.score}}</span>
<span style="color:darkred;font-weight:bold">{{Form.totalscore}} </span>
</el-form-item>
<el-form-item label="及格分数" prop="passscore">
<el-input v-model="ruleForm.detail.panduan.passscore" style="width:60px"></el-input>
<el-input-number v-model="Form.passscore" :min="0"></el-input-number>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')">立即创建</el-button>
<el-button @click="resetForm('ruleForm')">重置</el-button>
<el-button type="primary" @click="submitForm('Form')" :loading="submitLoding">立即创建</el-button>
<el-button @click="resetForm('Form')">重置</el-button>
<el-button type="warning" @click="goBack()">返回</el-button>
</el-form-item>
</el-form>
</div>
@ -73,27 +74,20 @@ import { genTree } from "@/utils";
export default {
data() {
return {
ruleForm: {
Form: {
name: "",
desc:"",
subject: null,
questioncat: [],
detail: {
danxuan: {
count: 0,
score: 0
},
duoxuan: {
count: 0,
score: 0
},
panduan: {
count: 0,
score: 0
},
duration: 0,
score: 0,
passscore: 0
}
danxuan_count:0,
danxuan_score:0,
duoxuan_count:0,
duoxuan_score:0,
panduan_count:0,
panduan_score:0,
limit:0,
totalscore:0,
passscore:0
},
typecount:{
danxuan:0,
@ -102,19 +96,22 @@ export default {
},
subjectData:[],
questioncatData:[],
submitLoding:false,
rules: {
name: [
{ required: true, message: "请输入名称", trigger: "blur" }
{ required: true, message: "名称不能为空", trigger: "blur" }
// { min: 3, max: 5, message: ' 3 5 ', trigger: 'blur' }
],
questioncat: [
{ required: true, message: "请选择题库范围", trigger: "change" }
{ required: true, message: "题库范围不能为空", trigger: "change" }
],
duration: [
{ type: 'number', required: true, message: "请填写时间限制", trigger: "blur" }
limit: [
{ required: true, message: "时间限制不能为空"},
{ type: "number", message: "时间限制必须是数字"}
],
passscore: [
{ type: 'number', required: true, message: "请填写及格分数", trigger: "blur" }
{ required: true, message: "及格分数不能为空"},
{ type: "number", message: "及格分数必须是数字"}
]
}
@ -124,12 +121,28 @@ export default {
this.getSubjectAll();
},
methods: {
maxDanxuan() {
return this.typecount.danxuan
},
maxDuoxuan() {
return this.typecount.duoxuan
},
maxPanduan() {
return this.typecount.panduan
},
submitForm(formName) {
this.$refs[formName].validate(valid => {
if (valid) {
alert("submit!");
this.submitLoding = true
createTestRule(this.Form).then(response => {
this.submitLoding = false
this.$message({
type: "success",
message: "新建成功!"
});
this.goBack()
});
} else {
console.log("error submit!!");
return false;
}
});
@ -139,24 +152,29 @@ export default {
this.subjectData = genTree(response.data) ;
});
},
getQuestioncatAll() {
getQuestioncatAll({pid:this.ruleForm.subject}).then(response => {
getQuestioncatAll(val) {
getQuestioncatAll({pid:val}).then(response => {
this.questioncatData = genTree(response.data) ;
});
},
getQuestionCount() {
console.log(this.ruleForm.questioncat)
// getQuestionCount({ids:this.ruleForm.questioncat}).then(response => {
// this.typecount = response.data
// });
getQuestionCount(val) {
if (val==false){
getQuestionCount({ids:this.Form.questioncat}).then(response => {
this.typecount = response.data
});
}
},
calScore() {
let detail = this.ruleForm.detail
let score = detail.danxuan.count * detail.danxuan.score + detail.duoxuan.count * detail.duoxuan.score + detail.panduan.count * detail.panduan.score
this.ruleForm.detail.score = score
calScore(current,old) {
let form = this.Form
let score = form.danxuan_count * form.danxuan_score + form.duoxuan_count * form.duoxuan_score + form.panduan_count * form.panduan_score
this.Form.totalscore = score
},
resetForm(formName) {
this.$refs[formName].resetFields();
},
goBack() {
this.$router.replace('/sjmanage/testrule/')
}
}
};

View File

@ -8,7 +8,10 @@
"pages/subject/index",
"pages/lianxi/main",
"pages/about/about",
"pages/cuoti/index"
"pages/cuoti/index",
"pages/moni/index",
"pages/moni/note",
"pages/test/test"
],
"window": {
"backgroundTextStyle": "light",

View File

@ -28,6 +28,7 @@ Page({
*/
onLoad: function (options) {
var that = this
wx.showLoading({})
try {
var value = wx.getStorageSync('ctms')
if (value) {
@ -36,7 +37,8 @@ Page({
tmtotal: value.length
})
}
} catch (e) { }
wx.hideLoading()
} catch (e) { wx.hideLoading()}
try {
const res = wx.getSystemInfoSync()
that.setData({

View File

@ -6,7 +6,7 @@
<block wx:for="{{questioncatData}}" wx:key="unique">
<view class="weui-media-box weui-media-box_appmsg">
<view class="weui-media-box__hd">
<image class="weui-media-box__thumb" src="/image/fushe.svg" alt></image>
<image class="weui-media-box__thumb" src="/images/fushe.svg" alt></image>
</view>
<view class="weui-media-box__bd">
<h4 class="weui-media-box__title">{{item.name}}</h4>

View File

@ -129,5 +129,19 @@ Page({
duration: 1500
})
}
},
goMoni: function () {
let nowSubject = wx.getStorageSync('nowSubject')
if (nowSubject) {
wx.navigateTo({
url: '/pages/moni/index',
})
} else {
wx.showToast({
title: '请先选择学科',
icon: 'none',
duration: 1500
})
}
}
})

View File

@ -41,9 +41,9 @@
<view class="weui-cells__title">考试</view>
<view class="weui-cells weui-cells_after-title">
<view class="weui-grids">
<a class="weui-grid" bindtap="goLianxi">
<a class="weui-grid" bindtap="goMoni">
<view class="weui-grid__icon">
<image src="/image/moni.svg" alt></image>
<image src="/images/moni.svg" alt></image>
</view>
<view class="weui-grid__label">模拟考试</view>
</a>

View File

@ -0,0 +1,103 @@
// pages/lianxi/index.js
const api = require("../../utils/request.js");
Page({
/**
* 页面的初始数据
*/
data: {
ruleData: [],
isLoad: true
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function () {
try {
var value = wx.getStorageSync('nowSubject')
if (value) {
this.setData({
subjectId: value.id
})
}
} catch (e) {
wx.navigateBack({
})
}
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
this.getList()
},
getList: function () {
var that = this
api.request('examtest/testrule/', 'GET', { 'subject': that.data.subjectId }).then(res => {
if (res.code == 200) {
if (res.data.length > 0) {
that.setData({
ruleData: res.data
})
}
}
})
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
},
genPaper: function (e) {
wx.showLoading({
title: '正在生成试卷',
})
api.request('examtest/monitest/', 'GET', { 'rule': e.currentTarget.id }).then(res => {
try {
wx.setStorageSync('monitest', res.data)
} catch (e) { }
wx.redirectTo({
url: 'note',
})
})
},
})

View File

@ -0,0 +1,4 @@
{
"usingComponents": {},
"navigationBarTitleText": "出题规则"
}

View File

@ -0,0 +1,19 @@
<!--pages/lianxi/index.wxml-->
<view class="page">
<view class="page__bd">
<view class="weui-panel__hd">当前学科出题规则</view>
<view class="weui-panel__bd">
<block wx:for="{{ruleData}}" wx:key="unique">
<view class="weui-media-box weui-media-box_appmsg">
<view class="weui-media-box__bd">
<h4 class="weui-media-box__title">{{item.name}}</h4>
<view class="weui-media-box__desc">{{item.desc}}</view>
<view class="weui-media-box__desc">
<a class="weui-btn weui-btn_mini weui-btn_primary" bindtap="genPaper" id="{{item.id}}" >生成考试</a>
</view>
</view>
</view>
</block>
</view>
</view>
</view>

View File

@ -0,0 +1 @@
/* pages/moni/index.wxss */

View File

@ -0,0 +1,77 @@
// pages/examtest/note.js
var util = require('../../utils/util.js')
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function () {
try {
var value = wx.getStorageSync('monitest')
if (value) {
let monitest = value
delete monitest['questions']
this.setData(monitest)
}
} catch (e) { }
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
},
startTest: function () {
wx.redirectTo({
url: '/pages/test/test',
})
},
})

View File

@ -0,0 +1,4 @@
{
"usingComponents": {},
"navigationBarTitleText": "考试须知"
}

View File

@ -0,0 +1,22 @@
<view class="page">
<view class="page__bd">
<view class="weui-article">
<view class="weui-article__h1">考试须知</view>
<view class="weui-article__h2">1.考试详情</view>
<view>名称:<span style="color:blue">{{name}}</span></view>
<view>答卷时长:<span style="color:red">{{limit}}分钟</span></view>
<view wx:if="{{danxuan_count>0}}">{{danxuan_count}}道单选题,每题{{danxuan_score}}分</view>
<view wx:if="{{duoxuan_count>0}}">{{duoxuan_count}}道单选题,每题{{duoxuan_score}}分</view>
<view wx:if="{{panduan_count>0}}">{{panduan_count}}道单选题,每题{{panduan_score}}分</view>
<view >满分{{totalscore}};{{passscore}}以上通过</view>
</view>
<view class="weui-article">
<view class="weui-article__h2">2.答题须知</view>
<view style="color:red">进入答题后请不要后退或返回桌面</view>
<view>用户可点击上一题/下一题进行切换答题</view>
<view>可点击答题卡复查</view>
<view>请合理安排时间答题,可提前交卷,超时会自动提交</view>
</view>
</view>
<a class="weui-btn weui-btn_primary" bindtap="startTest">开始考试</a>
</view>

View File

@ -0,0 +1 @@
/* pages/moni/note.wxss */

View File

@ -7,7 +7,7 @@
<block wx:for="{{subjectData}}" wx:key="unique">
<a class="weui-media-box weui-media-box_appmsg" bindtap="chooseSubject" data-id="{{item.id}}" data-name="{{item.name}}">
<view class="weui-media-box__hd">
<image class="weui-media-box__thumb" src="/image/fushe.svg" alt></image>
<image class="weui-media-box__thumb" src="/images/fushe.svg" alt></image>
</view>
<view class="weui-media-box__bd">
<h4 class="weui-media-box__title">{{item.name}}</h4>

View File

@ -0,0 +1,157 @@
// pages/lianxi/main.js
const api = require("../../utils/request.js");
var util = require('../../utils/util.js')
Page({
/**
* 页面的初始数据
*/
data: {
tms:[],
tmIndex: 0,
},
radioChange: function (e) {
var that = this
that.data.currentTm['userChecked'] = e.detail.value
that.data.tms[that.data.tmIndex] = that.data.currentTm
},
checkboxChange: function (e) {
var that = this
that.data.currentTm['userChecked'] = e.detail.value
that.data.tms[that.data.tmIndex] = that.data.currentTm
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function () {
var that = this
try {
var value = wx.getStorageSync('monitest')
if (value) {
that.data.monitest = value
that.data.tms = value.questions
that.setData({
tmtotal:value.questions.length
})
that.showTm(that.data.tmIndex)
}
} catch (e) { }
try {
const res = wx.getSystemInfoSync()
that.setData({
scrollHeight: res.windowHeight - 70
})
} catch (e) {
}
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
wx.hideHomeButton({})
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
},
showTm: function (index) {
var that = this
var currentTm = that.data.tms[index]
that.setData({
'tmIndex': index,
'currentTm': currentTm
})
that.showOptions()
},
// panTi: function () {
// var that = this
// let currentTm = that.data.currentTm
// let isright = false
// if (currentTm.type == 2) {
// if (currentTm.userChecked) {
// if (currentTm.userChecked.sort().toString() == currentTm.right.sort().toString()) {
// isright = true
// }
// }
// } else {
// isright = currentTm.right == currentTm.userChecked
// }
// if (isright == false && currentTm.userChecked != undefined) {
// currentTm.dtime = util.formatTime(new Date())
// that.data.ctms.unshift(currentTm)
// if (that.data.ctms.length > 40) {
// that.data.ctms.length = 40
// }
// }
// return isright
// },
next: function () {
var that = this
var tmIndex = that.data.tmIndex + 1
that.showTm(tmIndex)
},
previous: function () {
var that = this
var tmIndex = that.data.tmIndex - 1
that.showTm(tmIndex)
},
showOptions: function () {
let currentTm = this.data.currentTm
let options = []
for (let key in currentTm.options) {
let option = {}
option.key = key
option.value = key + ':' + currentTm.options[key]
if (currentTm.userChecked) {
if (key == currentTm.userChecked || currentTm.userChecked.indexOf(key) != -1) {
option.checked = true
}
} else {
option.checked = false
}
options.push(option)
}
this.setData({
options: options
})
},
})

View File

@ -0,0 +1,4 @@
{
"usingComponents": {},
"navigationBarTitleText": "考试中"
}

View File

@ -0,0 +1,55 @@
<view class="head">
题量: {{tmIndex+1}}/{{tmtotal}}
</view>
<scroll-view scroll-y="true" style="height: {{scrollHeight}}px;">
<view class="weui-article">
<view class="weui-article__h2">{{tmIndex+1}}.
<span wx:if="{{currentTm.type==1}}" class="txlabel">单选题</span>
<span wx:if="{{currentTm.type==2}}" class="txlabel">多选题</span>
<span wx:if="{{currentTm.type==3}}" class="txlabel">判断题</span>
<span>({{currentTm.score}}分)</span>
</view>
<view class="weui-article__title">{{currentTm.name}}</view>
</view>
<view class="weui-cells weui-cells_radio">
<radio-group class="radio-group" bindchange="radioChange" wx:if="{{(currentTm.type==1 ||currentTm.type==3)}}">
<label class="weui-cell weui-cell_active weui-check__label" wx:for="{{options}}" wx:key="key">
<view class="weui-cell__bd">
<view>{{item.value}}</view>
</view>
<view class="weui-cell__ft">
<radio class="weui-check" value="{{item.key}}" checked="{{item.checked}}" />
<i class="weui-icon-checked"></i>
</view>
</label>
</radio-group>
</view>
<view class="weui-cells weui-cells_checkbox">
<checkbox-group bindchange="checkboxChange" wx:if="{{currentTm.type==2}}">
<label class="weui-cell weui-cell_active weui-check__label" wx:for="{{options}}" wx:key="key">
<view class="weui-cell__bd">
<view>{{item.value}}</view>
</view>
<view class="weui-cell__hd">
<checkbox class="weui-check" value="{{item.key}}" checked="{{item.checked}}"/>
<i class="weui-icon-checked"></i>
</view>
</label>
</checkbox-group>
</view>
</scroll-view>
<view class="btns">
<view style="width:25%">
<button type="primary" size="mini" bindtap="previous" disabled="{{tmIndex==0}}">上题</button>
</view>
<view style="width:25%">
<button type="primary" size="mini" bindtap="next" disabled="{{tmIndex==tmtotal-1}}">下题</button>
</view>
<view style="width:25%">
<button type="primary" size="mini" bindtap="showAnswer">答题卡</button>
</view>
<view style="width:25%">
<a class="weui-btn weui-btn_mini weui-btn_warn">交卷</a>
</view>
</view>

View File

@ -0,0 +1,20 @@
.head{
width:100%;
height:30px;
color:#fff;
background-color: cornflowerblue;
text-align: center;
}
.btns{
height:40px;
display:flex;
flex-direction: row;
flex-wrap: wrap;
text-align:center;
}
.txlabel{
color:#fff;
background-color: rgb(216, 140, 0);
padding: 2px
}

View File

@ -0,0 +1,57 @@
# Generated by Django 3.0.4 on 2020-03-18 01:38
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('examtest', '0003_auto_20200317_2157'),
]
operations = [
migrations.RemoveField(
model_name='testrule',
name='detail',
),
migrations.AddField(
model_name='testrule',
name='danxuan_count',
field=models.IntegerField(default=0, verbose_name='单选数量'),
),
migrations.AddField(
model_name='testrule',
name='danxuan_score',
field=models.IntegerField(default=0, verbose_name='单选分数'),
),
migrations.AddField(
model_name='testrule',
name='duoxuan_count',
field=models.IntegerField(default=0, verbose_name='多选数量'),
),
migrations.AddField(
model_name='testrule',
name='duoxuan_score',
field=models.IntegerField(default=0, verbose_name='多选分数'),
),
migrations.AddField(
model_name='testrule',
name='panduan_count',
field=models.IntegerField(default=0, verbose_name='判断数量'),
),
migrations.AddField(
model_name='testrule',
name='panduan_score',
field=models.IntegerField(default=0, verbose_name='判断分数'),
),
migrations.AddField(
model_name='testrule',
name='passscore',
field=models.IntegerField(default=0, verbose_name='及格分数'),
),
migrations.AddField(
model_name='testrule',
name='score',
field=models.IntegerField(default=0, verbose_name='总分'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 3.0.4 on 2020-03-18 01:48
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('examtest', '0004_auto_20200318_0938'),
]
operations = [
migrations.AddField(
model_name='testrule',
name='limit',
field=models.IntegerField(default=0, verbose_name='限时(分钟)'),
),
]

View File

@ -0,0 +1,22 @@
# Generated by Django 3.0.4 on 2020-03-18 08:34
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('examtest', '0005_testrule_limit'),
]
operations = [
migrations.RemoveField(
model_name='testrule',
name='score',
),
migrations.AddField(
model_name='testrule',
name='totalscore',
field=models.IntegerField(default=0, verbose_name='满分'),
),
]

View File

@ -9,4 +9,12 @@ class TestRule(CommonModel):
desc = models.TextField(verbose_name='描述', default='')
subject = models.ForeignKey(Questioncat, blank=True, null=True, on_delete=models.CASCADE, verbose_name='所属学科', related_name='subject')
questioncat = models.ManyToManyField(Questioncat, verbose_name='所选题库')
detail = JSONField(verbose_name='试卷结构')
danxuan_count = models.IntegerField(default=0, verbose_name='单选数量')
danxuan_score = models.IntegerField(default=0, verbose_name='单选分数')
duoxuan_count = models.IntegerField(default=0, verbose_name='多选数量')
duoxuan_score = models.IntegerField(default=0, verbose_name='多选分数')
panduan_count = models.IntegerField(default=0, verbose_name='判断数量')
panduan_score = models.IntegerField(default=0, verbose_name='判断分数')
limit = models.IntegerField(default=0, verbose_name='限时(分钟)')
totalscore = models.IntegerField(default=0, verbose_name='满分')
passscore = models.IntegerField(default=0, verbose_name='及格分数')

View File

@ -4,9 +4,31 @@ from .models import TestRule
class TestRuleListSerializer(serializers.ModelSerializer):
"""
规则列表序列化
"""
create_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False, read_only=True)
update_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False, read_only=True)
class Meta:
model = TestRule
fields = ('id', 'name', 'create_time', 'update_time', 'subject', 'desc')
depth = 1
class TestRuleCreateSerializer(serializers.ModelSerializer):
"""
规则创建序列化
"""
create_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False, read_only=True)
update_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False, read_only=True)
class Meta:
model = TestRule
fields = '__all__'
class TestRuleSerializer(serializers.ModelSerializer):
"""
学科分类序列化
规则序列化
"""
create_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False, read_only=True)
update_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False, read_only=True)
@ -16,4 +38,5 @@ class TestRuleSerializer(serializers.ModelSerializer):
depth = 1

View File

@ -1,5 +1,5 @@
from django.urls import path,include
from .views import TestRuleViewSet
from .views import TestRuleViewSet, MoniTestView
from rest_framework import routers
@ -7,5 +7,6 @@ router = routers.DefaultRouter()
router.register('testrule', TestRuleViewSet, basename="testrule")
urlpatterns = [
path('monitest/',MoniTestView.as_view()),
path('', include(router.urls)),
]

View File

@ -9,15 +9,63 @@ from rest_framework import status
from django_filters.rest_framework import DjangoFilterBackend
from openpyxl import Workbook, load_workbook
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from datetime import datetime
from utils.custom import CommonPagination
from rbac.permission import RbacPermission
from question.models import Question
from question.serializers import QuestionSerializer
from .models import TestRule
from .serializers import TestRuleSerializer
from .serializers import TestRuleSerializer, TestRuleListSerializer, TestRuleCreateSerializer
from server import settings
from crm.authentication import ConsumerTokenAuthentication
# Create your views here.
class MoniTestView(APIView):
authentication_classes = [ConsumerTokenAuthentication]
permission_classes = []
def get(self, request, *args, **kwargs):
if request.query_params.get('rule', None):
ret = {}
testrule = TestRule.objects.get(id = request.query_params.get('rule'))
ret['name'] = '自助模考' + datetime.now().strftime('%Y%m%d%H%M')
ret['type'] = 1 # 自助模拟考试
ret['rule'] = testrule.id
ret['limit'] = testrule.limit
ret['totalscore'] = testrule.totalscore
ret['passscore'] = testrule.passscore
ret['danxuan_count'] = testrule.danxuan_count
ret['danxuan_score'] = testrule.danxuan_score
ret['duoxuan_count'] = testrule.duoxuan_count
ret['duoxuan_score'] = testrule.duoxuan_score
ret['panduan_count'] = testrule.panduan_count
ret['panduan_score'] = testrule.panduan_score
question_queryset = Question.objects.none()
queryset = Question.objects.filter(is_delete=0,questioncat__in = testrule.questioncat.all())
if ret['danxuan_count']:
danxuan = queryset.filter(type=1).order_by('?')[:ret['danxuan_count']]
question_queryset = question_queryset | danxuan
if ret['duoxuan_count']:
duoxuan = queryset.filter(type=2).order_by('?')[:ret['duoxuan_count']]
question_queryset = question_queryset | duoxuan
if ret['panduan_count']:
panduan = queryset.filter(type=3).order_by('?')[:ret['panduan_count']]
question_queryset = question_queryset | panduan
questions = QuestionSerializer(instance=question_queryset.order_by('type'),many=True).data
for i in questions:
if i['type'] == 1:
i['score'] = ret['danxuan_score']
elif i['type'] == 2:
i['score'] = ret['duoxuan_score']
else:
i['score'] = ret['panduan_score']
ret['questions'] = questions
return Response(ret)
class TestRuleViewSet(ModelViewSet):
"""
模考规则增删改查
@ -30,4 +78,34 @@ class TestRuleViewSet(ModelViewSet):
serializer_class = TestRuleSerializer
ordering_fields = ('id',)
ordering = ['id']
search_fields = ('^name',)
search_fields = ('^name',)
def get_serializer(self, *args, **kwargs):
"""
Return the serializer instance that should be used for validating and
deserializing input, and for serializing output.
"""
if self.action == 'list':
serializer_class = TestRuleListSerializer
elif self.action == 'create':
serializer_class = TestRuleCreateSerializer
else:
serializer_class = TestRuleSerializer
kwargs['context'] = self.get_serializer_context()
return serializer_class(*args, **kwargs)
def get_authenticators(self):
"""
GET请求不做登陆验证
"""
if self.request.method == 'GET':
self.authentication_classes = []
return [auth() for auth in self.authentication_classes]
def get_permissions(self):
"""
GET请求不做权限验证
"""
if self.request.method == 'GET':
self.permission_classes = []
return [permission() for permission in self.permission_classes]

View File

@ -125,16 +125,17 @@ class QuestionViewSet(ModelViewSet):
instance.save()
return Response(status=status.HTTP_204_NO_CONTENT)
@action(methods=['get'], detail=False, permission_classes=[IsAuthenticated],
@action(methods=['post'], detail=False, permission_classes=[IsAuthenticated],
url_path='count', url_name='question_count')
def count(self, request):
ret = {'danxuan':0,'duoxuan':0,'panduan':0}
queryset = self.queryset
if request.query_params.get('ids',None):
queryset = queryset.filter(questioncat__in = request.query_params.get('ids'))
if request.data.get('ids',None):
queryset = queryset.filter(questioncat__in = request.data.get('ids'))
ret['danxuan'] = queryset.filter(type=1).count()
ret['duoxuan'] = queryset.filter(type=1).count()
ret['panduan'] = queryset.filter(type=1).count()
ret['duoxuan'] = queryset.filter(type=2).count()
ret['panduan'] = queryset.filter(type=3).count()
print(ret)
return Response(ret)