monitest complete
This commit is contained in:
parent
54ee7e06f1
commit
fc66951a17
|
@ -16,7 +16,7 @@
|
|||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
<el-select
|
||||
<!-- <el-select
|
||||
v-model="listQuery.is_paid"
|
||||
placeholder="是否缴费"
|
||||
clearable
|
||||
|
@ -30,7 +30,7 @@
|
|||
:label="item.display_name"
|
||||
:value="item.key"
|
||||
/>
|
||||
</el-select>
|
||||
</el-select> -->
|
||||
<el-input
|
||||
v-model="search"
|
||||
placeholder="姓名"
|
||||
|
@ -96,10 +96,14 @@
|
|||
v-if="scope.row.company_name != null"
|
||||
>{{ scope.row.company_name }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="是否付费">
|
||||
<template slot-scope="scope">
|
||||
<el-tag type="success" v-if="scope.row.is_paid">已付费</el-tag>
|
||||
<el-tag type="danger" v-else>未付费</el-tag>
|
||||
<el-table-column align="center" label="缴费科目">
|
||||
<template slot-scope="scope" >
|
||||
<el-tag
|
||||
v-for="item in scope.row.subjects"
|
||||
:key="item.id"
|
||||
effect="dark">
|
||||
{{ item.name }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建日期">
|
||||
|
@ -153,7 +157,7 @@
|
|||
</el-form-item>
|
||||
<el-form-item label="单位" prop="company">
|
||||
<el-cascader
|
||||
v-model="consumer.company"
|
||||
v-model="consumer.company.id"
|
||||
:options="companyData"
|
||||
:props="{ checkStrictly: true }"
|
||||
clearable
|
||||
|
@ -188,8 +192,10 @@ const defaultConsumer = {
|
|||
id: "",
|
||||
name: "",
|
||||
username: "",
|
||||
company: null,
|
||||
is_paid: false
|
||||
company: {
|
||||
id:0,
|
||||
name:''
|
||||
},
|
||||
};
|
||||
const listQuery = {
|
||||
page: 1,
|
||||
|
@ -206,13 +212,7 @@ export default {
|
|||
return {
|
||||
uploadUrl: uploadUrl(),
|
||||
popovervisible: false,
|
||||
consumer: {
|
||||
id: "",
|
||||
name: "",
|
||||
username: "",
|
||||
company: null,
|
||||
ispaid: false
|
||||
},
|
||||
consumer: defaultConsumer,
|
||||
myHeaders: { Authorization: "JWT " + getToken() },
|
||||
consumerList: [],
|
||||
total: 0,
|
||||
|
@ -345,7 +345,9 @@ export default {
|
|||
if (valid) {
|
||||
const isEdit = this.dialogType === "edit";
|
||||
if (isEdit) {
|
||||
updateConsumer(this.consumer.id, this.consumer).then(() => {
|
||||
let consumer = this.consumer
|
||||
consumer.company = consumer.company.id
|
||||
updateConsumer(this.consumer.id, consumer).then(() => {
|
||||
for (let index = 0; index < this.consumerList.length; index++) {
|
||||
if (this.consumerList[index].id === this.consumer.id) {
|
||||
this.consumerList.splice(
|
||||
|
@ -365,8 +367,10 @@ export default {
|
|||
});
|
||||
});
|
||||
} else {
|
||||
this.consumer.company = this.consumer.company.pop();
|
||||
createConsumer(this.consumer).then(res => {
|
||||
this.consumer.company.id = this.consumer.company.id.pop();
|
||||
let consumer = this.consumer
|
||||
consumer.company = consumer.company.id
|
||||
createConsumer(consumer).then(res => {
|
||||
// this.consumer = res.data
|
||||
// this.consumerList.unshift(this.consumer)
|
||||
this.getList();
|
||||
|
|
|
@ -11,7 +11,11 @@
|
|||
"pages/cuoti/index",
|
||||
"pages/moni/index",
|
||||
"pages/moni/note",
|
||||
"pages/test/test"
|
||||
"pages/test/test",
|
||||
"pages/test/result",
|
||||
"pages/test/detail",
|
||||
"pages/test/sheet",
|
||||
"pages/test/list"
|
||||
],
|
||||
"window": {
|
||||
"backgroundTextStyle": "light",
|
||||
|
|
|
@ -8,20 +8,20 @@ Page({
|
|||
*/
|
||||
data: {
|
||||
ctms: [],
|
||||
tmIndex: 0,
|
||||
tm_index: 0,
|
||||
isright:false,
|
||||
answerP:false
|
||||
},
|
||||
radioChange: function (e) {
|
||||
var that = this
|
||||
that.data.currentTm['user_answer'] = e.detail.value
|
||||
that.data.ctms[that.data.tmIndex] = that.data.currentTm
|
||||
that.data.ctms[that.data.tm_index] = that.data.currentTm
|
||||
that.showAnswer()
|
||||
},
|
||||
checkboxChange: function (e) {
|
||||
var that = this
|
||||
that.data.currentTm['user_answer'] = e.detail.value
|
||||
that.data.ctms[that.data.tmIndex] = that.data.currentTm
|
||||
that.data.ctms[that.data.tm_index] = that.data.currentTm
|
||||
},
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
|
@ -64,7 +64,7 @@ Page({
|
|||
}
|
||||
})
|
||||
}else{
|
||||
that.showTm(that.data.tmIndex)
|
||||
that.showTm(that.data.tm_index)
|
||||
}
|
||||
|
||||
},
|
||||
|
@ -123,7 +123,7 @@ Page({
|
|||
var that = this
|
||||
var currentTm = that.data.ctms[index]
|
||||
that.setData({
|
||||
'tmIndex': index,
|
||||
'tm_index': index,
|
||||
'tmtotal':that.data.ctms.length,
|
||||
'currentTm': currentTm
|
||||
})
|
||||
|
@ -165,13 +165,13 @@ Page({
|
|||
},
|
||||
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
|
||||
|
@ -195,7 +195,7 @@ Page({
|
|||
},
|
||||
remove: function () {
|
||||
var that = this
|
||||
var index = that.data.tmIndex
|
||||
var index = that.data.tm_index
|
||||
that.data.ctms.splice(index,1)
|
||||
if(that.data.ctms.length>index){
|
||||
that.showTm(index)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<view class="head">
|
||||
题量: {{tmIndex+1}}/{{tmtotal}}
|
||||
题量: {{tm_index+1}}/{{tmtotal}}
|
||||
</view>
|
||||
<scroll-view scroll-y="true" style="height: {{scrollHeight}}px;">
|
||||
<view class="weui-article">
|
||||
<view class="weui-article__h2">{{tmIndex+1}}.
|
||||
<view class="weui-article__h2">{{tm_index+1}}.
|
||||
<span class="txlabel">{{currentTm.type}}</span>
|
||||
</view>
|
||||
<view style="text-align:center">
|
||||
|
@ -52,10 +52,10 @@
|
|||
</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==tmtotal-1}}">下题</button>
|
||||
</view>
|
||||
<view style="width:25%">
|
||||
<button type="primary" size="mini" bindtap="showAnswer">答案</button>
|
||||
|
|
|
@ -11,14 +11,14 @@ Page({
|
|||
tms:[],
|
||||
ydtms:[],
|
||||
ctms:[],
|
||||
tmIndex: 0,
|
||||
tm_index: 0,
|
||||
answerP: false,
|
||||
isLoad:true,
|
||||
},
|
||||
radioChange: function (e) {
|
||||
var that = this
|
||||
that.data.tm_current['user_answer'] = e.detail.value
|
||||
that.data.tms[that.data.tmIndex] = that.data.tm_current
|
||||
that.data.tms[that.data.tm_index] = that.data.tm_current
|
||||
that.showAnswer()
|
||||
if (that.data.ydtms.indexOf(that.data.tm_current.id)==-1){
|
||||
that.data.ydtms.push(that.data.tm_current.id)
|
||||
|
@ -27,7 +27,7 @@ Page({
|
|||
checkboxChange: function (e) {
|
||||
var that = this
|
||||
that.data.tm_current['user_answer'] = e.detail.value
|
||||
that.data.tms[that.data.tmIndex] = that.data.tm_current
|
||||
that.data.tms[that.data.tm_index] = that.data.tm_current
|
||||
if (that.data.ydtms.indexOf(that.data.tm_current.id) == -1) {
|
||||
that.data.ydtms.push(that.data.tm_current.id)
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ Page({
|
|||
})
|
||||
}else{
|
||||
that.data.tms = that.data.tms.concat(res.data.results)
|
||||
that.showTm(that.data.tmIndex) //展示题目和答案
|
||||
that.showTm(that.data.tm_index) //展示题目和答案
|
||||
if(that.data.isLoad){
|
||||
that.setData({
|
||||
tmtotal: res.data.total,
|
||||
|
@ -152,7 +152,7 @@ Page({
|
|||
var that = this
|
||||
var tm_current = that.data.tms[index]
|
||||
that.setData({
|
||||
'tmIndex': index,
|
||||
'tm_index': index,
|
||||
'tm_current': tm_current
|
||||
})
|
||||
that.showOptions()
|
||||
|
@ -193,25 +193,25 @@ Page({
|
|||
},
|
||||
next: function () {
|
||||
var that = this
|
||||
var tmIndex = that.data.tmIndex + 1
|
||||
var tm_index = that.data.tm_index + 1
|
||||
that.setData({
|
||||
tmIndex: tmIndex,
|
||||
tm_index: tm_index,
|
||||
answerP: false
|
||||
})
|
||||
if (tmIndex + 1 > that.data.tms.length) {
|
||||
if (tm_index + 1 > that.data.tms.length) {
|
||||
that.getTms()
|
||||
} else {
|
||||
that.showTm(tmIndex)
|
||||
that.showTm(tm_index)
|
||||
}
|
||||
|
||||
},
|
||||
previous: function () {
|
||||
var that = this
|
||||
var tmIndex = that.data.tmIndex - 1
|
||||
var tm_index = that.data.tm_index - 1
|
||||
that.setData({
|
||||
answerP: false
|
||||
})
|
||||
that.showTm(tmIndex)
|
||||
that.showTm(tm_index)
|
||||
},
|
||||
showOptions: function () {
|
||||
let tm_current = this.data.tm_current
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<view class="head">
|
||||
题量: {{tmIndex+1}}/{{tmtotal}}
|
||||
题量: {{tm_index+1}}/{{tmtotal}}
|
||||
</view>
|
||||
<scroll-view scroll-y="true" style="height: {{scrollHeight}}px;">
|
||||
<view class="weui-article">
|
||||
<view class="weui-article__h2">{{tmIndex+1}}.
|
||||
<view class="weui-article__h2">{{tm_index+1}}.
|
||||
<span class="txlabel">{{tm_current.type}}</span>
|
||||
</view>
|
||||
<view class="weui-article__title">{{tm_current.name}}</view>
|
||||
|
@ -48,10 +48,10 @@
|
|||
</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==tmtotal-1}}">下题</button>
|
||||
</view>
|
||||
<view style="width:25%">
|
||||
<button type="primary" size="mini" bindtap="showAnswer">答案</button>
|
||||
|
|
|
@ -143,5 +143,16 @@ Page({
|
|||
duration: 1500
|
||||
})
|
||||
}
|
||||
},
|
||||
goYati: function () {
|
||||
wx.showToast({
|
||||
title: '暂未开放',
|
||||
icon:'none'
|
||||
})
|
||||
},
|
||||
testList: function (){
|
||||
wx.navigateTo({
|
||||
url: '/pages/test/list',
|
||||
})
|
||||
}
|
||||
})
|
|
@ -47,14 +47,14 @@
|
|||
</view>
|
||||
<view class="weui-grid__label">自助模考</view>
|
||||
</a>
|
||||
<a class="weui-grid">
|
||||
<view class="weui-grid__icon">
|
||||
<a class="weui-grid" bindtap="goYati">
|
||||
<view class="weui-grid__icon" >
|
||||
<image src="/images/yati.svg" alt></image>
|
||||
</view>
|
||||
<view class="weui-grid__label">押题考试</view>
|
||||
</a>
|
||||
<a class="weui-grid">
|
||||
<view class="weui-grid__icon">
|
||||
<a class="weui-grid" bindtap="testList">
|
||||
<view class="weui-grid__icon" >
|
||||
<image src="/images/ksjl.svg" alt></image>
|
||||
</view>
|
||||
<view class="weui-grid__label">考试记录</view>
|
||||
|
|
|
@ -91,7 +91,7 @@ Page({
|
|||
wx.showLoading({
|
||||
title: '正在生成试卷',
|
||||
})
|
||||
api.request('examtest/monitest/', 'GET', { 'rule': e.currentTarget.id }).then(res => {
|
||||
api.request('examtest/testrule/' + e.currentTarget.id + '/monitest', 'GET').then(res => {
|
||||
try {
|
||||
wx.setStorageSync('monitest', res.data)
|
||||
} catch (e) { }
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
// pages/test/detail.js
|
||||
const api = require("../../utils/request.js");
|
||||
Page({
|
||||
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
tm_index:0,
|
||||
results:[]
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad: function (options) {
|
||||
var that = this
|
||||
var query = {'examtest':options.id}
|
||||
api.request('examtest/answerdetail/', 'GET', query).then(res => {
|
||||
that.data.results= res.data
|
||||
that.showTm(0)
|
||||
that.setData({
|
||||
tmtotal:res.data.length
|
||||
})
|
||||
})
|
||||
try {
|
||||
const res = wx.getSystemInfoSync()
|
||||
that.setData({
|
||||
scrollHeight: res.windowHeight - 70
|
||||
})
|
||||
} catch (e) {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面初次渲染完成
|
||||
*/
|
||||
onReady: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面隐藏
|
||||
*/
|
||||
onHide: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面卸载
|
||||
*/
|
||||
onUnload: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面相关事件处理函数--监听用户下拉动作
|
||||
*/
|
||||
onPullDownRefresh: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面上拉触底事件的处理函数
|
||||
*/
|
||||
onReachBottom: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击右上角分享
|
||||
*/
|
||||
onShareAppMessage: function () {
|
||||
|
||||
},
|
||||
showTm: function (index) {
|
||||
var that = this
|
||||
var tm_current = that.data.results[index]
|
||||
that.setData({
|
||||
'tm_index': index,
|
||||
'tm_current': tm_current
|
||||
})
|
||||
that.showOptions()
|
||||
},
|
||||
next: function () {
|
||||
var that = this
|
||||
var tm_index = that.data.tm_index + 1
|
||||
that.showTm(tm_index)
|
||||
|
||||
},
|
||||
previous: function () {
|
||||
var that = this
|
||||
var tm_index = that.data.tm_index - 1
|
||||
that.showTm(tm_index)
|
||||
},
|
||||
showOptions: function () {
|
||||
var that = this
|
||||
let question_options = that.data.tm_current.question.options
|
||||
let options = []
|
||||
let user_answer = that.data.tm_current.user_answer
|
||||
for (let key in question_options) {
|
||||
let option = {}
|
||||
option.key = key
|
||||
option.value = key + ':' + question_options[key]
|
||||
if (user_answer) {
|
||||
if (key == user_answer || user_answer.indexOf(key) != -1) {
|
||||
option.checked = true
|
||||
}
|
||||
} else {
|
||||
option.checked = false
|
||||
}
|
||||
options.push(option)
|
||||
}
|
||||
that.setData({
|
||||
options: options
|
||||
})
|
||||
},
|
||||
})
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"usingComponents": {}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
<view class="head">
|
||||
题量: {{tm_index+1}}/{{tmtotal}}
|
||||
</view>
|
||||
<scroll-view scroll-y="true" style="height: {{scrollHeight}}px;">
|
||||
<view class="weui-article">
|
||||
<view class="weui-article__h2">{{tm_index+1}}.
|
||||
<span class="txlabel">{{tm_current.question.type}}</span>
|
||||
</view>
|
||||
<view class="weui-article__title">{{tm_current.question.name}}</view>
|
||||
</view>
|
||||
<view class="weui-cells weui-cells_radio">
|
||||
<radio-group class="radio-group" wx:if="{{(tm_current.question.type=='单选' ||tm_current.question.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>
|
||||
</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="{{tm_current.question.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>
|
||||
</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>
|
||||
<view class="weui-article">
|
||||
<view class="weui-article__h2" wx:if="{{tm_current.is_right}}" 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">正确答案是{{tm_current.question.right}},你的答案是{{tm_current.user_answer}}</view>
|
||||
<view class="weui-article__title">
|
||||
<span style="color:blue">解析: </span>
|
||||
<span wx:if="{{tm_current.question.resoluation != null}}">{{tm_current.question.resoluation}}</span>
|
||||
<span wx:else>无</span>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="btns">
|
||||
<view style="width:33%">
|
||||
<button type="primary" size="mini" bindtap="previous" disabled="{{tm_index==0}}">上题</button>
|
||||
</view>
|
||||
<view style="width:33%">
|
||||
<button type="primary" size="mini" bindtap="next" disabled="{{tm_index==tmtotal-1}}">下题</button>
|
||||
</view>
|
||||
<view style="width:33%">
|
||||
<image style="height: 80%;" src="/images/weishoucang.svg" bindtap="shoucang" wx:if="weishoucang"></image>
|
||||
<image style="height: 80%;" src="/images/yishoucang.svg" bindtap="shoucang" wx:else></image>
|
||||
</view>
|
||||
</view>
|
|
@ -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
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
// pages/lianxi/index.js
|
||||
const api = require("../../utils/request.js");
|
||||
Page({
|
||||
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
results: [],
|
||||
query:{
|
||||
page:1,
|
||||
limit:10
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad: function () {
|
||||
var that = this
|
||||
that.getList(that.data.query)
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面初次渲染完成
|
||||
*/
|
||||
onReady: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow: function () {
|
||||
},
|
||||
getList: function () {
|
||||
var that = this
|
||||
api.request('examtest/myexamtest/', 'GET', that.data.query).then(res => {
|
||||
if(res.data.length==0){
|
||||
wx.showToast({
|
||||
title: '没有更多了',
|
||||
icon:''
|
||||
})
|
||||
}else{
|
||||
if (that.data.query.page == 1){
|
||||
that.data.results = res.data.results
|
||||
}else{
|
||||
that.data.results = that.data.results.concat(res.data.results)
|
||||
}
|
||||
|
||||
that.setData({
|
||||
results:that.data.results,
|
||||
count:res.data.count
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 生命周期函数--监听页面隐藏
|
||||
*/
|
||||
onHide: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面卸载
|
||||
*/
|
||||
onUnload: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面相关事件处理函数--监听用户下拉动作
|
||||
*/
|
||||
onPullDownRefresh: function () {
|
||||
var that = this
|
||||
that.data.query.page = 1;
|
||||
that.getList();
|
||||
wx.stopPullDownRefresh();
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面上拉触底事件的处理函数
|
||||
*/
|
||||
onReachBottom: function () {
|
||||
that.data.query.page = that.data.query.page + 1
|
||||
that.getList()
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击右上角分享
|
||||
*/
|
||||
onShareAppMessage: function () {
|
||||
|
||||
},
|
||||
|
||||
detail: function (e) {
|
||||
wx.navigateTo({
|
||||
url: '',
|
||||
})
|
||||
},
|
||||
})
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"usingComponents": {},
|
||||
"navigationBarTitleText": "考试记录",
|
||||
"enablePullDownRefresh": true,
|
||||
"onReachBottomDistance": 50
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<view class="head">
|
||||
|
||||
共{{count}}条考试记录</view>
|
||||
<view class="weui-cells weui-cells_after-title">
|
||||
<block wx:for="{{results}}" wx:key="unique">
|
||||
<navigator url="detail?id={{item.id}}" class="weui-media-box weui-media-box_appmsg" hover-class="weui-cell_active">
|
||||
<view class="weui-media-box__bd weui-media-box__bd_in-appmsg">
|
||||
<view class="weui-media-box__title">{{item.name}}</view>
|
||||
<view class="weui-media-box__desc" style="color:orange">
|
||||
<span style="font-weight:bold;color:white;background-color:orange;">{{item.type}}</span>
|
||||
<span>-</span>
|
||||
<span style="font-weight:bold;color:white;background-color:green;" wx:if="{{item.is_pass}}">通过</span>
|
||||
<span style="font-weight:bold;color:white;background-color:red;" wx:else>未通过</span>
|
||||
(得分
|
||||
<span style="color:green;font-weight:bold" wx:if="{{item.is_pass}}">{{item.score}}</span>
|
||||
<span style="color:red;font-weight:bold" wx:else>{{item.score}}</span>
|
||||
-满分
|
||||
<span style="font-weight:bold">{{item.total_score}})</span>
|
||||
</view>
|
||||
<view class="weui-media-box__desc" style="color:orange">
|
||||
耗时:{{item.took}}s
|
||||
开始答题:{{item.start_time}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="weui-panel__ft weui-cell__ft_in-access">
|
||||
<view class="weui-media-box__desc">答卷详情</view>
|
||||
</view>
|
||||
</navigator>
|
||||
</block>
|
||||
</view>
|
|
@ -0,0 +1,5 @@
|
|||
.head{
|
||||
color:#fff;
|
||||
background-color: cornflowerblue;
|
||||
text-align: center;
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
// pages/examtest/result.js
|
||||
Page({
|
||||
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad: function () {
|
||||
this.setData(getApp().globalData.testData)
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面初次渲染完成
|
||||
*/
|
||||
onReady: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面隐藏
|
||||
*/
|
||||
onHide: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面卸载
|
||||
*/
|
||||
onUnload: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面相关事件处理函数--监听用户下拉动作
|
||||
*/
|
||||
onPullDownRefresh: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面上拉触底事件的处理函数
|
||||
*/
|
||||
onReachBottom: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击右上角分享
|
||||
*/
|
||||
onShareAppMessage: function () {
|
||||
|
||||
},
|
||||
detail: function () {
|
||||
wx.redirectTo({
|
||||
url: 'detail?id=' + this.data.id,
|
||||
})
|
||||
},
|
||||
back: function () {
|
||||
wx.switchTab({
|
||||
url: '/pages/main/main'
|
||||
})
|
||||
},
|
||||
})
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"usingComponents": {}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<view class="page">
|
||||
<view class="weui-msg">
|
||||
<view class="weui-msg__icon-area" wx:if="{{is_pass}}"><i class="weui-icon-success weui-icon_msg"></i></view>
|
||||
<view class="weui-msg__icon-area" wx:else><i class="weui-icon-warn weui-icon_msg"></i></view>
|
||||
<view class="weui-msg__text-area">
|
||||
<h2 class="weui-msg__title" wx:if="{{is_pass}}">恭喜您,通过考试</h2>
|
||||
<h2 class="weui-msg__title" wx:else>很遗憾,下次加油</h2>
|
||||
<view class="weui-msg__desc">
|
||||
得分
|
||||
<span style="color:green;font-weight:bold" wx:if="{{is_pass}}">{{score}}</span>
|
||||
<span style="color:red;font-weight:bold" wx:else>{{score}}</span>
|
||||
——满分
|
||||
<span style="font-weight:bold">{{total_score}}</span>
|
||||
</view>
|
||||
<view class="weui-msg__desc">
|
||||
用时:
|
||||
<span style="color:green;font-weight:bold" wx:if="{{is_pass}}">{{took}}</span>
|
||||
<span style="color:red;font-weight:bold" wx:else>{{took}}</span>
|
||||
秒
|
||||
</view>
|
||||
</view>
|
||||
<view class="weui-msg__opr-area">
|
||||
<view class="weui-btn-area">
|
||||
<a class="weui-btn weui-btn_primary" bindtap="detail">查看答卷详情</a>
|
||||
<a class="weui-btn weui-btn_default" bindtap="back">返回首页</a>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
|
@ -0,0 +1 @@
|
|||
/* pages/test/note.wxss */
|
|
@ -0,0 +1,86 @@
|
|||
// pages/examtest/sheet.js
|
||||
|
||||
Page({
|
||||
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
|
||||
},
|
||||
|
||||
back: function (e) {
|
||||
console.log(e.currentTarget.dataset.index);
|
||||
var tm_index = e.currentTarget.dataset.index
|
||||
var pages = getCurrentPages();
|
||||
var prevPage = pages[pages.length - 2]; //上一个页面
|
||||
prevPage.setData({
|
||||
tm_index: tm_index
|
||||
})
|
||||
prevPage.showTm(tm_index)
|
||||
prevPage.showOptions()
|
||||
wx.navigateBack({
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad: function (options) {
|
||||
var pages = getCurrentPages();
|
||||
var prevPage = pages[pages.length - 2]; //上一个页面
|
||||
var tms = prevPage.data.tms //取上页data里的数据也可以修改
|
||||
this.setData({
|
||||
tms: tms
|
||||
})
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面初次渲染完成
|
||||
*/
|
||||
onReady: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面隐藏
|
||||
*/
|
||||
onHide: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面卸载
|
||||
*/
|
||||
onUnload: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面相关事件处理函数--监听用户下拉动作
|
||||
*/
|
||||
onPullDownRefresh: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面上拉触底事件的处理函数
|
||||
*/
|
||||
onReachBottom: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击右上角分享
|
||||
*/
|
||||
onShareAppMessage: function () {
|
||||
|
||||
}
|
||||
})
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"usingComponents": {},
|
||||
"navigationBarTitleText": "答题卡"
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<!--pages/examtest/sheet.wxml-->
|
||||
<view style="width:100%;display:flex;padding:20rpx;flex-wrap: wrap ">
|
||||
<view wx:for="{{tms}}" wx:key="id" >
|
||||
|
||||
<view wx:if="{{item.user_answer && item.user_answer.length !=0 }}" class="ok" data-index="{{index}}" bindtap='back'>
|
||||
{{index+1}}
|
||||
</view>
|
||||
<view wx:else class="no" data-index="{{index}}" bindtap='back'>
|
||||
{{index+1}}
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</view>
|
|
@ -0,0 +1,21 @@
|
|||
/* pages/examtest/sheet.wxss */
|
||||
.ok{
|
||||
display: flex;
|
||||
color:#fff;
|
||||
background-color: green;
|
||||
border:4rpx solid green;
|
||||
height:100rpx;
|
||||
width:100rpx;
|
||||
margin:20rpx;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.no{
|
||||
display: flex;
|
||||
border:4rpx solid red;
|
||||
height:100rpx;
|
||||
width:100rpx;
|
||||
margin:20rpx;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
|
@ -43,6 +43,12 @@ Page({
|
|||
})
|
||||
} catch (e) {
|
||||
}
|
||||
try {
|
||||
var value = wx.getStorageSync('ctms')
|
||||
if (value) {
|
||||
that.data.ctms = value
|
||||
}
|
||||
} catch (e) { }
|
||||
let mil = that.data.monitest.limit * 60 * 1000
|
||||
let starttimes = (new Date()).getTime() //时间戳
|
||||
let endtimes = starttimes + mil
|
||||
|
@ -78,6 +84,9 @@ Page({
|
|||
*/
|
||||
onUnload: function () {
|
||||
clearInterval(getApp().globalData.timer)
|
||||
try {
|
||||
wx.setStorageSync('ctms', this.data.ctms)
|
||||
} catch (e) { }
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -178,6 +187,11 @@ Page({
|
|||
options: options
|
||||
})
|
||||
},
|
||||
sheet: function () {
|
||||
wx.navigateTo({
|
||||
url: 'sheet',
|
||||
})
|
||||
},
|
||||
hand: function () {
|
||||
var that = this
|
||||
for (var i = 0, len = that.data.tms.length; i < len; i++) {
|
||||
|
@ -219,19 +233,35 @@ Page({
|
|||
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
|
||||
if (tm_result.is_right == false){
|
||||
that.data.ctms.unshift(that.data.tms[i])
|
||||
if (that.data.ctms.length > 40) {
|
||||
that.data.ctms.length = 40
|
||||
}
|
||||
}
|
||||
that.data.tms[i].score = tm_result.score
|
||||
score = score + tm_result.score
|
||||
}
|
||||
that.data.monitest.score = score
|
||||
if (score >= that.data.monitest.pass_score){
|
||||
that.data.monitest.is_pass = true
|
||||
}else{
|
||||
that.data.monitest.is_pass = false
|
||||
}
|
||||
console.log(that.data.tms)
|
||||
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',
|
||||
// })
|
||||
// })
|
||||
api.request('examtest/monitest/', 'POST', that.data.monitest).then(res => {
|
||||
getApp().globalData.testData = res.data
|
||||
try {
|
||||
wx.removeStorageSync('monitest')
|
||||
} catch (e) {
|
||||
}
|
||||
wx.redirectTo({
|
||||
url: 'result',
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"usingComponents": {},
|
||||
"navigationBarTitleText": "考试中"
|
||||
"navigationBarTitleText": "答题中"
|
||||
}
|
|
@ -53,7 +53,7 @@
|
|||
<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="sheet">答题卡</button>
|
||||
<a class="weui-btn weui-btn_mini weui-btn_primary" bindtap="sheet">答题卡</a>
|
||||
</view>
|
||||
<view style="width:25%">
|
||||
<a class="weui-btn weui-btn_mini weui-btn_warn" bindtap="hand">交卷</a>
|
||||
|
|
|
@ -6,7 +6,7 @@ const formatTime = date => {
|
|||
const minute = date.getMinutes()
|
||||
const second = date.getSeconds()
|
||||
|
||||
return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
|
||||
return [year, month, day].map(formatNumber).join('-') + ' ' + [hour, minute, second].map(formatNumber).join(':')
|
||||
}
|
||||
|
||||
const formatNumber = n => {
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
# Generated by Django 3.0.4 on 2020-03-20 09:26
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('question', '0007_auto_20200319_0846'),
|
||||
('crm', '0006_auto_20200310_1531'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='consumer',
|
||||
name='is_paid',
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PaySubject',
|
||||
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='删除标记')),
|
||||
('consumer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='crm.Consumer')),
|
||||
('subject', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='question.Questioncat')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='consumer',
|
||||
name='subjects',
|
||||
field=models.ManyToManyField(through='crm.PaySubject', to='question.Questioncat', verbose_name='付费学科'),
|
||||
),
|
||||
]
|
|
@ -1,9 +1,10 @@
|
|||
from django.db import models
|
||||
import django.utils.timezone as timezone
|
||||
from rbac.models import CommonModel
|
||||
from rbac.models import SoftCommonModel, CommonModel
|
||||
from question.models import Questioncat
|
||||
# Create your models here.
|
||||
|
||||
class Company(CommonModel):
|
||||
class Company(SoftCommonModel):
|
||||
"""
|
||||
客户企业
|
||||
"""
|
||||
|
@ -17,7 +18,7 @@ class Company(CommonModel):
|
|||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Consumer(CommonModel):
|
||||
class Consumer(SoftCommonModel):
|
||||
"""
|
||||
学员
|
||||
"""
|
||||
|
@ -27,7 +28,7 @@ class Consumer(CommonModel):
|
|||
openid = models.CharField(max_length=200, verbose_name="openid", null=True, blank=True, unique=True)
|
||||
avatar = models.CharField(default="/media/default/avatar.png",max_length=1000, null=True, blank=True, verbose_name="头像")
|
||||
nickname = models.CharField(max_length=200, verbose_name="昵称", null=True, blank=True)
|
||||
is_paid = models.BooleanField(default=False,verbose_name="是否付费")
|
||||
subjects = models.ManyToManyField(Questioncat, verbose_name="付费学科", through="PaySubject")
|
||||
|
||||
|
||||
class Meta:
|
||||
|
@ -35,4 +36,11 @@ class Consumer(CommonModel):
|
|||
verbose_name_plural = verbose_name
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
return self.name
|
||||
|
||||
class PaySubject(CommonModel):
|
||||
'''
|
||||
付费学科关联表
|
||||
'''
|
||||
consumer = models.ForeignKey(Consumer, on_delete=models.CASCADE)
|
||||
subject = models.ForeignKey(Questioncat, on_delete=models.CASCADE)
|
|
@ -24,3 +24,15 @@ class ConsumerSerializer(serializers.ModelSerializer):
|
|||
class Meta:
|
||||
model = Consumer
|
||||
fields = '__all__'
|
||||
depth = 1
|
||||
|
||||
class ConsumerCUSerializer(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 = Consumer
|
||||
fields = '__all__'
|
|
@ -14,9 +14,10 @@ import json
|
|||
|
||||
from utils.custom import CommonPagination
|
||||
from rbac.permission import RbacPermission
|
||||
from .models import Company, Consumer
|
||||
from .serializers import CompanySerializer, ConsumerSerializer
|
||||
from .models import Company, Consumer, PaySubject
|
||||
from .serializers import CompanySerializer, ConsumerSerializer, ConsumerCUSerializer
|
||||
from server import settings
|
||||
from question.models import Questioncat
|
||||
|
||||
appid = 'wx5c39b569f01c27db'
|
||||
secret = '68762892f8df2b4a0b1940c5250a8dc0'
|
||||
|
@ -70,9 +71,14 @@ class ConsumerViewSet(ModelViewSet):
|
|||
ordering_fields = ('id',)
|
||||
ordering = ['id']
|
||||
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
||||
filterset_fields = ('is_paid','company')
|
||||
filterset_fields = ('company',)
|
||||
search_fields = ('^name',)
|
||||
|
||||
def get_serializer_class(self):
|
||||
if self.action == 'list':
|
||||
return ConsumerSerializer
|
||||
else:
|
||||
return ConsumerCUSerializer
|
||||
|
||||
def destroy(self, request, *args, **kwargs): #逻辑删除
|
||||
instance = self.get_object()
|
||||
|
@ -125,8 +131,10 @@ class ConsumerViewSet(ModelViewSet):
|
|||
obj.name = name
|
||||
obj.username = username
|
||||
obj.company = companyobj
|
||||
obj.is_paid = True
|
||||
obj.save()
|
||||
subjects = Questioncat.objects.filter(is_subject=True,is_delete=False)
|
||||
if subjects.exists():
|
||||
PaySubject.objects.create(subject=subjects.first(), consumer=obj)
|
||||
i = i + 1
|
||||
if consumerdict:
|
||||
return {"code":206,"data":consumerdict,"msg":"导入部分成功"}
|
||||
|
|
|
@ -50,7 +50,7 @@ class Migration(migrations.Migration):
|
|||
field=models.FloatField(default=0, verbose_name='判断分数'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='MoniTest',
|
||||
name='ExamTest',
|
||||
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='创建时间')),
|
||||
|
@ -73,8 +73,8 @@ class Migration(migrations.Migration):
|
|||
),
|
||||
migrations.AddField(
|
||||
model_name='answerdetail',
|
||||
name='monitest',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='examtest.MoniTest'),
|
||||
name='examtest',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='examtest.ExamTest'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='answerdetail',
|
||||
|
|
|
@ -29,7 +29,7 @@ class Migration(migrations.Migration):
|
|||
options={'verbose_name': '答题记录', 'verbose_name_plural': '答题记录'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='monitest',
|
||||
name='examtest',
|
||||
options={'verbose_name': '自助模考', 'verbose_name_plural': '自助模考'},
|
||||
),
|
||||
]
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.0.4 on 2020-03-20 03:12
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('examtest', '0009_auto_20200319_1850'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='testrule',
|
||||
name='is_pass',
|
||||
field=models.BooleanField(default=True, verbose_name='是否通过'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,42 @@
|
|||
# Generated by Django 3.0.4 on 2020-03-20 03:15
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('examtest', '0010_testrule_is_pass'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='testrule',
|
||||
name='is_pass',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='examtest',
|
||||
name='is_pass',
|
||||
field=models.BooleanField(default=True, verbose_name='是否通过'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='examtest',
|
||||
name='total_score',
|
||||
field=models.FloatField(default=0, verbose_name='总分'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='examtest',
|
||||
name='score',
|
||||
field=models.FloatField(default=0, verbose_name='得分'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='testrule',
|
||||
name='pass_score',
|
||||
field=models.FloatField(default=0, verbose_name='及格分数'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='testrule',
|
||||
name='total_score',
|
||||
field=models.FloatField(default=0, verbose_name='满分'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,50 @@
|
|||
# Generated by Django 3.0.4 on 2020-03-20 06:39
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('examtest', '0011_auto_20200320_1115'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Paper',
|
||||
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='名称')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='PaperTest',
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='examtest',
|
||||
options={'verbose_name': '考试表', 'verbose_name_plural': '考试表'},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='examtest',
|
||||
name='rule',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='examtest.TestRule', verbose_name='所用规则'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='examtest',
|
||||
name='type',
|
||||
field=models.CharField(choices=[('自助模考', '自助模考'), ('押卷模考', '押卷模考')], default='自助模考', max_length=50, verbose_name='考试类型'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='examtest',
|
||||
name='paper',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='examtest.Paper', verbose_name='所用试卷'),
|
||||
),
|
||||
]
|
|
@ -1,11 +1,11 @@
|
|||
from django.db import models
|
||||
from rbac.models import CommonModel
|
||||
from rbac.models import SoftCommonModel, CommonModel
|
||||
from django.contrib.postgres.fields import JSONField, ArrayField
|
||||
from question.models import Questioncat, Question
|
||||
from crm.models import Consumer
|
||||
|
||||
# Create your models here.
|
||||
class TestRule(CommonModel):
|
||||
class TestRule(SoftCommonModel):
|
||||
name = models.CharField(max_length=200, unique=True, verbose_name='名称')
|
||||
desc = models.TextField(verbose_name='描述', default='')
|
||||
subject = models.ForeignKey(Questioncat, blank=True, null=True, on_delete=models.CASCADE, verbose_name='所属学科', related_name='subject')
|
||||
|
@ -17,8 +17,9 @@ class TestRule(CommonModel):
|
|||
panduan_count = models.IntegerField(default=0, verbose_name='判断数量')
|
||||
panduan_score = models.FloatField(default=0, verbose_name='判断分数')
|
||||
limit = models.IntegerField(default=0, verbose_name='限时(分钟)')
|
||||
total_score = models.IntegerField(default=0, verbose_name='满分')
|
||||
pass_score = models.IntegerField(default=0, verbose_name='及格分数')
|
||||
total_score = models.FloatField(default=0, verbose_name='满分')
|
||||
pass_score = models.FloatField(default=0, verbose_name='及格分数')
|
||||
|
||||
|
||||
class Meta:
|
||||
verbose_name = '出题规则'
|
||||
|
@ -27,31 +28,38 @@ class TestRule(CommonModel):
|
|||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class PaperTest(CommonModel):
|
||||
pass
|
||||
class Meta:
|
||||
verbose_name = '押题模考'
|
||||
verbose_name_plural = verbose_name
|
||||
|
||||
|
||||
class MoniTest(CommonModel):
|
||||
class Paper(SoftCommonModel):
|
||||
name = models.CharField(max_length=200, verbose_name='名称')
|
||||
type = models.CharField(max_length=50, default='自助模考',verbose_name='考试类型')
|
||||
|
||||
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='考试类型')
|
||||
limit = models.IntegerField(default=0, verbose_name='限时(分钟)')
|
||||
rule = models.ForeignKey(TestRule, on_delete=models.CASCADE, verbose_name='出题规则')
|
||||
rule = models.ForeignKey(TestRule, on_delete=models.CASCADE, verbose_name='所用规则', null=True, blank=True)
|
||||
paper = models.ForeignKey(Paper, on_delete=models.CASCADE, verbose_name='所用试卷', null=True, blank=True)
|
||||
consumer = models.ForeignKey(Consumer, on_delete=models.CASCADE, verbose_name='模考人')
|
||||
score = models.IntegerField(default=0, verbose_name='得分')
|
||||
total_score = models.FloatField(default=0, verbose_name='总分')
|
||||
score = models.FloatField(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')
|
||||
is_pass = models.BooleanField(default=True, verbose_name='是否通过')
|
||||
class Meta:
|
||||
verbose_name = '自助模考'
|
||||
verbose_name = '考试表'
|
||||
verbose_name_plural = verbose_name
|
||||
|
||||
|
||||
class AnswerDetail(CommonModel):
|
||||
monitest = models.ForeignKey(MoniTest, on_delete=models.CASCADE)
|
||||
class AnswerDetail(SoftCommonModel):
|
||||
examtest = models.ForeignKey(ExamTest, on_delete=models.CASCADE)
|
||||
question = models.ForeignKey(Question, on_delete=models.CASCADE)
|
||||
user_answer = JSONField()
|
||||
score = models.FloatField(default=0, verbose_name='本题得分')
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from rest_framework import serializers
|
||||
from question.models import Questioncat
|
||||
from .models import TestRule, MoniTest
|
||||
from crm.models import Consumer
|
||||
from .models import TestRule, ExamTest, AnswerDetail
|
||||
|
||||
|
||||
|
||||
|
@ -41,12 +42,36 @@ 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)
|
||||
start_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S")
|
||||
end_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S")
|
||||
consumer = serializers.PrimaryKeyRelatedField(queryset=Consumer.objects.all(), required=False)
|
||||
rule = serializers.PrimaryKeyRelatedField(queryset=TestRule.objects.all(), required=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
|
||||
model = ExamTest
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
|
||||
class ExamTestListSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
考试列表序列化
|
||||
"""
|
||||
start_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S")
|
||||
end_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S")
|
||||
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 = ExamTest
|
||||
fields = '__all__'
|
||||
|
||||
class AnswerDetailSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = AnswerDetail
|
||||
fields = '__all__'
|
||||
depth = 1
|
||||
|
||||
class AnswerDetailCreateSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = AnswerDetail
|
||||
fields = '__all__'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from django.urls import path,include
|
||||
from .views import TestRuleViewSet, MoniTestView
|
||||
from .views import TestRuleViewSet, MoniTestView, MyExamTestView, AnswerDetailView
|
||||
from rest_framework import routers
|
||||
|
||||
|
||||
|
@ -8,5 +8,7 @@ router.register('testrule', TestRuleViewSet, basename="testrule")
|
|||
|
||||
urlpatterns = [
|
||||
path('monitest/',MoniTestView.as_view()),
|
||||
path('myexamtest/',MyExamTestView.as_view()),
|
||||
path('answerdetail/', AnswerDetailView.as_view()),
|
||||
path('', include(router.urls)),
|
||||
]
|
||||
|
|
|
@ -15,60 +15,65 @@ 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, TestRuleListSerializer, TestRuleCreateSerializer, MoniTestSerializer
|
||||
from .models import TestRule, ExamTest, AnswerDetail
|
||||
from .serializers import TestRuleSerializer, TestRuleListSerializer, TestRuleCreateSerializer, MoniTestSerializer, AnswerDetailSerializer, ExamTestListSerializer, AnswerDetailCreateSerializer
|
||||
from server import settings
|
||||
from crm.authentication import ConsumerTokenAuthentication
|
||||
from utils.custom import CommonPagination
|
||||
|
||||
# Create your views here.
|
||||
|
||||
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'] = '自助模考' # 自助模拟考试
|
||||
ret['rule'] = testrule.id
|
||||
ret['limit'] = testrule.limit
|
||||
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
|
||||
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='单选').order_by('?')[:ret['danxuan_count']]
|
||||
question_queryset = question_queryset | danxuan
|
||||
if 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='判断').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['total_score'] = ret['danxuan_score']
|
||||
elif i['type'] == 2:
|
||||
i['total_score'] = ret['duoxuan_score']
|
||||
serializer = MoniTestSerializer(data = request.data)
|
||||
if serializer.is_valid():
|
||||
instance = serializer.save(consumer = request.user)
|
||||
if 'questions' in request.data:
|
||||
questions = []
|
||||
for i in request.data['questions']:
|
||||
question = {}
|
||||
question['question'] = i['id']
|
||||
question['examtest'] = instance.id
|
||||
question['score'] = i['score']
|
||||
if 'user_answer' in i:
|
||||
question['user_answer'] = i['user_answer']
|
||||
question['is_right'] = i['is_right']
|
||||
questions.append(question)
|
||||
serializer_detail = AnswerDetailCreateSerializer(data=questions, many=True)
|
||||
if serializer_detail.is_valid():
|
||||
serializer_detail.save()
|
||||
return Response(MoniTestSerializer(instance).data,status=status.HTTP_200_OK)
|
||||
else:
|
||||
i['total_score'] = ret['panduan_score']
|
||||
ret['questions'] = questions
|
||||
return Response(ret)
|
||||
return Response(serializer_detail.errors)
|
||||
|
||||
else:
|
||||
return Response({'error':'答题记录不存在'})
|
||||
else:
|
||||
return Response(serializer.errors)
|
||||
|
||||
|
||||
class MyExamTestView(APIView):
|
||||
authentication_classes = [ConsumerTokenAuthentication]
|
||||
permission_classes = []
|
||||
def get(self, request, *args, **kwargs):
|
||||
queryset = ExamTest.objects.filter(consumer=request.user)
|
||||
pg = CommonPagination()
|
||||
p = pg.paginate_queryset(queryset=queryset,request=request,view=self)
|
||||
serializer = ExamTestListSerializer(instance=p,many=True)
|
||||
return pg.get_paginated_response(serializer.data)
|
||||
|
||||
|
||||
class AnswerDetailView(APIView):
|
||||
authentication_classes = []
|
||||
permission_classes = []
|
||||
def get(self, request, *args, **kwargs):
|
||||
queryset = AnswerDetail.objects.all()
|
||||
if request.query_params.get('examtest', None):
|
||||
queryset = queryset.filter(examtest=request.query_params.get('examtest'))
|
||||
serializer = AnswerDetailSerializer(instance=queryset,many=True)
|
||||
return Response(serializer.data)
|
||||
|
||||
|
||||
|
||||
|
@ -114,4 +119,46 @@ class TestRuleViewSet(ModelViewSet):
|
|||
"""
|
||||
if self.request.method == 'GET':
|
||||
self.permission_classes = []
|
||||
return [permission() for permission in self.permission_classes]
|
||||
return [permission() for permission in self.permission_classes]
|
||||
|
||||
@action(methods=['get'], detail=True, permission_classes=[IsAuthenticated],
|
||||
url_path='monitest', url_name='gen_monitest')
|
||||
def monitest(self, request, pk=None):
|
||||
'''
|
||||
生成自助模拟考试
|
||||
'''
|
||||
ret = {}
|
||||
testrule = self.get_object()
|
||||
ret['name'] = '自助模考' + datetime.now().strftime('%Y%m%d%H%M')
|
||||
ret['type'] = '自助模考' # 自助模拟考试
|
||||
ret['rule'] = testrule.id
|
||||
ret['limit'] = testrule.limit
|
||||
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
|
||||
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='单选').order_by('?')[:ret['danxuan_count']]
|
||||
question_queryset = question_queryset | danxuan
|
||||
if 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='判断').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['total_score'] = ret['danxuan_score']
|
||||
elif i['type'] == 2:
|
||||
i['total_score'] = ret['duoxuan_score']
|
||||
else:
|
||||
i['total_score'] = ret['panduan_score']
|
||||
ret['questions'] = questions
|
||||
return Response(ret)
|
Binary file not shown.
Binary file not shown.
|
@ -1,10 +1,10 @@
|
|||
from django.db import models
|
||||
from rbac.models import CommonModel
|
||||
from rbac.models import SoftCommonModel
|
||||
from django.contrib.postgres.fields import JSONField, ArrayField
|
||||
# Create your models here.
|
||||
|
||||
|
||||
class Questioncat(CommonModel):
|
||||
class Questioncat(SoftCommonModel):
|
||||
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='是否是学科')
|
||||
|
@ -20,7 +20,7 @@ class Questioncat(CommonModel):
|
|||
return self.questioncat.count()
|
||||
|
||||
|
||||
class Question(CommonModel):
|
||||
class Question(SoftCommonModel):
|
||||
type_choices = (
|
||||
('单选', '单选'),
|
||||
('多选', '多选'),
|
||||
|
|
|
@ -13,7 +13,7 @@ class SoftDeletManager(models.Manager):
|
|||
'''
|
||||
def get_queryset(self):
|
||||
"""
|
||||
在这里处理一下QuerySet, 然后返回没被标记位is_deleted的QuerySet
|
||||
在这里处理一下QuerySet, 然后返回没被标记位is_delete的QuerySet
|
||||
"""
|
||||
kwargs = {'model': self.model, 'using': self._db}
|
||||
if hasattr(self, '_hints'):
|
||||
|
@ -21,7 +21,7 @@ class SoftDeletManager(models.Manager):
|
|||
|
||||
return self._queryset_class(**kwargs).filter(is_delete=False)
|
||||
|
||||
class CommonModel(models.Model):
|
||||
class SoftCommonModel(models.Model):
|
||||
create_time = models.DateTimeField(default=timezone.now, verbose_name='创建时间', help_text='创建时间')
|
||||
update_time = models.DateTimeField(auto_now=True, verbose_name='修改时间', help_text='修改时间')
|
||||
is_delete = models.BooleanField(default=False, verbose_name='删除标记', help_text='删除标记')
|
||||
|
@ -39,10 +39,18 @@ class CommonModel(models.Model):
|
|||
self.is_delete = True
|
||||
self.save(using=using)
|
||||
else:
|
||||
return super(CommonModel, self).delete(using=using, *args, **kwargs)
|
||||
return super(SoftCommonModel, self).delete(using=using, *args, **kwargs)
|
||||
|
||||
class CommonModel(models.Model):
|
||||
create_time = models.DateTimeField(default=timezone.now, verbose_name='创建时间', help_text='创建时间')
|
||||
update_time = models.DateTimeField(auto_now=True, verbose_name='修改时间', help_text='修改时间')
|
||||
is_delete = models.BooleanField(default=False, verbose_name='删除标记', help_text='删除标记')
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
||||
class Menu(CommonModel):
|
||||
class Menu(SoftCommonModel):
|
||||
"""
|
||||
功能权限:目录,菜单,权限
|
||||
"""
|
||||
|
@ -68,7 +76,7 @@ class Menu(CommonModel):
|
|||
ordering = ['id']
|
||||
|
||||
|
||||
class Role(CommonModel):
|
||||
class Role(SoftCommonModel):
|
||||
"""
|
||||
角色
|
||||
"""
|
||||
|
@ -83,7 +91,7 @@ class Role(CommonModel):
|
|||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Organization(CommonModel):
|
||||
class Organization(SoftCommonModel):
|
||||
"""
|
||||
组织架构
|
||||
"""
|
||||
|
|
Loading…
Reference in New Issue