Merge branch 'master' of https://e.coding.net/ctcdevteam/cma_search
This commit is contained in:
commit
acb25ae76e
File diff suppressed because one or more lines are too long
|
@ -27,10 +27,12 @@
|
||||||
"nprogress": "0.2.0",
|
"nprogress": "0.2.0",
|
||||||
"path-to-regexp": "2.4.0",
|
"path-to-regexp": "2.4.0",
|
||||||
"pdfobject": "^2.3.0",
|
"pdfobject": "^2.3.0",
|
||||||
|
"sortablejs": "^1.15.2",
|
||||||
"vod-js-sdk-v6": "^1.4.12",
|
"vod-js-sdk-v6": "^1.4.12",
|
||||||
"vue": "2.6.10",
|
"vue": "2.7",
|
||||||
"vue-pdf": "^4.2.0",
|
"vue-pdf": "^4.2.0",
|
||||||
"vue-router": "3.0.6",
|
"vue-router": "3.0.6",
|
||||||
|
"vuedraggable": "^2.24.3",
|
||||||
"vuex": "3.1.0",
|
"vuex": "3.1.0",
|
||||||
"xlsx": "^0.15.5"
|
"xlsx": "^0.15.5"
|
||||||
},
|
},
|
||||||
|
|
|
@ -27,10 +27,11 @@ export function updateQuestioncat(id, data) {
|
||||||
//删除题目类型
|
//删除题目类型
|
||||||
export function deleteQuestioncat(id) {
|
export function deleteQuestioncat(id) {
|
||||||
return request({
|
return request({
|
||||||
url: `/exam/questioncat/${id}/`,
|
url: `/exam/question/${id}/`,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//题目列表
|
//题目列表
|
||||||
export function getQuestionList(query) {
|
export function getQuestionList(query) {
|
||||||
return request({
|
return request({
|
||||||
|
@ -69,6 +70,14 @@ export function deleteQuestion(id) {
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
//批量删除题目类型
|
||||||
|
export function deletesQuestion(data) {
|
||||||
|
return request({
|
||||||
|
url: `/exam/question/deletes/`,
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
//导入题目
|
//导入题目
|
||||||
export function importQuestion(data) {
|
export function importQuestion(data) {
|
||||||
return request({
|
return request({
|
||||||
|
@ -82,7 +91,7 @@ export function exportQuestion(data) {
|
||||||
return request({
|
return request({
|
||||||
url: `/exam/question/export/`,
|
url: `/exam/question/export/`,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
//启用题目
|
//启用题目
|
||||||
|
@ -213,6 +222,15 @@ export function updateExamRecord(id, data) {
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//导出考试记录
|
||||||
|
export function exportRecord(data) {
|
||||||
|
return request({
|
||||||
|
url: `/exam/examrecord/export/`,
|
||||||
|
method: 'get',
|
||||||
|
params: data,
|
||||||
|
})
|
||||||
|
}
|
||||||
//删除考试记录
|
//删除考试记录
|
||||||
export function deleteExamRecord(id) {
|
export function deleteExamRecord(id) {
|
||||||
return request({
|
return request({
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
<svg t="1717725053175" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3023" width="200" height="200"><path d="M153.6 58.88v901.632h706.56V58.88H153.6z m641.024 834.56H218.624v-768h576v768z" fill="#ffffff" p-id="3024"></path><path d="M399.36 228.352h-35.84c-2.048 0-4.608 1.536-5.12 3.584l-31.232 186.368c-0.512 4.096 2.56 7.68 6.144 7.68h32.768c2.048 0 4.096-1.536 4.096-3.584l33.28-188.416c1.024-3.072-1.024-5.632-4.096-5.632zM537.088 242.176c-8.704-10.24-23.552-15.36-39.424-15.36-15.872 0-32.256 5.12-44.544 15.36-12.288 9.728-19.968 22.016-23.552 42.496l-15.36 86.016c-3.584 20.48 0 32.256 8.704 42.496 8.704 10.24 23.552 15.36 39.424 15.36 15.872 0 32.256-5.12 44.544-15.36 12.288-9.728 19.968-22.016 23.552-42.496l15.36-86.016c3.584-20.48 0-32.768-8.704-42.496z m-35.328 40.96l-15.872 89.6c-2.048 10.752-8.704 16.384-16.896 16.384s-12.8-5.12-11.264-16.384l15.872-89.6c2.048-10.752 8.704-16.384 16.896-16.384 8.192 0 13.312 5.12 11.264 16.384zM676.352 242.176c-8.704-10.24-23.552-15.36-39.424-15.36s-32.256 5.12-44.544 15.36c-12.288 9.728-19.968 22.016-23.552 42.496l-15.36 86.016c-3.584 20.48 0 32.256 8.704 42.496 8.704 10.24 23.552 15.36 39.424 15.36 15.872 0 32.256-5.12 44.544-15.36 12.288-9.728 19.968-22.016 23.552-42.496l15.36-86.016c3.584-20.48 0-32.768-8.704-42.496z m-35.328 40.96l-15.872 89.6c-2.048 10.752-8.704 16.384-16.896 16.384s-12.8-5.12-11.264-16.384l15.872-89.6c2.048-10.752 8.704-16.384 16.896-16.384 8.192 0 13.312 5.12 11.264 16.384zM313.856 515.584h347.648V573.44H313.856zM313.856 638.976h275.968v57.856H313.856zM313.856 767.488h275.968v57.856H313.856z" fill="#ffffff" p-id="3025"></path></svg>
|
After Width: | Height: | Size: 1.6 KiB |
|
@ -55,8 +55,11 @@
|
||||||
@sort-change="changeSort"
|
@sort-change="changeSort"
|
||||||
>
|
>
|
||||||
<el-table-column type="index" width="50"></el-table-column>
|
<el-table-column type="index" width="50"></el-table-column>
|
||||||
<el-table-column align="left" label="类型">
|
<!-- <el-table-column align="left" label="类型">
|
||||||
<template slot-scope="scope">{{ scope.row.type }}</template>
|
<template slot-scope="scope">{{ scope.row.type }}</template>
|
||||||
|
</el-table-column> -->
|
||||||
|
<el-table-column align="left" label="考试名称">
|
||||||
|
<template slot-scope="scope">{{ scope.row.exam_name }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="left" label="用户">
|
<el-table-column align="left" label="用户">
|
||||||
<template slot-scope="scope">{{ scope.row.create_by_name}}</template>
|
<template slot-scope="scope">{{ scope.row.create_by_name}}</template>
|
||||||
|
@ -82,20 +85,32 @@
|
||||||
<el-table-column align="left" label="答题时间">
|
<el-table-column align="left" label="答题时间">
|
||||||
<template slot-scope="scope">{{ scope.row.start_time }}</template>
|
<template slot-scope="scope">{{ scope.row.start_time }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<el-table-column align="left" label="证书路径" prop="cert_path">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<img v-if="scope.row.cert_path" :src="scope.row.cert_path" @click="handlePictureCardPreview(scope.row.cert_path)" alt="图片" height="30" width="50"/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="left" label="单位名称">
|
||||||
|
<template slot-scope="scope">{{ scope.row.blong_dept_name }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="left" label="考试时间">
|
||||||
|
<template slot-scope="scope">{{ scope.row.create_time }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column align="center" label="操作" fixed="right">
|
<el-table-column align="center" label="操作" fixed="right">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button
|
<!-- <el-button
|
||||||
v-if="scope.row.type=='正式考试'"
|
v-if="scope.row.type=='正式考试'"
|
||||||
type="primary"
|
type="primary"
|
||||||
size="small"
|
size="small"
|
||||||
@click="handleExport(scope)"
|
@click="handleExport(scope)"
|
||||||
>生成Word</el-button>
|
>生成Word</el-button> -->
|
||||||
<el-button
|
<!-- <el-button
|
||||||
v-if="scope.row.type=='正式考试'"
|
v-if="scope.row.type=='正式考试'"
|
||||||
type="warning"
|
type="warning"
|
||||||
size="small"
|
size="small"
|
||||||
@click="handleExport2(scope)"
|
@click="handleExport2(scope)"
|
||||||
>重新生成</el-button>
|
>重新生成</el-button> -->
|
||||||
<el-button
|
<el-button
|
||||||
v-if="scope.row.type=='正式考试'"
|
v-if="scope.row.type=='正式考试'"
|
||||||
type="danger"
|
type="danger"
|
||||||
|
@ -116,14 +131,13 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { getExamRecordList, exportTest, exportwTest, deleteExamRecord,issue } from "@/api/exam";
|
import { getExamRecordList, exportRecord, exportwTest, deleteExamRecord,issue } from "@/api/exam";
|
||||||
import checkPermission from "@/utils/permission";
|
import checkPermission from "@/utils/permission";
|
||||||
import Pagination from "@/components/Pagination";
|
import Pagination from "@/components/Pagination";
|
||||||
|
|
||||||
const listQuery = {
|
const listQuery = {
|
||||||
page: 1,
|
page: 1,
|
||||||
limit: 20,
|
limit: 20,
|
||||||
type:'正式考试',
|
|
||||||
search:''
|
search:''
|
||||||
};
|
};
|
||||||
export default {
|
export default {
|
||||||
|
@ -193,13 +207,13 @@
|
||||||
methods: {
|
methods: {
|
||||||
checkPermission,
|
checkPermission,
|
||||||
getQuery() {
|
getQuery() {
|
||||||
if(this.$route.params.exam){
|
if(this.$route.query.exam){
|
||||||
this.listQuery.exam = this.$route.params.exam;
|
this.listQuery.exam = this.$route.query.exam;
|
||||||
this.getList()
|
|
||||||
}else{
|
|
||||||
this.getList()
|
|
||||||
}
|
}
|
||||||
|
this.getList()
|
||||||
|
},
|
||||||
|
handlePictureCardPreview(url){
|
||||||
|
window.open(url);
|
||||||
},
|
},
|
||||||
getList() {
|
getList() {
|
||||||
this.listLoading = true;
|
this.listLoading = true;
|
||||||
|
@ -216,11 +230,10 @@
|
||||||
this.listQuery = {
|
this.listQuery = {
|
||||||
page: 1,
|
page: 1,
|
||||||
limit: 20,
|
limit: 20,
|
||||||
type:'正式考试',
|
|
||||||
search:'',
|
search:'',
|
||||||
};
|
};
|
||||||
this.value = []
|
this.value = []
|
||||||
this.getList();
|
// this.getList();
|
||||||
},
|
},
|
||||||
handleExport(scope) {
|
handleExport(scope) {
|
||||||
const loading = this.$loading({text: '正在生成word...',});
|
const loading = this.$loading({text: '正在生成word...',});
|
||||||
|
@ -236,7 +249,7 @@
|
||||||
type: "error"
|
type: "error"
|
||||||
})
|
})
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
await deleteExamtest(scope.row.id);
|
await deleteExamRecord(scope.row.id);
|
||||||
this.getList()
|
this.getList()
|
||||||
this.$message({
|
this.$message({
|
||||||
type: "success",
|
type: "success",
|
||||||
|
@ -256,10 +269,10 @@
|
||||||
},
|
},
|
||||||
exportTest() {
|
exportTest() {
|
||||||
const loading = this.$loading();
|
const loading = this.$loading();
|
||||||
exportTest(this.listQuery).then(response => {
|
exportRecord(this.listQuery).then(res=>{
|
||||||
loading.close()
|
loading.close()
|
||||||
window.open(response.data.path, "_blank");
|
window.open(res.data.path, "_blank");
|
||||||
});
|
}).catch(e=>{loading.close()})
|
||||||
},
|
},
|
||||||
setTimeRange(){
|
setTimeRange(){
|
||||||
this.listQuery.start = this.value[0],
|
this.listQuery.start = this.value[0],
|
||||||
|
|
|
@ -39,9 +39,9 @@
|
||||||
<el-table-column label="考试地点">
|
<el-table-column label="考试地点">
|
||||||
<template slot-scope="scope">{{ scope.row.place }}</template>
|
<template slot-scope="scope">{{ scope.row.place }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="参考机会">
|
<!-- <el-table-column label="参考机会">
|
||||||
<template slot-scope="scope">{{ scope.row.chance }}</template>
|
<template slot-scope="scope">{{ scope.row.chance }}</template>
|
||||||
</el-table-column>
|
</el-table-column> -->
|
||||||
<el-table-column label="开启时间">
|
<el-table-column label="开启时间">
|
||||||
<template slot-scope="scope">{{ scope.row.open_time }}</template>
|
<template slot-scope="scope">{{ scope.row.open_time }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
@ -96,9 +96,9 @@
|
||||||
<el-form-item label="考试地点" prop="place">
|
<el-form-item label="考试地点" prop="place">
|
||||||
<el-input v-model="exam.place" placeholder="考试地点" />
|
<el-input v-model="exam.place" placeholder="考试地点" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="参考机会" prop="chance">
|
<!-- <el-form-item label="参考机会" prop="chance">
|
||||||
<el-input-number v-model="exam.chance" placeholder="参考机会" :min="1"/>
|
<el-input-number v-model="exam.chance" placeholder="参考机会" :min="1"/>
|
||||||
</el-form-item>
|
</el-form-item> -->
|
||||||
<el-form-item label="开启时间" prop="open_time">
|
<el-form-item label="开启时间" prop="open_time">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
v-model="exam.open_time"
|
v-model="exam.open_time"
|
||||||
|
@ -154,17 +154,27 @@
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="考试部门" prop="participant_dep" style="width:100%" clearable collapse-tags filterable >
|
<el-form-item label="考试部门" prop="participant_dep" style="width:100%" clearable collapse-tags filterable >
|
||||||
<el-button @click="selectAll">全选部门</el-button>
|
<!-- <el-button @click="selectAll">全选部门</el-button> -->
|
||||||
<el-select v-model="exam.participant_dep" multiple collapse-tags filterable placeholder = "选择部门" >
|
<!-- <el-select v-model="exam.participant_dep" multiple collapse-tags filterable placeholder = "选择部门" >
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in depOptions"
|
v-for="item in depOptions"
|
||||||
:key = "item.id"
|
:key = "item.id"
|
||||||
:label = "item.name"
|
:label = "item.name"
|
||||||
:value = "item.id">
|
:value = "item.id">
|
||||||
</el-option>
|
</el-option>
|
||||||
</el-select>
|
</el-select> -->
|
||||||
|
<div>
|
||||||
|
<el-transfer
|
||||||
|
:props="{key: 'id',label: 'name'}"
|
||||||
|
:data="depOptions"
|
||||||
|
v-model="exam.participant_dep"
|
||||||
|
:titles="['未选部门','指定考试部门']"
|
||||||
|
@change="handleChange"
|
||||||
|
@on-change="handleOnChange"
|
||||||
|
></el-transfer>
|
||||||
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<!-- <el-form-item label="考试人员" prop="participant_user" style="width:100%" clearable>
|
<!-- <el-form-item label="考试人员" prop="participant_user" style="width:100%" clearable>
|
||||||
<el-select v-model="exam.participant_user" multiple filterable placeholder = "请选择人员">
|
<el-select v-model="exam.participant_user" multiple filterable placeholder = "请选择人员">
|
||||||
<el-option
|
<el-option
|
||||||
|
@ -184,6 +194,7 @@
|
||||||
:total="total"
|
:total="total"
|
||||||
></el-pagination>
|
></el-pagination>
|
||||||
</el-form-item> -->
|
</el-form-item> -->
|
||||||
|
|
||||||
</el-form>
|
</el-form>
|
||||||
<div style="text-align:right;">
|
<div style="text-align:right;">
|
||||||
<el-button type="danger" @click="dialogVisible=false">取消</el-button>
|
<el-button type="danger" @click="dialogVisible=false">取消</el-button>
|
||||||
|
@ -197,7 +208,11 @@
|
||||||
import {getUserList} from "@/api/user";
|
import {getUserList} from "@/api/user";
|
||||||
import checkPermission from "@/utils/permission";
|
import checkPermission from "@/utils/permission";
|
||||||
import Pagination from "@/components/Pagination"
|
import Pagination from "@/components/Pagination"
|
||||||
|
import Vue from 'vue'
|
||||||
|
// import ElementUI from 'element-ui'
|
||||||
|
// import 'element-ui/lib/theme-chalk/index.css'
|
||||||
|
|
||||||
|
// Vue.use(ElementUI)
|
||||||
|
|
||||||
const defaultexam = {
|
const defaultexam = {
|
||||||
id: "",
|
id: "",
|
||||||
|
@ -207,7 +222,7 @@
|
||||||
close_time: null,
|
close_time: null,
|
||||||
proctor_name:'',
|
proctor_name:'',
|
||||||
proctor_phone:'',
|
proctor_phone:'',
|
||||||
chance:3,
|
chance:1,
|
||||||
paper:'',
|
paper:'',
|
||||||
certificate:'',
|
certificate:'',
|
||||||
course_name:[],
|
course_name:[],
|
||||||
|
@ -270,9 +285,9 @@
|
||||||
this.paperOptions = res.data
|
this.paperOptions = res.data
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
selectAll(){
|
// selectAll(){
|
||||||
this.exam.participant_dep = this.depOptions.map(option => option.id);
|
// this.exam.participant_dep = this.depOptions.map(option => option.id);
|
||||||
},
|
// },
|
||||||
getList() {
|
getList() {
|
||||||
this.listLoading = true;
|
this.listLoading = true;
|
||||||
debugger;
|
debugger;
|
||||||
|
@ -281,6 +296,12 @@
|
||||||
this.listLoading = false;
|
this.listLoading = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
handleChange(value, direction, movedKeys) {
|
||||||
|
console.log(value, direction, movedKeys)
|
||||||
|
},
|
||||||
|
handleOnChange(value, direction, movedKeys) {
|
||||||
|
console.log(value, direction, movedKeys)
|
||||||
|
},
|
||||||
handleSizeChange(val) {
|
handleSizeChange(val) {
|
||||||
// 改变每页显示的条数
|
// 改变每页显示的条数
|
||||||
this.pageSize = val;
|
this.pageSize = val;
|
||||||
|
@ -353,7 +374,7 @@
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
// console.error(err);
|
console.error(err);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleView(scope){
|
handleView(scope){
|
||||||
|
|
|
@ -36,7 +36,8 @@
|
||||||
|
|
||||||
<el-button slot="reference">Excel导入</el-button>
|
<el-button slot="reference">Excel导入</el-button>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
<el-button type="primary" icon="el-icon-download" @click="exportQuestion">导出Excel</el-button>
|
<el-button type="primary" icon="el-icon-download" @click="exportQuestions">导出Excel</el-button>
|
||||||
|
<el-button type="danger" v-if="checkPermission(['question_batch_delete'])" :disabled="this.selects.length==0" @click="batchDelete()">批量删除</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-table :data="tableData" style="width: 100%;margin-top:10px;" border stripe fit v-loading="listLoading"
|
<el-table :data="tableData" style="width: 100%;margin-top:10px;" border stripe fit v-loading="listLoading"
|
||||||
|
@ -104,6 +105,7 @@
|
||||||
importQuestion,
|
importQuestion,
|
||||||
exportQuestion,
|
exportQuestion,
|
||||||
enableQuestions,
|
enableQuestions,
|
||||||
|
deletesQuestion,
|
||||||
} from "@/api/exam";
|
} from "@/api/exam";
|
||||||
import checkPermission from "@/utils/permission";
|
import checkPermission from "@/utils/permission";
|
||||||
import Pagination from "@/components/Pagination";
|
import Pagination from "@/components/Pagination";
|
||||||
|
@ -159,7 +161,6 @@ export default {
|
||||||
handleUploadSuccess(res, file) {
|
handleUploadSuccess(res, file) {
|
||||||
if (res.code == 201) {
|
if (res.code == 201) {
|
||||||
const loading = this.$loading({ text: "正在导入中..." })
|
const loading = this.$loading({ text: "正在导入中..." })
|
||||||
console.log(res.data);
|
|
||||||
importQuestion(res.data).then(response => {
|
importQuestion(res.data).then(response => {
|
||||||
loading.close()
|
loading.close()
|
||||||
if (response.code == 200) {
|
if (response.code == 200) {
|
||||||
|
@ -235,7 +236,7 @@ export default {
|
||||||
// console.error(err);
|
// console.error(err);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
exportQuestion() {
|
exportQuestions() {
|
||||||
const loading = this.$loading({
|
const loading = this.$loading({
|
||||||
text: '正在准备..'
|
text: '正在准备..'
|
||||||
});
|
});
|
||||||
|
@ -244,6 +245,34 @@ export default {
|
||||||
window.open(response.data.path, "_blank");
|
window.open(response.data.path, "_blank");
|
||||||
}).catch(e => { loading.close() });
|
}).catch(e => { loading.close() });
|
||||||
},
|
},
|
||||||
|
batchDelete() {
|
||||||
|
if (this.selects.length === 0) {
|
||||||
|
this.$message({
|
||||||
|
message: '请选择要删除的项',
|
||||||
|
type: 'warning'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}else{
|
||||||
|
// 删除前的提示
|
||||||
|
this.$confirm("确认删除记录吗?", "提示", {
|
||||||
|
type: "warning",
|
||||||
|
}).then(() => {
|
||||||
|
console.log(this.selects)
|
||||||
|
this.deleteItems(this.selects);
|
||||||
|
this.getList()});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
deleteItems(ids){
|
||||||
|
let item = {ids:ids};
|
||||||
|
deletesQuestion(item).then(response => {
|
||||||
|
if (response.code == 200) {
|
||||||
|
this.$message.success("删除成功");
|
||||||
|
this.getList();
|
||||||
|
} else {
|
||||||
|
this.$message.error(response.msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
changeSort(val) {
|
changeSort(val) {
|
||||||
if (val.order == "ascending") {
|
if (val.order == "ascending") {
|
||||||
this.listQuery.ordering = val.prop;
|
this.listQuery.ordering = val.prop;
|
||||||
|
|
|
@ -86,7 +86,7 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="submitForm('Form')" :loading="submitLoding">保存</el-button>
|
<el-button type="primary" @click="submitForm('Form')" :loading="submitLoding">保存</el-button>
|
||||||
<el-button type="warning" @click="goBack()">返回</el-button>
|
<el-button type="warning" @click="goBack()" v-if="qid==null">返回</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -97,6 +97,7 @@ import { upUrl } from "@/api/file";
|
||||||
import { getToken } from "@/utils/auth";
|
import { getToken } from "@/utils/auth";
|
||||||
export default {
|
export default {
|
||||||
components:{ },
|
components:{ },
|
||||||
|
props:["qid"],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
upHeaders: { Authorization: "JWT " + getToken() },
|
upHeaders: { Authorization: "JWT " + getToken() },
|
||||||
|
@ -135,7 +136,12 @@ export default {
|
||||||
watch:{
|
watch:{
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.Form.id = this.$route.query.id //接收参数
|
if(this.qid) {
|
||||||
|
this.Form.id = this.qid
|
||||||
|
}else{
|
||||||
|
this.Form.id = this.$route.query.id //接收参数
|
||||||
|
}
|
||||||
|
|
||||||
this.getQuestion();
|
this.getQuestion();
|
||||||
this.getQuestioncatAll()
|
this.getQuestioncatAll()
|
||||||
},
|
},
|
||||||
|
@ -169,7 +175,12 @@ export default {
|
||||||
type: "success",
|
type: "success",
|
||||||
message: "修改成功!"
|
message: "修改成功!"
|
||||||
});
|
});
|
||||||
this.goBack()
|
if (this.qid){
|
||||||
|
this.$emit("updateQuestion", this.Form)
|
||||||
|
}else{
|
||||||
|
this.goBack()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -54,12 +54,12 @@
|
||||||
icon="el-icon-edit"
|
icon="el-icon-edit"
|
||||||
:disabled="!checkPermission(['paper_update'])"
|
:disabled="!checkPermission(['paper_update'])"
|
||||||
></el-button>
|
></el-button>
|
||||||
<el-button
|
<!-- <el-button
|
||||||
type="warning"
|
type="warning"
|
||||||
size="small"
|
size="small"
|
||||||
@click="handleClone(scope)"
|
@click="handleClone(scope)"
|
||||||
:disabled="!checkPermission(['paper_clone'])"
|
:disabled="!checkPermission(['paper_clone'])"
|
||||||
>克隆</el-button>
|
>克隆</el-button> -->
|
||||||
<el-button
|
<el-button
|
||||||
type="danger"
|
type="danger"
|
||||||
size="small"
|
size="small"
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
<el-row>
|
<el-row :gutter="6">
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<h3>基本信息</h3>
|
<el-card header="试卷信息">
|
||||||
<el-form :model="Form" :rules="rules" ref="Form" label-width="100px" status-icon>
|
<el-form :model="Form" :rules="rules" ref="Form" label-width="100px" status-icon>
|
||||||
<el-form-item label="名称" prop="name">
|
<el-form-item label="名称" prop="name">
|
||||||
<el-input v-model="Form.name" style="width:80%"></el-input>
|
<el-input v-model="Form.name" style="width:80%"></el-input>
|
||||||
|
@ -42,9 +42,10 @@
|
||||||
<el-button type="warning" @click="goBack()">返回</el-button>
|
<el-button type="warning" @click="goBack()">返回</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="16">
|
<el-col :span="16">
|
||||||
<h3>选题信息</h3>
|
<el-card header="试题信息">
|
||||||
<!-- <div> -->
|
<!-- <div> -->
|
||||||
<div style="display: flex;">
|
<div style="display: flex;">
|
||||||
<el-button type="primary" @click="handleChoose" icon="el-icon-plus" style="margin-right: 10px;">选择试题</el-button>
|
<el-button type="primary" @click="handleChoose" icon="el-icon-plus" style="margin-right: 10px;">选择试题</el-button>
|
||||||
|
@ -86,34 +87,45 @@
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
<div v-for="(item, index) in questions">
|
<draggable v-model="questions">
|
||||||
<h4>
|
<el-card style="margin-top: 4px" shadow="never" v-for="(item, index) in questions" v-bind:key="index">
|
||||||
<el-button
|
<div slot="header" style="display: flex;">
|
||||||
type="danger"
|
<span>第{{ index+1 }}题</span>
|
||||||
size="small"
|
<el-link style="margin-left: auto; margin-right: 8px" type="primary" @click="handleEdit(item, index)" icon="el-icon-edit"></el-link>
|
||||||
@click="handleDelete(index)"
|
<el-link style="margin-right: 4px" type="danger" @click="handleDelete(index)" icon="el-icon-remove"></el-link>
|
||||||
icon="el-icon-delete"
|
<el-link style="margin-right: 4px" type="danger" @click="handleDelete2(item, index)" icon="el-icon-delete"></el-link>
|
||||||
></el-button>
|
</div>
|
||||||
{{ index+1 }} -
|
<div style="font-weight: bold;">
|
||||||
<el-tag>{{item.type}}</el-tag>
|
<el-tag>{{item.type}}</el-tag>
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
<span>(正确答案:{{item.right}})</span>
|
<span>(正确答案:{{item.right}})</span>
|
||||||
</h4>
|
</div>
|
||||||
<div v-for="(value, name) in item.options">{{ name }}: {{ value }}</div>
|
<div style="font-size: 14px;" v-for="(value, name) in item.options">{{ name }}: {{ value }}</div>
|
||||||
</div>
|
</el-card>
|
||||||
|
</draggable>
|
||||||
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<Questionchoose v-bind:chooseVisible="chooseVisible" @closeDg="closeDg" @choseQ="choseQ"></Questionchoose>
|
<Questionchoose v-bind:chooseVisible="chooseVisible" @closeDg="closeDg" @choseQ="choseQ"></Questionchoose>
|
||||||
|
<el-dialog title="编辑题目" :visible.sync="qDialog">
|
||||||
|
<QuestionUpdate v-if="qDialog" :qid="qid" @updateQuestion="updateQuestion"></QuestionUpdate>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { getQuestioncatList, createPaper, UploadPaper } from "@/api/exam";
|
import { getQuestioncatList, createPaper, UploadPaper, deleteQuestion } from "@/api/exam";
|
||||||
import Questionchoose from "@/views/exam/questionChoose";
|
import Questionchoose from "@/views/exam/questionChoose";
|
||||||
import { upUrl, upHeaders } from "@/api/file";
|
import { upUrl, upHeaders } from "@/api/file";
|
||||||
|
import draggable from 'vuedraggable';
|
||||||
|
import QuestionUpdate from "./questionupdate.vue";
|
||||||
export default {
|
export default {
|
||||||
components: { Questionchoose },
|
components: { Questionchoose, draggable, QuestionUpdate },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
qDialog: false,
|
||||||
|
qid: null,
|
||||||
|
currentEditIndex: null,
|
||||||
questions: [],
|
questions: [],
|
||||||
Form: {
|
Form: {
|
||||||
name: "",
|
name: "",
|
||||||
|
@ -164,6 +176,15 @@
|
||||||
this.getQuestioncat();
|
this.getQuestioncat();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
updateQuestion(data){
|
||||||
|
this.qDialog = false;
|
||||||
|
this.questions[this.currentEditIndex] = data;
|
||||||
|
},
|
||||||
|
handleEdit(item, index) {
|
||||||
|
this.qDialog = true;
|
||||||
|
this.qid = item.id;
|
||||||
|
this.currentEditIndex = index;
|
||||||
|
},
|
||||||
getQuestioncat() {
|
getQuestioncat() {
|
||||||
getQuestioncatList().then(response => {
|
getQuestioncatList().then(response => {
|
||||||
this.workscopeData = response.data.results;
|
this.workscopeData = response.data.results;
|
||||||
|
@ -180,10 +201,8 @@
|
||||||
let that =this;
|
let that =this;
|
||||||
if (res.code == 201){
|
if (res.code == 201){
|
||||||
that.impForm.doc_path = res.data.path;
|
that.impForm.doc_path = res.data.path;
|
||||||
console.log(that.impForm)
|
|
||||||
UploadPaper(that.impForm).then(res => {
|
UploadPaper(that.impForm).then(res => {
|
||||||
if (res.code == 200) {
|
if (res.code == 200) {
|
||||||
console.log(res.data)
|
|
||||||
that.questions = res.data;
|
that.questions = res.data;
|
||||||
|
|
||||||
that.$message({
|
that.$message({
|
||||||
|
@ -236,6 +255,21 @@
|
||||||
handleDelete(val) {
|
handleDelete(val) {
|
||||||
this.questions.splice(val, 1);
|
this.questions.splice(val, 1);
|
||||||
},
|
},
|
||||||
|
handleDelete2(item, val){
|
||||||
|
|
||||||
|
deleteQuestion(item.id).then(res=>{
|
||||||
|
console.log(res)
|
||||||
|
if (res.code ==204) {
|
||||||
|
this.$message({
|
||||||
|
type: "success",
|
||||||
|
message: "删除成功!"
|
||||||
|
});
|
||||||
|
this.questions.splice(val, 1);
|
||||||
|
}
|
||||||
|
}).catch(res=>{
|
||||||
|
console.log(res)
|
||||||
|
})
|
||||||
|
},
|
||||||
calScore() {
|
calScore() {
|
||||||
let danxuan_count = 0,
|
let danxuan_count = 0,
|
||||||
duoxuan_count = 0,
|
duoxuan_count = 0,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
<el-row>
|
<el-row :gutter="6">
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<h3>基本信息</h3>
|
<el-card header="试卷信息">
|
||||||
<el-form :model="Form" :rules="rules" ref="Form" label-width="100px" status-icon>
|
<el-form :model="Form" :rules="rules" ref="Form" label-width="100px" status-icon>
|
||||||
<el-form-item label="名称" prop="name">
|
<el-form-item label="名称" prop="name">
|
||||||
<el-input v-model="Form.name" style="width:80%"></el-input>
|
<el-input v-model="Form.name" style="width:80%"></el-input>
|
||||||
|
@ -42,38 +42,48 @@
|
||||||
<el-button type="warning" @click="goBack()">返回</el-button>
|
<el-button type="warning" @click="goBack()">返回</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="16">
|
<el-col :span="16">
|
||||||
<h3>选题信息</h3>
|
<el-card header="试题信息">
|
||||||
<el-button type="primary" @click="handleChoose" icon="el-icon-plus">选择试题</el-button>
|
<el-button type="primary" @click="handleChoose" icon="el-icon-plus">选择试题</el-button>
|
||||||
<div v-for="(item, index) in questions">
|
<draggable v-model="questions">
|
||||||
<h4>
|
<el-card style="margin-top: 4px" shadow="never" v-for="(item, index) in questions" v-bind:key="index">
|
||||||
<el-button
|
<div slot="header" style="display: flex;">
|
||||||
type="danger"
|
<span>第{{ index+1 }}题</span>
|
||||||
size="small"
|
<el-link style="margin-left: auto; margin-right: 8px" type="primary" @click="handleEdit(item, index)" icon="el-icon-edit"></el-link>
|
||||||
@click="handleDelete(index)"
|
<el-link style="margin-right: 4px" type="danger" @click="handleDelete(index)" icon="el-icon-delete"></el-link>
|
||||||
icon="el-icon-delete"
|
</div>
|
||||||
></el-button>
|
<div style="font-weight: bold;">
|
||||||
{{ index+1 }} -
|
|
||||||
<el-tag>{{item.type}}</el-tag>
|
<el-tag>{{item.type}}</el-tag>
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
<span>(正确答案:{{item.right}})</span>
|
<span>(正确答案:{{item.right}})</span>
|
||||||
</h4>
|
</div>
|
||||||
<div v-for="(value, name) in item.options">{{ name }}: {{ value }}</div>
|
<div style="font-size: 14px;" v-for="(value, name) in item.options">{{ name }}: {{ value }}</div>
|
||||||
</div>
|
</el-card>
|
||||||
|
</draggable>
|
||||||
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<Questionchoose v-bind:chooseVisible="chooseVisible" @closeDg="closeDg" @choseQ="choseQ"></Questionchoose>
|
<Questionchoose v-bind:chooseVisible="chooseVisible" @closeDg="closeDg" @choseQ="choseQ"></Questionchoose>
|
||||||
|
<el-dialog title="编辑题目" :visible.sync="qDialog">
|
||||||
|
<QuestionUpdate v-if="qDialog" :qid="qid" @updateQuestion="updateQuestion"></QuestionUpdate>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { getQuestioncatList, updatePaper,getPaperDetail } from "@/api/exam";
|
import { getQuestioncatList, updatePaper,getPaperDetail } from "@/api/exam";
|
||||||
import { genTree } from "@/utils";
|
import { genTree } from "@/utils";
|
||||||
import Questionchoose from "@/views/exam/questionChoose";
|
import Questionchoose from "@/views/exam/questionChoose";
|
||||||
|
import draggable from 'vuedraggable';
|
||||||
|
import QuestionUpdate from "./questionupdate.vue";
|
||||||
export default {
|
export default {
|
||||||
components: { Questionchoose },
|
components: { Questionchoose, draggable, QuestionUpdate },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
qDialog: false,
|
||||||
|
qid: null,
|
||||||
|
currentEditIndex: null,
|
||||||
questions: [],
|
questions: [],
|
||||||
Form: {
|
Form: {
|
||||||
name: "",
|
name: "",
|
||||||
|
@ -116,6 +126,16 @@
|
||||||
this.getPaperDetail();
|
this.getPaperDetail();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
updateQuestion(data){
|
||||||
|
this.qDialog = false;
|
||||||
|
data["question"] = data["id"]
|
||||||
|
this.questions[this.currentEditIndex] = data;
|
||||||
|
},
|
||||||
|
handleEdit(item, index) {
|
||||||
|
this.qDialog = true;
|
||||||
|
this.qid = item.question;
|
||||||
|
this.currentEditIndex = index;
|
||||||
|
},
|
||||||
getQuestioncat() {
|
getQuestioncat() {
|
||||||
getQuestioncatList().then(response => {
|
getQuestioncatList().then(response => {
|
||||||
this.workscopeData = genTree(response.data);
|
this.workscopeData = genTree(response.data);
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
:value="item.key"
|
:value="item.key"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-select
|
<!-- <el-select
|
||||||
v-model="listQuery.roles"
|
v-model="listQuery.roles"
|
||||||
placeholder="角色"
|
placeholder="角色"
|
||||||
style="width: 90px"
|
style="width: 90px"
|
||||||
|
@ -55,7 +55,7 @@
|
||||||
:label="item.label"
|
:label="item.label"
|
||||||
:value="item.value"
|
:value="item.value"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select> -->
|
||||||
<el-input
|
<el-input
|
||||||
v-model="listQuery.search"
|
v-model="listQuery.search"
|
||||||
placeholder="姓名/邮箱"
|
placeholder="姓名/邮箱"
|
||||||
|
@ -115,16 +115,16 @@
|
||||||
</el-form>
|
</el-form>
|
||||||
<div style="text-align: right">
|
<div style="text-align: right">
|
||||||
<el-button type="danger" @click="close_dialog">取消</el-button>
|
<el-button type="danger" @click="close_dialog">取消</el-button>
|
||||||
<el-button type="primary" @click="submitUpload" :disabled="saveLoading">确认</el-button>
|
<el-button type="primary" @click="submitUpload">确认</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
<div style="margin-top: 10px">
|
|
||||||
<el-button type="primary" icon="el-icon-plus" @click="handleAddUser"
|
<div style="margin-top: 10px">
|
||||||
>新增</el-button
|
<el-button type="primary" icon="el-icon-plus" @click="handleAddUser"
|
||||||
>
|
>新增</el-button>
|
||||||
</div>
|
</div>
|
||||||
<el-table
|
<el-table
|
||||||
v-loading="listLoading"
|
v-loading="listLoading"
|
||||||
:data="userList.results"
|
:data="userList.results"
|
||||||
|
@ -147,7 +147,7 @@
|
||||||
scope.row.dept_name
|
scope.row.dept_name
|
||||||
}}</template>
|
}}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="header-center" label="角色">
|
<!-- <el-table-column align="header-center" label="角色">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-tag
|
<el-tag
|
||||||
style="margin: 2px"
|
style="margin: 2px"
|
||||||
|
@ -158,7 +158,7 @@
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column> -->
|
||||||
<el-table-column label="创建日期">
|
<el-table-column label="创建日期">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<span>{{ scope.row.date_joined }}</span>
|
<span>{{ scope.row.date_joined }}</span>
|
||||||
|
@ -196,6 +196,7 @@
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<pagination
|
<pagination
|
||||||
v-show="userList.count > 0"
|
v-show="userList.count > 0"
|
||||||
:total="userList.count"
|
:total="userList.count"
|
||||||
|
@ -206,6 +207,66 @@
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
<el-dialog
|
||||||
|
:visible.sync="dialogVisible"
|
||||||
|
:title="dialogType === 'edit' ? '编辑用户' : '新增用户'"
|
||||||
|
>
|
||||||
|
<el-form
|
||||||
|
ref="Form"
|
||||||
|
:model="user"
|
||||||
|
label-width="80px"
|
||||||
|
label-position="right"
|
||||||
|
:rules="rule1"
|
||||||
|
>
|
||||||
|
<el-form-item label="姓名" prop="name">
|
||||||
|
<el-input v-model="user.name" placeholder="姓名" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="账户" prop="username">
|
||||||
|
<el-input v-model="user.username" placeholder="账户" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="所属部门" prop="dept">
|
||||||
|
<treeselect
|
||||||
|
v-model="user.dept"
|
||||||
|
:multiple="false"
|
||||||
|
:options="orgData"
|
||||||
|
placeholder="所属部门"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<!-- <el-form-item label="角色" prop="roles">
|
||||||
|
<el-select
|
||||||
|
v-model="user.roles"
|
||||||
|
multiple
|
||||||
|
placeholder="请选择"
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in roles"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item> -->
|
||||||
|
<el-form-item label="头像" prop="dept">
|
||||||
|
<el-upload
|
||||||
|
class="avatar-uploader"
|
||||||
|
:action="upUrl"
|
||||||
|
accept="image/jpeg, image/gif, image/png, image/bmp"
|
||||||
|
:show-file-list="false"
|
||||||
|
:on-success="handleAvatarSuccess"
|
||||||
|
:before-upload="beforeAvatarUpload"
|
||||||
|
:headers="upHeaders"
|
||||||
|
>
|
||||||
|
<img v-if="user.avatar" :src="user.avatar" class="avatar" />
|
||||||
|
<i v-else class="el-icon-plus avatar-uploader-icon" />
|
||||||
|
</el-upload>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<div style="text-align: right">
|
||||||
|
<el-button type="danger" @click="dialogVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="confirm('Form')">确认</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<style>
|
<style>
|
||||||
|
@ -266,9 +327,12 @@ export default {
|
||||||
upHeaders: upHeaders(),
|
upHeaders: upHeaders(),
|
||||||
upUrl: upUrl(),
|
upUrl: upUrl(),
|
||||||
userList: { count: 0 },
|
userList: { count: 0 },
|
||||||
roles: [],
|
// roles: [],
|
||||||
saveLoading:false,
|
saveLoading:false,
|
||||||
fileList: [],
|
fileList: [],
|
||||||
|
impForm:{
|
||||||
|
file:''
|
||||||
|
},
|
||||||
impDialogVisible: false,
|
impDialogVisible: false,
|
||||||
listLoading: true,
|
listLoading: true,
|
||||||
downloadUrl: process.env.VUE_APP_BASE_API,
|
downloadUrl: process.env.VUE_APP_BASE_API,
|
||||||
|
@ -300,7 +364,7 @@ export default {
|
||||||
{ header: '姓名', key: 'name', wpx: 60 },
|
{ header: '姓名', key: 'name', wpx: 60 },
|
||||||
{ header: '账户', key: 'username', wch: 32 },
|
{ header: '账户', key: 'username', wch: 32 },
|
||||||
{ header: '部门', key: 'dept_name', width: 30 },
|
{ header: '部门', key: 'dept_name', width: 30 },
|
||||||
{ header: '角色', key: 'roles', width: 70 }
|
// { header: '角色', key: 'roles', width: 70 }
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -353,11 +417,9 @@ export default {
|
||||||
this.impForm.file = '';
|
this.impForm.file = '';
|
||||||
},
|
},
|
||||||
handleUpSuccess(res, file, filelist) {
|
handleUpSuccess(res, file, filelist) {
|
||||||
this.Content.file = res.data.id;
|
|
||||||
this.impForm.file = res.data.path;
|
this.impForm.file = res.data.path;
|
||||||
},
|
},
|
||||||
handleRemove(file, filelist) {
|
handleRemove(file, filelist) {
|
||||||
this.Content.file = null;
|
|
||||||
this.impForm.file = '';
|
this.impForm.file = '';
|
||||||
},
|
},
|
||||||
handlePreview(file) {
|
handlePreview(file) {
|
||||||
|
@ -438,12 +500,16 @@ export default {
|
||||||
type: "error",
|
type: "error",
|
||||||
})
|
})
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
await deleteUserExam(scope.row.id);
|
deleteUserExam(scope.row.id).then((res) => {
|
||||||
this.userList.splice(scope.row.index, 1);
|
console.log(res);
|
||||||
this.$message.success("成功");
|
if (res.code >= 200) {
|
||||||
|
// this.userList.splice(scope.row.index, 1);
|
||||||
|
this.$message.success("成功");
|
||||||
|
this.getList();
|
||||||
|
};
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
async confirm(form) {
|
async confirm(form) {
|
||||||
|
@ -454,9 +520,11 @@ export default {
|
||||||
updateUser(this.user.id, this.user).then((res) => {
|
updateUser(this.user.id, this.user).then((res) => {
|
||||||
if (res.code >= 200) {
|
if (res.code >= 200) {
|
||||||
this.getList();
|
this.getList();
|
||||||
this.dialogVisible = false;
|
this.dialogVisible = true;
|
||||||
|
this.impForm.file = ''
|
||||||
this.$message.success("成功");
|
this.$message.success("成功");
|
||||||
}
|
};
|
||||||
|
this.impForm.file = ''
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
createUser(this.user).then((res) => {
|
createUser(this.user).then((res) => {
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
# Generated by Django 3.2.12 on 2024-06-04 09:28
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('exam', '0001_initial'),
|
||||||
|
('edu', '0006_certificate_examrecord'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='certificate',
|
||||||
|
name='examrecord',
|
||||||
|
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='cert_er', to='exam.examrecord'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.2.12 on 2024-06-06 01:44
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('edu', '0007_alter_certificate_examrecord'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='certificate',
|
||||||
|
name='用户ID',
|
||||||
|
field=models.IntegerField(blank=True, max_length=32, null=True),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,21 @@
|
||||||
|
# Generated by Django 3.2.12 on 2024-06-06 02:26
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
('edu', '0008_certificate_用户id'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='certificate',
|
||||||
|
name='用户ID',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||||
|
),
|
||||||
|
]
|
|
@ -26,7 +26,8 @@ class Certificate(CommonADModel):
|
||||||
是否需要北京标研培训合格 = models.BooleanField(default=False)
|
是否需要北京标研培训合格 = models.BooleanField(default=False)
|
||||||
课程列表 = models.ManyToManyField(Course, blank=True)
|
课程列表 = models.ManyToManyField(Course, blank=True)
|
||||||
培训日期 = models.DateField(null=True, blank=True)
|
培训日期 = models.DateField(null=True, blank=True)
|
||||||
培训结束日期 = models.DateField(null=True, blank=True)
|
培训结束日期 = models.DateField(null=True, blank=True)
|
||||||
发证日期 = models.DateField(null=True, blank=True)
|
发证日期 = models.DateField(null=True, blank=True)
|
||||||
证书地址 = models.CharField(max_length=100, null=True, blank=True)
|
证书地址 = models.CharField(max_length=100, null=True, blank=True)
|
||||||
examrecord = models.ForeignKey('exam.ExamRecord', on_delete=models.CASCADE, null=True, blank=True)
|
用户ID = models.ForeignKey(null=True, blank=True, to='system.User', on_delete=models.CASCADE)
|
||||||
|
examrecord = models.OneToOneField('exam.ExamRecord', on_delete=models.CASCADE, null=True, blank=True, related_name='cert_er')
|
||||||
|
|
|
@ -5,7 +5,7 @@ from openpyxl.styles import Font, Fill
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
|
||||||
def export_question(questions):
|
def export_question(questions:object):
|
||||||
'''
|
'''
|
||||||
params: serializer questions
|
params: serializer questions
|
||||||
return: xlsx path
|
return: xlsx path
|
||||||
|
@ -24,4 +24,33 @@ def export_question(questions):
|
||||||
if not os.path.exists(full_path):
|
if not os.path.exists(full_path):
|
||||||
os.makedirs(full_path)
|
os.makedirs(full_path)
|
||||||
wb.save(full_path+filename)
|
wb.save(full_path+filename)
|
||||||
return path + filename
|
return path + filename
|
||||||
|
|
||||||
|
|
||||||
|
def export_record(records:object):
|
||||||
|
'''
|
||||||
|
params: serializer records
|
||||||
|
return: xlsx path
|
||||||
|
'''
|
||||||
|
wb = Workbook()
|
||||||
|
ws1 = wb.active
|
||||||
|
ws1.title = '答题记录表'
|
||||||
|
ws1.append(['类型', '用户', '是否通过', '得分', '总分', '耗时(时分秒)', '答题时间', '部门'])
|
||||||
|
row = ws1.row_dimensions[1]
|
||||||
|
row.font = Font(bold=True)
|
||||||
|
for i in records:
|
||||||
|
tookformat = get_took_format(i.took)
|
||||||
|
ws1.append([i.type, i.create_by.name, i.is_pass, i.score, i.total_score, str(tookformat), str(i.start_time), i.belong_dept.name])
|
||||||
|
filename = 'records' + datetime.now().strftime("%Y%m%d%H%M%S") +'.xlsx'
|
||||||
|
path = '/media/temp/'
|
||||||
|
full_path = settings.BASE_DIR + '/media/temp/'
|
||||||
|
if not os.path.exists(full_path):
|
||||||
|
os.makedirs(full_path)
|
||||||
|
wb.save(full_path+filename)
|
||||||
|
return path + filename
|
||||||
|
|
||||||
|
|
||||||
|
def get_took_format(took:int):
|
||||||
|
m, s = divmod(took, 60)
|
||||||
|
h, m = divmod(m, 60)
|
||||||
|
return "%02d:%02d:%02d" % (h, m, s)
|
|
@ -1,6 +1,9 @@
|
||||||
from django_filters import rest_framework as filters
|
from django_filters import rest_framework as filters
|
||||||
|
from django.utils import timezone
|
||||||
from .models import ExamRecord, Exam
|
from .models import ExamRecord, Exam
|
||||||
|
from django.db.models import Q
|
||||||
class ExamRecordFilter(filters.FilterSet):
|
class ExamRecordFilter(filters.FilterSet):
|
||||||
|
is_my = filters.BooleanFilter(method='filter_is_my')
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ExamRecord
|
model = ExamRecord
|
||||||
fields = {
|
fields = {
|
||||||
|
@ -8,9 +11,17 @@ class ExamRecordFilter(filters.FilterSet):
|
||||||
'is_pass': ['exact'],
|
'is_pass': ['exact'],
|
||||||
'type': ['exact'],
|
'type': ['exact'],
|
||||||
'is_submited': ['exact'],
|
'is_submited': ['exact'],
|
||||||
|
'exam': ['exact']
|
||||||
}
|
}
|
||||||
|
def filter_is_my(self, queryset, name, value):
|
||||||
|
if value:
|
||||||
|
user = self.request.user
|
||||||
|
return queryset.filter(create_by=user)
|
||||||
|
return queryset
|
||||||
|
|
||||||
class ExamFilter(filters.FilterSet):
|
class ExamFilter(filters.FilterSet):
|
||||||
|
can_attend = filters.BooleanFilter(method='filter_can_attend')
|
||||||
|
is_my = filters.BooleanFilter(method='filter_is_my')
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Exam
|
model = Exam
|
||||||
fields = {
|
fields = {
|
||||||
|
@ -18,4 +29,17 @@ class ExamFilter(filters.FilterSet):
|
||||||
'paper': ['exact'],
|
'paper': ['exact'],
|
||||||
'code': ['exact'],
|
'code': ['exact'],
|
||||||
'is_open': ['exact']
|
'is_open': ['exact']
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def filter_can_attend(self, queryset, name, value):
|
||||||
|
if value:
|
||||||
|
now = timezone.now()
|
||||||
|
return queryset.filter(open_time__lte=now, close_time__gte=now)| queryset.filter(close_time__isnull=True)
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
def filter_is_my(self, queryset, name, value):
|
||||||
|
if value:
|
||||||
|
user = self.request.user
|
||||||
|
return queryset.filter(Q(participant_user=user)|Q(participant_dep=user.dept)|Q(is_open=True))
|
||||||
|
return queryset
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from apps.system.models import CommonAModel, CommonBModel
|
from apps.system.models import CommonAModel, CommonADModel, CommonBDModel
|
||||||
from django.contrib.postgres.fields import JSONField
|
from django.contrib.postgres.fields import JSONField
|
||||||
from utils.model import BaseModel
|
from utils.model import BaseModel
|
||||||
from apps.edu.models import Course
|
from apps.edu.models import Course
|
||||||
|
@ -20,7 +20,7 @@ class Questioncat(CommonAModel):
|
||||||
return self.questioncat.count()
|
return self.questioncat.count()
|
||||||
|
|
||||||
|
|
||||||
class Question(CommonAModel):
|
class Question(CommonADModel):
|
||||||
type_choices = (
|
type_choices = (
|
||||||
('单选', '单选'),
|
('单选', '单选'),
|
||||||
('多选', '多选'),
|
('多选', '多选'),
|
||||||
|
@ -99,7 +99,7 @@ class Exam(CommonAModel):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
class ExamRecord(CommonBModel):
|
class ExamRecord(CommonBDModel):
|
||||||
'''
|
'''
|
||||||
考试记录表
|
考试记录表
|
||||||
'''
|
'''
|
||||||
|
|
|
@ -94,6 +94,6 @@ def interpret_text(start:int, excel_path:str, doc_path:str, field=None):
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
doc_path = "C:\code\data\\test.docx"
|
doc_path = "C:\code\data\\判断题.docx"
|
||||||
excel_path = "C:\code\data\question.xlsx"
|
excel_path = "C:\code\data\question.xlsx"
|
||||||
interpret_text(3, excel_path, doc_path)
|
interpret_text(3, excel_path, doc_path)
|
|
@ -88,6 +88,7 @@ class ExamListSerializer(ModelSerializer):
|
||||||
course_ = CourseSerializer(source='course_name', read_only=True)
|
course_ = CourseSerializer(source='course_name', read_only=True)
|
||||||
user_count = serializers.SerializerMethodField()
|
user_count = serializers.SerializerMethodField()
|
||||||
submit_count = serializers.SerializerMethodField()
|
submit_count = serializers.SerializerMethodField()
|
||||||
|
limit = CharField(source='paper.limit', read_only=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Exam
|
model = Exam
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
@ -132,6 +133,8 @@ class ExamRecordListSerializer(serializers.ModelSerializer):
|
||||||
source='exam.name', read_only=True)
|
source='exam.name', read_only=True)
|
||||||
blong_dept_name = serializers.CharField(
|
blong_dept_name = serializers.CharField(
|
||||||
source='belong_dept.name', read_only=True)
|
source='belong_dept.name', read_only=True)
|
||||||
|
cert_number = serializers.CharField(source='cert_er.证书编号', read_only=True)
|
||||||
|
cert_path = serializers.CharField(source='cert_er.证书地址', read_only=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ExamRecord
|
model = ExamRecord
|
||||||
exclude = ('detail',)
|
exclude = ('detail',)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from rest_framework.viewsets import ModelViewSet, GenericViewSet
|
from rest_framework.viewsets import ModelViewSet, GenericViewSet
|
||||||
from rest_framework.mixins import ListModelMixin, DestroyModelMixin, RetrieveModelMixin
|
from rest_framework.mixins import ListModelMixin, DestroyModelMixin, RetrieveModelMixin
|
||||||
from apps.exam.exports import export_question
|
from apps.exam.exports import export_question, export_record
|
||||||
from apps.exam.models import Question, Questioncat, PaperQuestion
|
from apps.exam.models import Question, Questioncat, PaperQuestion
|
||||||
from apps.exam.serializers import (QuestionSerializer, QuestioncatSerializer, PaperSerializer, ExamDetailSerializer, ExamRecordDetailSerializer, ExamListSerializer,
|
from apps.exam.serializers import (QuestionSerializer, QuestioncatSerializer, PaperSerializer, ExamDetailSerializer, ExamRecordDetailSerializer, ExamListSerializer,
|
||||||
ExamCreateUpdateSerializer, ExamListSerializer, ExamRecordSubmitSerializer, PaperDetailSerializer, PaperCreateUpdateSerializer, AnswerDetailOutSerializer, ExamRecordListSerializer)
|
ExamCreateUpdateSerializer, ExamListSerializer, ExamRecordSubmitSerializer, PaperDetailSerializer, PaperCreateUpdateSerializer, AnswerDetailOutSerializer, ExamRecordListSerializer)
|
||||||
|
@ -11,7 +11,7 @@ from rest_framework.permissions import IsAuthenticated
|
||||||
from rest_framework.exceptions import ParseError
|
from rest_framework.exceptions import ParseError
|
||||||
from openpyxl import Workbook, load_workbook
|
from openpyxl import Workbook, load_workbook
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from apps.exam.models import Paper, Exam, ExamRecord, AnswerDetail
|
from apps.exam.models import Paper, Exam, ExamRecord, AnswerDetail, PaperQuestion
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from rest_framework.serializers import Serializer
|
from rest_framework.serializers import Serializer
|
||||||
|
@ -20,11 +20,13 @@ from apps.exam.filters import ExamRecordFilter, ExamFilter
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from apps.system.mixins import CreateUpdateCustomMixin
|
from apps.system.mixins import CreateUpdateCustomMixin
|
||||||
from apps.edu.serializers import CertificateSerializer
|
from apps.edu.serializers import CertificateSerializer
|
||||||
|
from apps.edu.models import Certificate
|
||||||
from utils.queryset import get_child_queryset2
|
from utils.queryset import get_child_queryset2
|
||||||
from apps.system.permission import has_permission
|
from apps.system.permission import has_permission
|
||||||
from apps.exam.parse_word import interpret_text
|
from apps.exam.parse_word import interpret_text
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
from django.db.models import Q
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
|
|
||||||
EXCEL_PATH = os.path.join(settings.BASE_DIR, "media/default/question.xlsx")
|
EXCEL_PATH = os.path.join(settings.BASE_DIR, "media/default/question.xlsx")
|
||||||
|
@ -63,22 +65,21 @@ class QuestionViewSet(CreateUpdateCustomMixin, ModelViewSet):
|
||||||
perms_map = {'get': '*', 'post':'question', 'put':'question', 'delete':'question'}
|
perms_map = {'get': '*', 'post':'question', 'put':'question', 'delete':'question'}
|
||||||
queryset = Question.objects.all()
|
queryset = Question.objects.all()
|
||||||
serializer_class = QuestionSerializer
|
serializer_class = QuestionSerializer
|
||||||
filterset_fields = ['level', 'type', 'year']
|
filterset_fields = ['level', 'type', 'year', 'questioncat']
|
||||||
search_fields = ['name', 'options', 'resolution']
|
search_fields = ['name', 'options', 'resolution']
|
||||||
|
|
||||||
|
def destroy(self, request, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
删除题目
|
||||||
|
"""
|
||||||
|
id = kwargs.get('pk', None)
|
||||||
|
# 删除前进行校验,如果存在考试中不允许删除。
|
||||||
|
paperquestion = PaperQuestion.objects.filter(question_id=id).exists()
|
||||||
|
if paperquestion:
|
||||||
|
raise ParseError('此试题存在考试中不允许删除')
|
||||||
|
Question.objects.filter(id=id).delete()
|
||||||
|
return Response("删除成功")
|
||||||
|
|
||||||
@action(methods=['get'], detail=False,
|
|
||||||
url_path='export', url_name='export_question', perms_map=[{'get': '*'}], serializer_class=Serializer)
|
|
||||||
def export_question(self, request):
|
|
||||||
"""
|
|
||||||
导出题目
|
|
||||||
|
|
||||||
导出题目
|
|
||||||
"""
|
|
||||||
queryset = self.filter_queryset(self.get_queryset())
|
|
||||||
path = export_question(queryset)
|
|
||||||
return Response({'path': path})
|
|
||||||
|
|
||||||
@action(methods=['post'], detail=False, url_name='enable_question', perms_map={'post': 'question'}, serializer_class=Serializer)
|
@action(methods=['post'], detail=False, url_name='enable_question', perms_map={'post': 'question'}, serializer_class=Serializer)
|
||||||
def enable(self, request):
|
def enable(self, request):
|
||||||
"""
|
"""
|
||||||
|
@ -90,6 +91,30 @@ class QuestionViewSet(CreateUpdateCustomMixin, ModelViewSet):
|
||||||
if ids:
|
if ids:
|
||||||
Question.objects.filter(pk__in=ids).update(enabled=True)
|
Question.objects.filter(pk__in=ids).update(enabled=True)
|
||||||
return Response(status=200)
|
return Response(status=200)
|
||||||
|
|
||||||
|
@action(methods=['post'], detail=False, perms_map={'*':'question_delete'})
|
||||||
|
def deletes(self, request):
|
||||||
|
"""
|
||||||
|
批量删除
|
||||||
|
"""
|
||||||
|
ids = request.data.get('ids', [])
|
||||||
|
if request.user.is_superuser:
|
||||||
|
# 删除前进行校验,如果存在考试中不允许删除。
|
||||||
|
paperquestion = PaperQuestion.objects.filter(question__id__in=ids).exists()
|
||||||
|
if paperquestion:
|
||||||
|
return Response('此试题存在考试中不允许删除')
|
||||||
|
Question.objects.filter(id__in=ids).update(is_deleted=True)
|
||||||
|
return Response()
|
||||||
|
return Response({'msg':'权限不足'},status=401)
|
||||||
|
|
||||||
|
@action(methods=['get'], detail=False, perms_map={'get':'export_question'})
|
||||||
|
def export(self, request):
|
||||||
|
"""
|
||||||
|
导出题目
|
||||||
|
"""
|
||||||
|
queryset = self.filter_queryset(self.get_queryset())
|
||||||
|
path = export_question(queryset)
|
||||||
|
return Response({'path': path})
|
||||||
|
|
||||||
@action(methods=['post'], detail=False,
|
@action(methods=['post'], detail=False,
|
||||||
url_path='import', url_name='import_question', perms_map={'post': 'question'}, serializer_class=Serializer)
|
url_path='import', url_name='import_question', perms_map={'post': 'question'}, serializer_class=Serializer)
|
||||||
|
@ -269,6 +294,34 @@ class PaperViewSet(ModelViewSet):
|
||||||
PaperQuestion.objects.filter(paper=paper).delete()
|
PaperQuestion.objects.filter(paper=paper).delete()
|
||||||
PaperQuestion.objects.bulk_create(q_list)
|
PaperQuestion.objects.bulk_create(q_list)
|
||||||
return Response()
|
return Response()
|
||||||
|
|
||||||
|
|
||||||
|
@action(methods=['put'], detail=True, url_path='clone', url_name='clone_paper', perms_map={'put':'clone_paper'})
|
||||||
|
def clone(self, request, pk=None):
|
||||||
|
'''
|
||||||
|
克隆试卷
|
||||||
|
'''
|
||||||
|
paper = self.get_object()
|
||||||
|
obj = Paper()
|
||||||
|
obj.name = '克隆卷-'+paper.name
|
||||||
|
obj.workscope = paper.workscope
|
||||||
|
obj.limit = paper.limit
|
||||||
|
obj.total_score = paper.total_score
|
||||||
|
obj.pass_score = paper.pass_score
|
||||||
|
obj.danxuan_count = paper.danxuan_count
|
||||||
|
obj.danxuan_score = paper.danxuan_score
|
||||||
|
obj.duoxuan_count = paper.duoxuan_count
|
||||||
|
obj.duoxuan_score = paper.duoxuan_score
|
||||||
|
obj.panduan_count = paper.panduan_count
|
||||||
|
obj.panduan_score = paper.panduan_score
|
||||||
|
obj.save()
|
||||||
|
for i in PaperQuestion.objects.filter(paper=paper):
|
||||||
|
o = PaperQuestion()
|
||||||
|
o.paper = obj
|
||||||
|
o.question = i.question
|
||||||
|
o.total_score = i.total_score
|
||||||
|
o.save()
|
||||||
|
return Response(status=200)
|
||||||
|
|
||||||
@action(methods=['post'], detail=False, perms_map={'post': 'question'}, serializer_class=Serializer)
|
@action(methods=['post'], detail=False, perms_map={'post': 'question'}, serializer_class=Serializer)
|
||||||
def upload_paper(self, request):
|
def upload_paper(self, request):
|
||||||
|
@ -276,7 +329,6 @@ class PaperViewSet(ModelViewSet):
|
||||||
question_type = request.data.get('question_type')
|
question_type = request.data.get('question_type')
|
||||||
excel_path = settings.BASE_DIR + "/media/default/question.xlsx"
|
excel_path = settings.BASE_DIR + "/media/default/question.xlsx"
|
||||||
doc_path = settings.BASE_DIR + doc_path
|
doc_path = settings.BASE_DIR + doc_path
|
||||||
# excel_path = "C:\code\data\question.xlsx"
|
|
||||||
timenow = timezone.now().strftime('%Y%m%d%H%M%S')
|
timenow = timezone.now().strftime('%Y%m%d%H%M%S')
|
||||||
question_excel_name = "question_excel_"+timenow
|
question_excel_name = "question_excel_"+timenow
|
||||||
question_excel = os.path.join(os.path.dirname(excel_path), question_excel_name)
|
question_excel = os.path.join(os.path.dirname(excel_path), question_excel_name)
|
||||||
|
@ -425,15 +477,23 @@ class ExamViewSet(CreateUpdateCustomMixin, ModelViewSet):
|
||||||
elif self.action in ['retrieve']:
|
elif self.action in ['retrieve']:
|
||||||
return ExamDetailSerializer
|
return ExamDetailSerializer
|
||||||
return super().get_serializer_class()
|
return super().get_serializer_class()
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
qs = super().get_queryset()
|
||||||
|
user = self.request.user
|
||||||
|
if has_permission("exam", user):
|
||||||
|
return qs
|
||||||
|
return qs.filter(Q(participant_user=user)|Q(participant_dep=user.dept)|Q(is_open=True))
|
||||||
|
|
||||||
|
|
||||||
def destroy(self, request, *args, **kwargs):
|
def destroy(self, request, *args, **kwargs):
|
||||||
instance = self.get_object()
|
instance = self.get_object()
|
||||||
if ExamRecord.objects.filter(exam=instance).exists():
|
if ExamRecord.objects.filter(exam=instance).exists():
|
||||||
raise ParseError('存在考试记录,禁止删除')
|
raise ParseError('存在考试记录,禁止删除')
|
||||||
instance.delete(soft=False)
|
instance.delete()
|
||||||
return Response(status=204)
|
return Response(status=204)
|
||||||
|
|
||||||
@action(methods=['post'], detail=True, perms_map=[{'post': '*'}], serializer_class=Serializer, permission_classes = [IsAuthenticated])
|
@action(methods=['post'], detail=True, perms_map={'post': '*'}, serializer_class=Serializer, permission_classes = [IsAuthenticated])
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def start(self, request, *args, **kwargs):
|
def start(self, request, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
@ -441,7 +501,8 @@ class ExamViewSet(CreateUpdateCustomMixin, ModelViewSet):
|
||||||
|
|
||||||
开始考试具体题目信息
|
开始考试具体题目信息
|
||||||
"""
|
"""
|
||||||
exam = self.get_object()
|
# exam = self.get_object()
|
||||||
|
exam = Exam.objects.get(id=kwargs['pk'])
|
||||||
# 查询本次考试对应哪些人
|
# 查询本次考试对应哪些人
|
||||||
participants = exam.participant_user.all()
|
participants = exam.participant_user.all()
|
||||||
participants_ids = [i.id for i in participants]
|
participants_ids = [i.id for i in participants]
|
||||||
|
@ -489,7 +550,7 @@ class ExamRecordViewSet(ListModelMixin, DestroyModelMixin, RetrieveModelMixin, G
|
||||||
考试记录列表和详情
|
考试记录列表和详情
|
||||||
"""
|
"""
|
||||||
perms_map = {'get': '*', 'post': '*', 'delete':'examrecord'}
|
perms_map = {'get': '*', 'post': '*', 'delete':'examrecord'}
|
||||||
queryset = ExamRecord.objects.select_related('create_by')
|
queryset = ExamRecord.objects.select_related('create_by', 'cert_er')
|
||||||
serializer_class = ExamRecordListSerializer
|
serializer_class = ExamRecordListSerializer
|
||||||
ordering_fields = ['create_time', 'score', 'took', 'update_time', 'belong_dept']
|
ordering_fields = ['create_time', 'score', 'took', 'update_time', 'belong_dept']
|
||||||
ordering = ['-update_time']
|
ordering = ['-update_time']
|
||||||
|
@ -505,24 +566,25 @@ class ExamRecordViewSet(ListModelMixin, DestroyModelMixin, RetrieveModelMixin, G
|
||||||
if has_permission('ctc_manager', self.request.user):
|
if has_permission('ctc_manager', self.request.user):
|
||||||
return qs
|
return qs
|
||||||
# 如果是部门管理员,只能看到自己部门下的考试记录
|
# 如果是部门管理员,只能看到自己部门下的考试记录
|
||||||
# return qs.filter(belong_dept__in=get_child_queryset2(self.request.user.dept))
|
elif has_permission('exam_manager', self.request.user):
|
||||||
|
return qs.filter(belong_dept__in=get_child_queryset2(self.request.user.dept))
|
||||||
# 如果是普通员工,只能看到自己考试记录
|
# 如果是普通员工,只能看到自己考试记录
|
||||||
else:
|
else:
|
||||||
return qs.filter(create_by=self.request.user)
|
return qs.filter(create_by=self.request.user)
|
||||||
|
|
||||||
def get_serializer_class(self):
|
def get_serializer_class(self):
|
||||||
if self.action == 'retrieve':
|
if self.action == 'retrieve':
|
||||||
return ExamRecordDetailSerializer
|
now = timezone.now()
|
||||||
|
if now > self.get_object().exam.close_time:
|
||||||
|
return ExamRecordDetailSerializer
|
||||||
return super().get_serializer_class()
|
return super().get_serializer_class()
|
||||||
|
|
||||||
def perform_destroy(self, instance): # 考试记录物理删除
|
def perform_destroy(self, instance): # 考试记录物理删除
|
||||||
instance.delete(soft=False)
|
instance.delete()
|
||||||
|
|
||||||
@action(methods=['post'], detail=False, perms_map=[{'post': '*'}], serializer_class=Serializer, permission_classes = [IsAuthenticated])
|
@action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=Serializer, permission_classes = [IsAuthenticated])
|
||||||
def clear(self, request, pk=None):
|
def clear(self, request, pk=None):
|
||||||
"""
|
"""
|
||||||
清除七日前未提交的考试记录
|
|
||||||
|
|
||||||
清除七日前未提交的考试记录
|
清除七日前未提交的考试记录
|
||||||
"""
|
"""
|
||||||
now = timezone.now
|
now = timezone.now
|
||||||
|
@ -530,19 +592,19 @@ class ExamRecordViewSet(ListModelMixin, DestroyModelMixin, RetrieveModelMixin, G
|
||||||
ExamRecord.objects.filter(create_time__lte=days7_ago, is_submited=False).delete(soft=False)
|
ExamRecord.objects.filter(create_time__lte=days7_ago, is_submited=False).delete(soft=False)
|
||||||
return Response(status=False)
|
return Response(status=False)
|
||||||
|
|
||||||
@action(methods=['get'], detail=False, permission_classes=[IsAuthenticated])
|
|
||||||
def self(self, request, pk=None):
|
|
||||||
'''
|
|
||||||
个人考试记录
|
|
||||||
|
|
||||||
个人考试记录
|
@action(methods=['get'], detail=False,
|
||||||
'''
|
url_path='export', url_name='export_record', perms_map={'*': 'export_ansrecord'}, serializer_class=Serializer)
|
||||||
queryset = ExamRecord.objects.filter(create_by=request.user).order_by('-update_time')
|
def export(self, request):
|
||||||
page = self.paginate_queryset(queryset)
|
"""
|
||||||
serializer = self.get_serializer(page, many=True)
|
导出答题记录
|
||||||
return self.get_paginated_response(serializer.data)
|
"""
|
||||||
|
queryset = self.filter_queryset(self.get_queryset())
|
||||||
|
path = export_record(queryset)
|
||||||
|
return Response({'path': path})
|
||||||
|
|
||||||
@action(methods=['post'], detail=True, perms_map=[{'post': '*'}], serializer_class=ExamRecordSubmitSerializer, permission_classes = [IsAuthenticated])
|
|
||||||
|
@action(methods=['post'], detail=True, perms_map={'post': '*'}, serializer_class=ExamRecordSubmitSerializer, permission_classes = [IsAuthenticated])
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def submit(self, request, pk=None):
|
def submit(self, request, pk=None):
|
||||||
'''
|
'''
|
||||||
|
@ -594,13 +656,23 @@ class ExamRecordViewSet(ListModelMixin, DestroyModelMixin, RetrieveModelMixin, G
|
||||||
now_data = datetime.now()
|
now_data = datetime.now()
|
||||||
course = exam.course_name.all()
|
course = exam.course_name.all()
|
||||||
courese_ids = [i.id for i in course]
|
courese_ids = [i.id for i in course]
|
||||||
current_date = now_data.strftime('%Y-%m-%d')
|
current_date = now_data.strftime('%Y-%m-%d')
|
||||||
|
cer_number = now_data.strftime('%Y%m%d')
|
||||||
|
# 查询证明编号创建时间为最后一个
|
||||||
|
cer = Certificate.objects.latest('证书编号')
|
||||||
|
if cer:
|
||||||
|
cer_number = int(cer.证书编号[5:]) + 1
|
||||||
|
cer_number = 'CTCZL' + str(cer_number)
|
||||||
data_dict = {
|
data_dict = {
|
||||||
'姓名': request.user.name,
|
'姓名': request.user.name,
|
||||||
'证书编号': 'CTCZL'+ current_date,
|
'用户ID': request.user.id,
|
||||||
|
'证书编号': cer_number,
|
||||||
|
'证书方案': '202312',
|
||||||
'单位名称': request.user.dept.name,
|
'单位名称': request.user.dept.name,
|
||||||
'所属单位': '国检测试控股集团'+request.user.dept.name,
|
'所属单位': '国检测试控股集团'+request.user.dept.name,
|
||||||
'发证日期': current_date,
|
'发证日期': current_date,
|
||||||
|
'培训日期':current_date,
|
||||||
|
'培训结束日期': current_date,
|
||||||
'课程列表': courese_ids,
|
'课程列表': courese_ids,
|
||||||
'examrecord': er.id,
|
'examrecord': er.id,
|
||||||
}
|
}
|
||||||
|
@ -610,7 +682,7 @@ class ExamRecordViewSet(ListModelMixin, DestroyModelMixin, RetrieveModelMixin, G
|
||||||
|
|
||||||
er.took = (now - er.create_time).total_seconds()
|
er.took = (now - er.create_time).total_seconds()
|
||||||
er.end_time = now
|
er.end_time = now
|
||||||
er.belong_dept=request.user.dept.id
|
er.belong_dept=request.user.dept
|
||||||
er.is_submited = True
|
er.is_submited = True
|
||||||
er.save()
|
er.save()
|
||||||
return Response(ExamRecordListSerializer(instance=er).data)
|
return Response(ExamRecordListSerializer(instance=er).data)
|
|
@ -0,0 +1,20 @@
|
||||||
|
# Generated by Django 3.2.12 on 2024-06-04 09:28
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
from django.db import migrations, models
|
||||||
|
from django.utils.timezone import utc
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('information', '0047_alter_qualification_change_date'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='qualification',
|
||||||
|
name='change_date',
|
||||||
|
field=models.DateField(blank=True, default=datetime.datetime(2024, 6, 4, 9, 28, 52, 579869, tzinfo=utc), null=True, verbose_name='变更日期'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,20 @@
|
||||||
|
# Generated by Django 3.2.12 on 2024-06-06 01:44
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
from django.db import migrations, models
|
||||||
|
from django.utils.timezone import utc
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('information', '0048_alter_qualification_change_date'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='qualification',
|
||||||
|
name='change_date',
|
||||||
|
field=models.DateField(blank=True, default=datetime.datetime(2024, 6, 6, 1, 44, 19, 206626, tzinfo=utc), null=True, verbose_name='变更日期'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,20 @@
|
||||||
|
# Generated by Django 3.2.12 on 2024-06-06 02:26
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
from django.db import migrations, models
|
||||||
|
from django.utils.timezone import utc
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('information', '0049_alter_qualification_change_date'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='qualification',
|
||||||
|
name='change_date',
|
||||||
|
field=models.DateField(blank=True, default=datetime.datetime(2024, 6, 6, 2, 26, 43, 23224, tzinfo=utc), null=True, verbose_name='变更日期'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,20 @@
|
||||||
|
# Generated by Django 3.2.12 on 2024-06-14 05:35
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
from django.db import migrations, models
|
||||||
|
from django.utils.timezone import utc
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('information', '0050_alter_qualification_change_date'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='qualification',
|
||||||
|
name='change_date',
|
||||||
|
field=models.DateField(blank=True, default=datetime.datetime(2024, 6, 14, 5, 35, 33, 230280, tzinfo=utc), null=True, verbose_name='变更日期'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,20 @@
|
||||||
|
# Generated by Django 3.2.12 on 2024-06-14 06:51
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
from django.db import migrations, models
|
||||||
|
from django.utils.timezone import utc
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('information', '0051_alter_qualification_change_date'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='qualification',
|
||||||
|
name='change_date',
|
||||||
|
field=models.DateField(blank=True, default=datetime.datetime(2024, 6, 14, 6, 51, 53, 747831, tzinfo=utc), null=True, verbose_name='变更日期'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -100,8 +100,6 @@ class ImpMixin:
|
||||||
if 'file' not in request.data:
|
if 'file' not in request.data:
|
||||||
raise ParseError('请提供文件')
|
raise ParseError('请提供文件')
|
||||||
path = request.data['file']
|
path = request.data['file']
|
||||||
print(path, "---------ssss")
|
|
||||||
|
|
||||||
if not str(path).endswith('.xlsx'):
|
if not str(path).endswith('.xlsx'):
|
||||||
raise ParseError('请提供xlsx格式文件')
|
raise ParseError('请提供xlsx格式文件')
|
||||||
fullpath = settings.BASE_DIR + str(path)
|
fullpath = settings.BASE_DIR + str(path)
|
||||||
|
@ -111,7 +109,7 @@ class ImpMixin:
|
||||||
data_list = self.build_data(sheet, start)
|
data_list = self.build_data(sheet, start)
|
||||||
serializer = mySerializer(data=data_list, many=True, context={'request': request})
|
serializer = mySerializer(data=data_list, many=True, context={'request': request})
|
||||||
if serializer.is_valid():
|
if serializer.is_valid():
|
||||||
serializer.save(create_by=request.user, belong_dept=request.user.dept)
|
serializer.save()
|
||||||
else:
|
else:
|
||||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
@ -335,6 +333,8 @@ class UserExamViewset(ImpMixin, ModelViewSet):
|
||||||
else:
|
else:
|
||||||
# password = make_password(''.join(random.sample(string.ascii_letters + string.digits, 8)))
|
# password = make_password(''.join(random.sample(string.ascii_letters + string.digits, 8)))
|
||||||
password = make_password('0000')
|
password = make_password('0000')
|
||||||
|
exam_role = Role.objects.get(name='考试')
|
||||||
|
request.data['roles'] = [exam_role.id]
|
||||||
serializer = self.get_serializer(data=request.data)
|
serializer = self.get_serializer(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
serializer.save(password=password)
|
serializer.save(password=password)
|
||||||
|
@ -347,12 +347,14 @@ class UserExamViewset(ImpMixin, ModelViewSet):
|
||||||
return Response({'msg': '考试角色不存在'})
|
return Response({'msg': '考试角色不存在'})
|
||||||
for row in sheet.iter_rows(min_row=start, values_only=True): # 假设第一行是表头,从第二行开始读取数据
|
for row in sheet.iter_rows(min_row=start, values_only=True): # 假设第一行是表头,从第二行开始读取数据
|
||||||
if row[0] is not None:
|
if row[0] is not None:
|
||||||
dept = Organization.objects.get(name=row[3])
|
dept = Organization.objects.get(name=row[2])
|
||||||
if not dept:
|
user_depts = get_child_queryset2(self.request.user.dept).order_by('sort')
|
||||||
return Response({'msg': '部门不存在'})
|
depts = any(i.name==dept.name for i in user_depts)
|
||||||
|
if depts is False:
|
||||||
|
return Response({'msg': f'本公司下不存在此部门{row[2]}'})
|
||||||
serializer_data = {
|
serializer_data = {
|
||||||
'name': row[1],
|
'name': row[0],
|
||||||
'username':row[2],
|
'username':row[1],
|
||||||
'dept':dept.id,
|
'dept':dept.id,
|
||||||
'roles':[exam_role.id],
|
'roles':[exam_role.id],
|
||||||
'avatar': "/media/default/avatar.png"
|
'avatar': "/media/default/avatar.png"
|
||||||
|
@ -510,6 +512,7 @@ class UserViewSet(PageOrNot, ModelViewSet):
|
||||||
while sheet['b'+str(i)].value:
|
while sheet['b'+str(i)].value:
|
||||||
name = sheet['b'+str(i)].value
|
name = sheet['b'+str(i)].value
|
||||||
email = sheet['e'+str(i)].value
|
email = sheet['e'+str(i)].value
|
||||||
|
dept = Organization.objects.get(name=sheet['j'+str(i)].value)
|
||||||
if not User.objects.filter(username=email).exists():
|
if not User.objects.filter(username=email).exists():
|
||||||
user = User.objects.create(name=name,
|
user = User.objects.create(name=name,
|
||||||
username=email,
|
username=email,
|
||||||
|
@ -517,7 +520,7 @@ class UserViewSet(PageOrNot, ModelViewSet):
|
||||||
dept=dept)
|
dept=dept)
|
||||||
else:
|
else:
|
||||||
user = User.objects.get(username=email)
|
user = User.objects.get(username=email)
|
||||||
dept = Organization.objects.get(name=sheet['j'+str(i)].value)
|
|
||||||
if sheet['f'+str(i)].value:
|
if sheet['f'+str(i)].value:
|
||||||
user.roles.add(role1)
|
user.roles.add(role1)
|
||||||
if sheet['g'+str(i)].value:
|
if sheet['g'+str(i)].value:
|
||||||
|
|
|
@ -28,6 +28,4 @@ DATABASES = {
|
||||||
# 'HOST':'1.203.161.101',
|
# 'HOST':'1.203.161.101',
|
||||||
'PORT': '5432',
|
'PORT': '5432',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue