This commit is contained in:
caoqianming 2020-03-19 20:10:06 +08:00
parent 8d68e1cf92
commit 54ee7e06f1
21 changed files with 464 additions and 168 deletions

View File

@ -26,7 +26,8 @@
<el-form-item label="题库范围" prop="questioncat">
<el-select
v-model="Form.questioncat" multiple placeholder="请选择题库范围" style="width:400px"
@visible-change="getQuestionCount">
@visible-change="getQuestionCount"
@remove-tag="getQuestionCount2">
<el-option
v-for="item in questioncatData"
:key="item.value"
@ -54,10 +55,10 @@
<el-input-number v-model="Form.limit" :min="0"></el-input-number>分钟
</el-form-item>
<el-form-item label="当前总分">
<span style="color:darkred;font-weight:bold">{{Form.totalscore}} </span>
<span style="color:darkred;font-weight:bold">{{Form.total_score}} </span>
</el-form-item>
<el-form-item label="及格分数" prop="passscore">
<el-input-number v-model="Form.passscore" :min="0"></el-input-number>
<el-form-item label="及格分数" prop="pass_score">
<el-input-number v-model="Form.pass_score" :min="0"></el-input-number>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('Form')" :loading="submitLoding">立即创建</el-button>
@ -86,8 +87,8 @@ export default {
panduan_count:0,
panduan_score:0,
limit:0,
totalscore:0,
passscore:0
total_score:0,
pass_score:0
},
typecount:{
danxuan:0,
@ -109,7 +110,7 @@ export default {
{ required: true, message: "时间限制不能为空"},
{ type: "number", message: "时间限制必须是数字"}
],
passscore: [
pass_score: [
{ required: true, message: "及格分数不能为空"},
{ type: "number", message: "及格分数必须是数字"}
]
@ -163,15 +164,22 @@ export default {
this.typecount = response.data
});
}
},
getQuestionCount2(val) {
getQuestionCount({ids:this.Form.questioncat}).then(response => {
this.typecount = response.data
});
},
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
this.Form.total_score = score
},
resetForm(formName) {
this.$refs[formName].resetFields();
this.typecount.danxuan = 0;
this.typecount.duoxuan = 0;
this.typecount.panduan = 0;
},
goBack() {
this.$router.replace('/sjmanage/testrule/')

View File

@ -83,10 +83,10 @@
<template slot-scope="scope">{{ scope.row.questioncat_name }}</template>
</el-table-column>
<el-table-column align="left" label="题型">
<template slot-scope="scope">{{ scope.row.type_display }}</template>
<template slot-scope="scope">{{ scope.row.type }}</template>
</el-table-column>
<el-table-column align="left" label="难易度">
<template slot-scope="scope">{{ scope.row.level_display }}</template>
<template slot-scope="scope">{{ scope.row.level }}</template>
</el-table-column>
<el-table-column label="创建日期">
<template slot-scope="scope">

View File

@ -14,13 +14,13 @@ Page({
},
radioChange: function (e) {
var that = this
that.data.currentTm['userChecked'] = e.detail.value
that.data.currentTm['user_answer'] = e.detail.value
that.data.ctms[that.data.tmIndex] = that.data.currentTm
that.showAnswer()
},
checkboxChange: function (e) {
var that = this
that.data.currentTm['userChecked'] = e.detail.value
that.data.currentTm['user_answer'] = e.detail.value
that.data.ctms[that.data.tmIndex] = that.data.currentTm
},
/**
@ -128,7 +128,7 @@ Page({
'currentTm': currentTm
})
that.showOptions()
if (currentTm.userChecked) {
if (currentTm.user_answer) {
that.showAnswer()
}
},
@ -136,17 +136,17 @@ Page({
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()) {
if (currentTm.type == '多选') {
if (currentTm.user_answer) {
if (currentTm.user_answer.sort().toString() == currentTm.right.sort().toString()) {
isright = true
}
}
} else {
isright = currentTm.right == currentTm.userChecked
isright = currentTm.right == currentTm.user_answer
}
// if (isright == false && currentTm.userChecked != undefined) {
// if (isright == false && currentTm.user_answer != undefined) {
// currentTm.dtime = util.formatTime(new Date())
// that.data.ctms.unshift(currentTm)
// if (that.data.ctms.length > 40) {
@ -180,8 +180,8 @@ Page({
let option = {}
option.key = key
option.value = key + ':' + currentTm.options[key]
if (currentTm.userChecked) {
if (key == currentTm.userChecked || currentTm.userChecked.indexOf(key) != -1) {
if (currentTm.user_answer) {
if (key == currentTm.user_answer || currentTm.user_answer.indexOf(key) != -1) {
option.checked = true
}
} else {
@ -199,6 +199,8 @@ Page({
that.data.ctms.splice(index,1)
if(that.data.ctms.length>index){
that.showTm(index)
} else if (that.data.ctms.length > 0 && index > 1){
that.showTm(index-1)
}
else{
wx.navigateBack({

View File

@ -4,9 +4,7 @@
<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 class="txlabel">{{currentTm.type}}</span>
</view>
<view style="text-align:center">
<span style="color:drakblue;font-weight:bold;font-size:14px">{{currentTm.questioncat_name}}(</span>
@ -15,7 +13,7 @@
<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)}}">
<radio-group class="radio-group" bindchange="radioChange" wx:if="{{(currentTm.type=='单选' ||currentTm.type=='判断')}}">
<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>
@ -28,7 +26,7 @@
</radio-group>
</view>
<view class="weui-cells weui-cells_checkbox">
<checkbox-group bindchange="checkboxChange" wx:if="{{currentTm.type==2}}">
<checkbox-group bindchange="checkboxChange" wx:if="{{currentTm.type=='多选'}}">
<label class="weui-cell weui-cell_active weui-check__label" wx:for="{{options}}" wx:key="key">
<view class="weui-cell__bd">
@ -44,7 +42,7 @@
<view class="weui-article" wx:if="{{answerP}}">
<view class="weui-article__h2" wx:if="{{isright}}" style="color:green;font-weight:bold">回答正确!</view>
<view class="weui-article__h2" wx:else style="color:red;font-weight:bold">回答有误!</view>
<view class="weui-article__h2">正确答案是{{currentTm.right}},你的答案是{{currentTm.userChecked}}</view>
<view class="weui-article__h2">正确答案是{{currentTm.right}},你的答案是{{currentTm.user_answer}}</view>
<view class="weui-article__title">
<span style="color:blue">解析: </span>
<span wx:if="{{currentTm.resoluation != null}}">{{currentTm.resoluation}}</span>

View File

@ -17,19 +17,19 @@ Page({
},
radioChange: function (e) {
var that = this
that.data.currentTm['userChecked'] = e.detail.value
that.data.tms[that.data.tmIndex] = that.data.currentTm
that.data.tm_current['user_answer'] = e.detail.value
that.data.tms[that.data.tmIndex] = that.data.tm_current
that.showAnswer()
if (that.data.ydtms.indexOf(that.data.currentTm.id)==-1){
that.data.ydtms.push(that.data.currentTm.id)
if (that.data.ydtms.indexOf(that.data.tm_current.id)==-1){
that.data.ydtms.push(that.data.tm_current.id)
}
},
checkboxChange: function (e) {
var that = this
that.data.currentTm['userChecked'] = e.detail.value
that.data.tms[that.data.tmIndex] = that.data.currentTm
if (that.data.ydtms.indexOf(that.data.currentTm.id) == -1) {
that.data.ydtms.push(that.data.currentTm.id)
that.data.tm_current['user_answer'] = e.detail.value
that.data.tms[that.data.tmIndex] = that.data.tm_current
if (that.data.ydtms.indexOf(that.data.tm_current.id) == -1) {
that.data.ydtms.push(that.data.tm_current.id)
}
},
/**
@ -150,33 +150,33 @@ Page({
showTm: function (index) {
var that = this
var currentTm = that.data.tms[index]
var tm_current = that.data.tms[index]
that.setData({
'tmIndex': index,
'currentTm': currentTm
'tm_current': tm_current
})
that.showOptions()
if (currentTm.userChecked){
if (tm_current.user_answer){
that.showAnswer()
}
},
panTi: function () {
var that = this
let currentTm = that.data.currentTm
let tm_current = that.data.tm_current
let isright = false
if (currentTm.type == 2) {
if (currentTm.userChecked) {
if (currentTm.userChecked.sort().toString() == currentTm.right.sort().toString()) {
if (tm_current.type == '多选') {
if (tm_current.user_answer) {
if (tm_current.user_answer.sort().toString() == tm_current.right.sort().toString()) {
isright = true
}
}
} else {
isright = currentTm.right == currentTm.userChecked
isright = tm_current.right == tm_current.user_answer
}
if(isright == false && currentTm.userChecked != undefined){
currentTm.dtime = util.formatTime(new Date())
that.data.ctms.unshift(currentTm)
if(isright == false && tm_current.user_answer != undefined){
tm_current.dtime = util.formatTime(new Date())
that.data.ctms.unshift(tm_current)
if(that.data.ctms.length>40){
that.data.ctms.length = 40
}
@ -188,7 +188,7 @@ Page({
this.setData({
isright: isright,
answerP: true,
currentTm: this.data.currentTm
tm_current: this.data.tm_current
})
},
next: function () {
@ -214,14 +214,14 @@ Page({
that.showTm(tmIndex)
},
showOptions: function () {
let currentTm = this.data.currentTm
let tm_current = this.data.tm_current
let options = []
for (let key in currentTm.options) {
for (let key in tm_current.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.value = key + ':' + tm_current.options[key]
if (tm_current.user_answer){
if (key == tm_current.user_answer || tm_current.user_answer.indexOf(key)!=-1){
option.checked = true
}
}else{

View File

@ -4,14 +4,12 @@
<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 class="txlabel">{{tm_current.type}}</span>
</view>
<view class="weui-article__title">{{currentTm.name}}</view>
<view class="weui-article__title">{{tm_current.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)}}">
<radio-group class="radio-group" bindchange="radioChange" wx:if="{{(tm_current.type=='单选' ||tm_current.type=='判断')}}">
<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>
@ -24,7 +22,7 @@
</radio-group>
</view>
<view class="weui-cells weui-cells_checkbox">
<checkbox-group bindchange="checkboxChange" wx:if="{{currentTm.type==2}}">
<checkbox-group bindchange="checkboxChange" wx:if="{{tm_current.type=='多选'}}">
<label class="weui-cell weui-cell_active weui-check__label" wx:for="{{options}}" wx:key="key">
<view class="weui-cell__bd">
@ -40,10 +38,10 @@
<view class="weui-article" wx:if="{{answerP}}">
<view class="weui-article__h2" wx:if="{{isright}}" style="color:green;font-weight:bold">回答正确!</view>
<view class="weui-article__h2" wx:else style="color:red;font-weight:bold">回答有误!</view>
<view class="weui-article__h2">正确答案是{{currentTm.right}},你的答案是{{currentTm.userChecked}}</view>
<view class="weui-article__h2">正确答案是{{tm_current.right}},你的答案是{{tm_current.user_answer}}</view>
<view class="weui-article__title">
<span style="color:blue">解析: </span>
<span wx:if="{{currentTm.resoluation != null}}">{{currentTm.resoluation}}</span>
<span wx:if="{{tm_current.resoluation != null}}">{{tm_current.resoluation}}</span>
<span wx:else>无</span>
</view>
</view>

View File

@ -45,7 +45,7 @@
<view class="weui-grid__icon">
<image src="/images/moni.svg" alt></image>
</view>
<view class="weui-grid__label">模</view>
<view class="weui-grid__label">自助模考</view>
</a>
<a class="weui-grid">
<view class="weui-grid__icon">

View File

@ -6,9 +6,10 @@
<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 wx:if="{{duoxuan_count>0}}">{{duoxuan_count}}道多选题,每题{{duoxuan_score}}分</view>
<view wx:if="{{panduan_count>0}}">{{panduan_count}}道判断题,每题{{panduan_score}}分</view>
<view >多选题漏选每个正确选项得1分,错选0分</view>
<view >满分{{total_score}};{{pass_score}}以上通过</view>
</view>
<view class="weui-article">
<view class="weui-article__h2">2.答题须知</view>

View File

@ -8,17 +8,17 @@ Page({
*/
data: {
tms:[],
tmIndex: 0,
tm_index: 0,
},
radioChange: function (e) {
var that = this
that.data.currentTm['userChecked'] = e.detail.value
that.data.tms[that.data.tmIndex] = that.data.currentTm
that.data.tm_current['user_answer'] = e.detail.value
that.data.tms[that.data.tm_index] = that.data.tm_current
},
checkboxChange: function (e) {
var that = this
that.data.currentTm['userChecked'] = e.detail.value
that.data.tms[that.data.tmIndex] = that.data.currentTm
that.data.tm_current['user_answer'] = e.detail.value
that.data.tms[that.data.tm_index] = that.data.tm_current
},
/**
* 生命周期函数--监听页面加载
@ -31,9 +31,9 @@ Page({
that.data.monitest = value
that.data.tms = value.questions
that.setData({
tmtotal:value.questions.length
tm_total:value.questions.length
})
that.showTm(that.data.tmIndex)
that.showTm(that.data.tm_index)
}
} catch (e) { wx.navigateBack({}) }
try {
@ -49,7 +49,7 @@ Page({
that.data.starttimes = starttimes
that.data.endtimes = endtimes
getApp().globalData.timer = setInterval(function () {
that.startpass()
that.startPass()
}, 1000)
},
/**
@ -100,11 +100,11 @@ Page({
onShareAppMessage: function () {
},
startpass: function () {
startPass: function () {
var mil = this.data.endtimes - (new Date()).getTime()
if (mil < 2000) {
clearInterval(getApp().globalData.timer)
this.handtest()
this.handTest()
};
var temp = util.formatmil(mil);
this.setData({
@ -114,53 +114,59 @@ Page({
},
showTm: function (index) {
var that = this
var currentTm = that.data.tms[index]
var tm_current = that.data.tms[index]
that.setData({
'tmIndex': index,
'currentTm': currentTm
'tm_index': index,
'tm_current': tm_current
})
that.showOptions()
},
panTi: function (currentTm) {
let isright = false
if (currentTm.type == 2) {
if (currentTm.userChecked) {
if (currentTm.userChecked.sort().toString() == currentTm.right.sort().toString()) {
isright = true
panTi: function (tm_current) {
// 返回当前题目是否正确,得分多少
let is_right = false, score = 0
if (tm_current.type == '多选') {
if (tm_current.user_answer) {
if (tm_current.user_answer.sort().toString() == tm_current.right.sort().toString()) {
is_right = true
score = tm_current.total_score
}else{
for(var i=0;i<tm_current.user_answer.length;i++){
if(tm_current.right.indexOf(tm_current.user_answer[i])!=-1){
score = score + 1
}else{
break;
}
}
}
}
} 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
if(tm_current.right == tm_current.user_answer){
is_right = true
score = tm_current.total_score
}
}
return isright
return {'is_right':is_right,'score':score}
},
next: function () {
var that = this
var tmIndex = that.data.tmIndex + 1
that.showTm(tmIndex)
var tm_index = that.data.tm_index + 1
that.showTm(tm_index)
},
previous: function () {
var that = this
var tmIndex = that.data.tmIndex - 1
that.showTm(tmIndex)
var tm_index = that.data.tm_index - 1
that.showTm(tm_index)
},
showOptions: function () {
let currentTm = this.data.currentTm
let tm_current = this.data.tm_current
let options = []
for (let key in currentTm.options) {
for (let key in tm_current.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.value = key + ':' + tm_current.options[key]
if (tm_current.user_answer) {
if (key == tm_current.user_answer || tm_current.user_answer.indexOf(key) != -1) {
option.checked = true
}
} else {
@ -174,9 +180,9 @@ Page({
},
hand: function () {
var that = this
for (i = 0, len = that.data.tms.length; i < len; i++) {
for (var i = 0, len = that.data.tms.length; i < len; i++) {
let tm = that.data.tms[i]
if (tm.userChecked == undefined || tm.length == 0){
if (tm.user_answer == undefined || tm.length == 0){
wx.showModal({
title: '警告',
content: '答卷未完成,可点击答题卡复查!',
@ -184,7 +190,7 @@ Page({
cancelText: "取消",
success: function (res) {
if (res.confirm) {
that.handtest()
that.handTest()
}
}
})
@ -197,16 +203,35 @@ Page({
cancelText: "取消",
success: function (res) {
if (res.confirm) {
that.handtest()
that.handTest()
}
}
})
},
handtest: function (){
handTest: function (){
var that = this
clearInterval(getApp().globalData.timer)
wx.showLoading({
title: '正在判卷中...',
mask:true
})
let score = 0;
for (var i = 0, len = that.data.tms.length; i < len; i++) {
let tm_result = that.panTi(that.data.tms[i])
that.data.tms[i].is_right = tm_result.is_right
that.data.tms[i].score = tm_result.score
score = score + tm_result.score
}
that.data.monitest.score = score
that.data.monitest.questions = that.data.tms
that.data.monitest.start_time = util.formatTime(new Date(that.data.starttimes))
that.data.monitest.end_time = util.formatTime(new Date())
that.data.monitest.took = Math.floor(((new Date()).getTime() - this.data.starttimes) / 1000)
console.log(that.data.monitest)
// api.request('examtest/monitest/', 'POST', that.data.monitest).then(res => {
// wx.redirectTo({
// url: 'note',
// })
// })
}
})

View File

@ -1,24 +1,24 @@
<view class="head">
<view style="width:50%">
倒计时 {{countdown}}
倒计时
<span style="font-weight:bold">{{countdown}}</span>
</view>
<view style="width:50%;text-align:right">
题量:{{tmIndex+1}}/{{tmtotal}}
题量:
<span style="font-weight:bold">{{tm_index+1}}/{{tm_total}}</span>
</view>
</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 class="weui-article__h2">{{tm_index+1}}.
<span class="txlabel">{{tm_current.type}}</span>
<span>({{tm_current.total_score}}分)</span>
</view>
<view class="weui-article__title">{{currentTm.name}}</view>
<view class="weui-article__title">{{tm_current.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)}}">
<radio-group class="radio-group" bindchange="radioChange" wx:if="{{(tm_current.type=='单选' ||tm_current.type=='判断')}}">
<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>
@ -31,7 +31,7 @@
</radio-group>
</view>
<view class="weui-cells weui-cells_checkbox">
<checkbox-group bindchange="checkboxChange" wx:if="{{currentTm.type==2}}">
<checkbox-group bindchange="checkboxChange" wx:if="{{tm_current.type=='多选'}}">
<label class="weui-cell weui-cell_active weui-check__label" wx:for="{{options}}" wx:key="key">
<view class="weui-cell__bd">
@ -47,15 +47,15 @@
</scroll-view>
<view class="btns">
<view style="width:25%">
<button type="primary" size="mini" bindtap="previous" disabled="{{tmIndex==0}}">上题</button>
<button type="primary" size="mini" bindtap="previous" disabled="{{tm_index==0}}">上题</button>
</view>
<view style="width:25%">
<button type="primary" size="mini" bindtap="next" disabled="{{tmIndex==tmtotal-1}}">下题</button>
<button type="primary" size="mini" bindtap="next" disabled="{{tm_index==tm_total-1}}">下题</button>
</view>
<view style="width:25%">
<button type="primary" size="mini" bindtap="showAnswer">答题卡</button>
<button type="primary" size="mini" bindtap="sheet">答题卡</button>
</view>
<view style="width:25%">
<a class="weui-btn weui-btn_mini weui-btn_warn">交卷</a>
<a class="weui-btn weui-btn_mini weui-btn_warn" bindtap="hand">交卷</a>
</view>
</view>

View File

@ -0,0 +1,23 @@
# Generated by Django 3.0.4 on 2020-03-19 05:55
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('examtest', '0006_auto_20200318_1634'),
]
operations = [
migrations.RenameField(
model_name='testrule',
old_name='passscore',
new_name='pass_score',
),
migrations.RenameField(
model_name='testrule',
old_name='totalscore',
new_name='total_score',
),
]

View File

@ -0,0 +1,84 @@
# Generated by Django 3.0.4 on 2020-03-19 10:27
import django.contrib.postgres.fields.jsonb
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('crm', '0006_auto_20200310_1531'),
('question', '0007_auto_20200319_0846'),
('examtest', '0007_auto_20200319_1355'),
]
operations = [
migrations.CreateModel(
name='AnswerDetail',
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='删除标记')),
('user_answer', django.contrib.postgres.fields.jsonb.JSONField()),
('score', models.FloatField(default=0, verbose_name='本题得分')),
('is_right', models.BooleanField(default=False, verbose_name='是否正确')),
],
options={
'abstract': False,
},
),
migrations.AlterModelOptions(
name='testrule',
options={'verbose_name': '出题规则', 'verbose_name_plural': '出题规则'},
),
migrations.AlterField(
model_name='testrule',
name='danxuan_score',
field=models.FloatField(default=0, verbose_name='单选分数'),
),
migrations.AlterField(
model_name='testrule',
name='duoxuan_score',
field=models.FloatField(default=0, verbose_name='多选分数'),
),
migrations.AlterField(
model_name='testrule',
name='panduan_score',
field=models.FloatField(default=0, verbose_name='判断分数'),
),
migrations.CreateModel(
name='MoniTest',
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='删除标记')),
('name', models.CharField(max_length=200, verbose_name='名称')),
('type', models.CharField(default='自助模考', max_length=50, verbose_name='考试类型')),
('limit', models.IntegerField(default=0, verbose_name='限时(分钟)')),
('score', models.IntegerField(default=0, verbose_name='得分')),
('took', models.IntegerField(default=0, verbose_name='耗时(秒)')),
('start_time', models.DateTimeField(verbose_name='开始答题时间')),
('end_time', models.DateTimeField(verbose_name='结束答题时间')),
('consumer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='crm.Consumer', verbose_name='模考人')),
('detail', models.ManyToManyField(related_name='答题记录', through='examtest.AnswerDetail', to='question.Question')),
('rule', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='examtest.TestRule', verbose_name='出题规则')),
],
options={
'abstract': False,
},
),
migrations.AddField(
model_name='answerdetail',
name='monitest',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='examtest.MoniTest'),
),
migrations.AddField(
model_name='answerdetail',
name='question',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='question.Question'),
),
]

View File

@ -0,0 +1,35 @@
# Generated by Django 3.0.4 on 2020-03-19 10:50
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('examtest', '0008_auto_20200319_1827'),
]
operations = [
migrations.CreateModel(
name='PaperTest',
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='删除标记')),
],
options={
'verbose_name': '押题模考',
'verbose_name_plural': '押题模考',
},
),
migrations.AlterModelOptions(
name='answerdetail',
options={'verbose_name': '答题记录', 'verbose_name_plural': '答题记录'},
),
migrations.AlterModelOptions(
name='monitest',
options={'verbose_name': '自助模考', 'verbose_name_plural': '自助模考'},
),
]

View File

@ -1,7 +1,8 @@
from django.db import models
from rbac.models import CommonModel
from django.contrib.postgres.fields import JSONField, ArrayField
from question.models import Questioncat
from question.models import Questioncat, Question
from crm.models import Consumer
# Create your models here.
class TestRule(CommonModel):
@ -10,11 +11,51 @@ class TestRule(CommonModel):
subject = models.ForeignKey(Questioncat, blank=True, null=True, on_delete=models.CASCADE, verbose_name='所属学科', related_name='subject')
questioncat = models.ManyToManyField(Questioncat, verbose_name='所选题库')
danxuan_count = models.IntegerField(default=0, verbose_name='单选数量')
danxuan_score = models.IntegerField(default=0, verbose_name='单选分数')
danxuan_score = models.FloatField(default=0, verbose_name='单选分数')
duoxuan_count = models.IntegerField(default=0, verbose_name='多选数量')
duoxuan_score = models.IntegerField(default=0, verbose_name='多选分数')
duoxuan_score = models.FloatField(default=0, verbose_name='多选分数')
panduan_count = models.IntegerField(default=0, verbose_name='判断数量')
panduan_score = models.IntegerField(default=0, verbose_name='判断分数')
panduan_score = models.FloatField(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='及格分数')
total_score = models.IntegerField(default=0, verbose_name='满分')
pass_score = models.IntegerField(default=0, verbose_name='及格分数')
class Meta:
verbose_name = '出题规则'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
class PaperTest(CommonModel):
pass
class Meta:
verbose_name = '押题模考'
verbose_name_plural = verbose_name
class MoniTest(CommonModel):
name = models.CharField(max_length=200, verbose_name='名称')
type = models.CharField(max_length=50, default='自助模考',verbose_name='考试类型')
limit = models.IntegerField(default=0, verbose_name='限时(分钟)')
rule = models.ForeignKey(TestRule, on_delete=models.CASCADE, verbose_name='出题规则')
consumer = models.ForeignKey(Consumer, on_delete=models.CASCADE, verbose_name='模考人')
score = models.IntegerField(default=0, verbose_name='得分')
took = models.IntegerField(default=0, verbose_name='耗时(秒)')
start_time = models.DateTimeField(verbose_name='开始答题时间')
end_time = models.DateTimeField(verbose_name='结束答题时间')
detail = models.ManyToManyField(Question, related_name='答题记录', through='AnswerDetail')
class Meta:
verbose_name = '自助模考'
verbose_name_plural = verbose_name
class AnswerDetail(CommonModel):
monitest = models.ForeignKey(MoniTest, on_delete=models.CASCADE)
question = models.ForeignKey(Question, on_delete=models.CASCADE)
user_answer = JSONField()
score = models.FloatField(default=0, verbose_name='本题得分')
is_right = models.BooleanField(default=False, verbose_name='是否正确')
class Meta:
verbose_name = '答题记录'
verbose_name_plural = verbose_name

View File

@ -1,6 +1,6 @@
from rest_framework import serializers
from question.models import Questioncat
from .models import TestRule
from .models import TestRule, MoniTest
@ -37,6 +37,16 @@ class TestRuleSerializer(serializers.ModelSerializer):
fields = '__all__'
depth = 1
class MoniTestSerializer(serializers.ModelSerializer):
"""
自助模考序列化
"""
start_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", read_only=True)
end_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", read_only=True)
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 = MoniTest
fields = '__all__'

View File

@ -16,7 +16,7 @@ from rbac.permission import RbacPermission
from question.models import Question
from question.serializers import QuestionSerializer
from .models import TestRule
from .serializers import TestRuleSerializer, TestRuleListSerializer, TestRuleCreateSerializer
from .serializers import TestRuleSerializer, TestRuleListSerializer, TestRuleCreateSerializer, MoniTestSerializer
from server import settings
from crm.authentication import ConsumerTokenAuthentication
@ -26,16 +26,22 @@ class MoniTestView(APIView):
authentication_classes = [ConsumerTokenAuthentication]
permission_classes = []
def post(self, request, *args, **kwargs):
data = request.data
pass
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['type'] = '自助模考' # 自助模拟考试
ret['rule'] = testrule.id
ret['limit'] = testrule.limit
ret['totalscore'] = testrule.totalscore
ret['passscore'] = testrule.passscore
ret['total_score'] = testrule.total_score
ret['pass_score'] = testrule.pass_score
ret['danxuan_count'] = testrule.danxuan_count
ret['danxuan_score'] = testrule.danxuan_score
ret['duoxuan_count'] = testrule.duoxuan_count
@ -45,22 +51,22 @@ class MoniTestView(APIView):
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']]
danxuan = queryset.filter(type='单选').order_by('?')[:ret['danxuan_count']]
question_queryset = question_queryset | danxuan
if ret['duoxuan_count']:
duoxuan = queryset.filter(type=2).order_by('?')[:ret['duoxuan_count']]
duoxuan = queryset.filter(type='多选').order_by('?')[:ret['duoxuan_count']]
question_queryset = question_queryset | duoxuan
if ret['panduan_count']:
panduan = queryset.filter(type=3).order_by('?')[:ret['panduan_count']]
panduan = queryset.filter(type='判断').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']
i['total_score'] = ret['danxuan_score']
elif i['type'] == 2:
i['score'] = ret['duoxuan_score']
i['total_score'] = ret['duoxuan_score']
else:
i['score'] = ret['panduan_score']
i['total_score'] = ret['panduan_score']
ret['questions'] = questions
return Response(ret)

View File

@ -0,0 +1,34 @@
# Generated by Django 3.0.4 on 2020-03-19 00:46
import django.contrib.postgres.fields.jsonb
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('question', '0006_auto_20200317_1445'),
]
operations = [
migrations.AlterField(
model_name='question',
name='level',
field=models.CharField(choices=[('', ''), ('', ''), ('', '')], default='', max_length=50, verbose_name='难度'),
),
migrations.AlterField(
model_name='question',
name='options',
field=django.contrib.postgres.fields.jsonb.JSONField(verbose_name='选项'),
),
migrations.AlterField(
model_name='question',
name='right',
field=django.contrib.postgres.fields.jsonb.JSONField(verbose_name='正确答案'),
),
migrations.AlterField(
model_name='question',
name='type',
field=models.CharField(choices=[('单选', '单选'), ('多选', '多选'), ('判断', '判断')], default='单选', max_length=50, verbose_name='题型'),
),
]

View File

@ -5,11 +5,11 @@ from django.contrib.postgres.fields import JSONField, ArrayField
class Questioncat(CommonModel):
name = models.CharField(max_length=200, unique=True, verbose_name="名称")
pid = models.ForeignKey("self", verbose_name="", null=True, blank=True, on_delete=models.CASCADE, related_name="questioncatpid")
is_subject = models.BooleanField(default=False, verbose_name="是否是学科")
name = models.CharField(max_length=200, unique=True, verbose_name='名称')
pid = models.ForeignKey('self', verbose_name='', null=True, blank=True, on_delete=models.CASCADE, related_name='questioncatpid')
is_subject = models.BooleanField(default=False, verbose_name='是否是学科')
class Meta:
verbose_name = "题库类别/学科类别"
verbose_name = '题库类别/学科类别'
verbose_name_plural = verbose_name
def __str__(self):
@ -22,25 +22,25 @@ class Questioncat(CommonModel):
class Question(CommonModel):
type_choices = (
(1, "单选"),
(2, "多选"),
(3, "判断"),
('单选', '单选'),
('多选', '多选'),
('判断', '判断'),
)
level_choices = (
(1, ""),
(2, ""),
(3, ""),
('', ''),
('', ''),
('', ''),
)
name = models.TextField(verbose_name="题干")
type = models.IntegerField(default=1, choices=type_choices, verbose_name="题型")
level = models.IntegerField(default=1, choices=level_choices, verbose_name="难度")
questioncat = models.ForeignKey(Questioncat, blank=True, null=True, on_delete=models.CASCADE, verbose_name="所属题库", related_name="questioncat")
options = JSONField()
right = JSONField()
resolution = models.TextField(verbose_name="解析")
name = models.TextField(verbose_name='题干')
type = models.CharField(max_length=50, default='单选', choices=type_choices, verbose_name='题型')
level = models.CharField(max_length=50, default='', choices=level_choices, verbose_name='难度')
questioncat = models.ForeignKey(Questioncat, blank=True, null=True, on_delete=models.CASCADE, verbose_name='所属题库', related_name='questioncat')
options = JSONField(verbose_name='选项')
right = JSONField(verbose_name='正确答案')
resolution = models.TextField(verbose_name='解析')
class Meta:
verbose_name = "题目"
verbose_name = '题目'
verbose_name_plural = verbose_name
def __str__(self):

View File

@ -39,8 +39,8 @@ class QuestionSerializer(serializers.ModelSerializer):
"""
题目序列化
"""
level_display = serializers.CharField(source='get_level_display')
type_display = serializers.CharField(source='get_type_display')
# level_display = serializers.CharField(source='get_level_display')
# type_display = serializers.CharField(source='get_type_display')
questioncat_name = serializers.StringRelatedField(source='questioncat')
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)

View File

@ -132,10 +132,9 @@ class QuestionViewSet(ModelViewSet):
queryset = self.queryset
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=2).count()
ret['panduan'] = queryset.filter(type=3).count()
print(ret)
ret['danxuan'] = queryset.filter(type='单选').count()
ret['duoxuan'] = queryset.filter(type='多选').count()
ret['panduan'] = queryset.filter(type='判断').count()
return Response(ret)
@ -189,12 +188,12 @@ class QuestionViewSet(ModelViewSet):
else:
cateobj = Questioncat.objects.get(id=questioncatdict[questioncat])
if type == '单选':
if Question.objects.filter(type=1,name=name,right=right,is_delete=0).exists():
if Question.objects.filter(type='单选',name=name,right=right,is_delete=0).exists():
notinlist.append(i)
else:
if right in ['A','B','C','D','E','F']:
obj = Question()
obj.type = 1
obj.type = '单选'
obj.questioncat = cateobj
obj.name = name
obj.answer=answer
@ -209,14 +208,14 @@ class QuestionViewSet(ModelViewSet):
obj.save()
elif type == '多选':
right = list(right)
if Question.objects.filter(type=2,name=name,right=right,is_delete=0).exists():
if Question.objects.filter(type='多选',name=name,right=right,is_delete=0).exists():
notinlist.append(i)
else:
if [False for c in right if c not in qlist]:
pass
else:
obj = Question()
obj.type = 2
obj.type = '多选'
obj.questioncat = cateobj
obj.name = name
obj.answer=answer
@ -232,11 +231,11 @@ class QuestionViewSet(ModelViewSet):
right = 'A'
else:
right = 'B'
if Question.objects.filter(type=3,name=name,right=right,is_delete=0).exists():
if Question.objects.filter(type='判断',name=name,right=right,is_delete=0).exists():
notinlist.append(i)
else:
obj = Question()
obj.type = 3
obj.type = '判断'
obj.questioncat = cateobj
obj.name = name
obj.answer={'A':'','B':''}

View File

@ -1,6 +1,25 @@
from django.db import models
from django.contrib.auth.models import AbstractUser
import django.utils.timezone as timezone
from django.db.models.query import QuerySet
class SoftDeleteQuerySet(QuerySet):
def delete(self):
self.update(is_delete=True)
class SoftDeletManager(models.Manager):
'''
仅返回删除的实例
'''
def get_queryset(self):
"""
在这里处理一下QuerySet, 然后返回没被标记位is_deleted的QuerySet
"""
kwargs = {'model': self.model, 'using': self._db}
if hasattr(self, '_hints'):
kwargs['hints'] = self._hints
return self._queryset_class(**kwargs).filter(is_delete=False)
class CommonModel(models.Model):
create_time = models.DateTimeField(default=timezone.now, verbose_name='创建时间', help_text='创建时间')
@ -10,6 +29,19 @@ class CommonModel(models.Model):
class Meta:
abstract = True
objects = SoftDeletManager()
def delete(self, using=None, soft=True, *args, **kwargs):
"""
这里需要真删除的话soft=False即可
"""
if soft:
self.is_delete = True
self.save(using=using)
else:
return super(CommonModel, self).delete(using=using, *args, **kwargs)
class Menu(CommonModel):
"""
功能权限:目录,菜单,权限