Merge branch 'test_dispaly' of https://git.code.tencent.com/lian-cbtc/jl-client into test_dispaly

This commit is contained in:
fan 2022-10-17 15:40:52 +08:00
commit ad5c4b78d4
14 changed files with 1369 additions and 1230 deletions

View File

@ -1,114 +1,216 @@
import request from '@/utils/request';
import request from '@/utils/request'
/** 创建对应课程考题 */
export function createExam(data) {
return request({
url: `/api/exam`,
method: 'post',
data: data
});
return request({
url: `/api/exam`,
method: 'post',
data: data,
})
}
/** 获取试卷详情 */
export function getExamLessonDetail(examId) {
return request({
url: `/api/exam/${examId}`,
method: 'get'
});
return request({
url: `/api/exam/${examId}`,
method: 'get',
})
}
/** 获取试卷列表 */
export function getExamList(data) {
return request({
url: '/api/exam/list',
method: 'get',
params: data
});
return request({
url: '/api/exam/list',
method: 'get',
params: data,
})
}
/** 删除试卷 */
export function deleteExam(data) {
return request({
url: `/api/exam/${data.id}`,
method: 'delete'
});
return request({
url: `/api/exam/${data.id}`,
method: 'delete',
})
}
/** 设置试卷下架 */
export function setExamEfficacy(data) {
return request({
url: `/api/exam/${data.id}/offLine`,
method: 'put'
});
return request({
url: `/api/exam/${data.id}/offLine`,
method: 'put',
})
}
/** 设置试卷上架 */
export function setExamEffectivey(data) {
return request({
url: `/api/exam/${data.id}/onLine`,
method: 'put'
});
return request({
url: `/api/exam/${data.id}/onLine`,
method: 'put',
})
}
/** 更新考试规则*/
export function updateExamRules(data) {
return request({
url: `/api/exam/${data.id}`,
method: 'put',
data: data
});
return request({
url: `/api/exam/${data.id}`,
method: 'put',
data: data,
})
}
/** 查询本项目下的考试列表 */
export function getExamListProject(params) {
return request({
url: `/api/exam/paged/loginProject`,
method: 'get',
params
});
return request({
url: `/api/exam/paged/loginProject`,
method: 'get',
params,
})
}
/** 查询本项目下的考试列表不分页 */
export function getExamListProjectUnpage(params) {
return request({
url: `/api/exam/list/loginProject`,
methods: 'get',
params
});
return request({
url: `/api/exam/list/loginProject`,
methods: 'get',
params,
})
}
/** 查询班级关联的自己创建的试卷 */
export function getExamListSelfByClassId(params) {
return request({
url: `/api/exam/list/org/self`,
method: 'get',
params
});
return request({
url: `/api/exam/list/org/self`,
method: 'get',
params,
})
}
/** 根据地图ID和prdType查询试卷列表 */
export function getExamListByMapIdAndPrdType(mapId, prdType) {
return request({
url: `/api/exam/list/${mapId}`,
method: 'get',
params: { prdType: prdType }
});
return request({
url: `/api/exam/list/${mapId}`,
method: 'get',
params: { prdType: prdType },
})
}
/** 更新试卷规则 */
export function updateExamRule(data) {
return request({
url: `/api/exam/update/rules`,
method: 'put',
data:data
});
return request({
url: `/api/exam/update/rules`,
method: 'put',
data: data,
})
}
/** 检查并更新【规则数据异常】状态 */
export function checkAndUpdateAbnormal(mapId) {
return request({
url: `/api/exam/checkAndUpdateAbnormal/${mapId}`,
method: 'put'
});
return request({
url: `/api/exam/checkAndUpdateAbnormal/${mapId}`,
method: 'put',
})
}
/** 重新生成考试规则 */
export function regenerateRule (mapId) {
return request({
url: `/api/exam/regenerateRules/${mapId}`,
method: 'put'
});
export function regenerateRule(mapId) {
return request({
url: `/api/exam/regenerateRules/${mapId}`,
method: 'put',
})
}
/**
* ============================================================================
* ============================================================================
* ============================= 以下为新版试卷的接口 ============================
* ============================================================================
* ============================================================================
*/
/**
* LIST -
* 根据试卷蓝图名称简介分页查找某个组织的试卷蓝图
* @param {Number} orgId 组织ID
* @param {String} name 试卷蓝图名称
* @param {String} profile 试卷蓝图简介
* @param {Number} findState 状态: (All(1)-所有,Editing(2)-正在编辑的,CanUse(3)-可以用于生成试卷的,Locked(4)-封存,Used(5)-已经被使用过)
* @param {Number} orderBy 排序依据: (1--创建时间 2--更新时间 3--名称默认值为1)
*/
export function getPapaerListOfOrg({ orgId, ...data }) {
return request({
url: `/api/v2/paper/composition/find/page/for/${orgId}`,
method: 'POST',
data,
})
}
/**
* 创建试卷蓝图
* @param {Number} data.orgId 组织ID
* @param {String} data.name 试卷蓝图名称
* @param {String} data.profile 简介
* @param {String} data.startTime 启用起始时间
* @param {String} data.endTime 启用截止时间
* @param {Number} data.validDuration 考试时长
* @param {String} data.passScore 及格分
* @param {String} data.fullScore 满分
* @param {Object} data.ruleList 规则列表
* @param {Object} data.ruleList.id 规则id
* @param {Object} data.ruleList.pcId 试卷蓝图ID
* @param {Object} data.ruleList.type 试题类型
* @param {Object} data.ruleList.subtype 规则类型
* @param {Object} data.ruleList.tags 标签
* @param {Object} data.ruleList.amount 数量
* @param {Object} data.ruleList.score 每题分值
*/
export function createPaper(data) {
return request({
url: `/api/v2/paper/composition/${data.orgId}`,
method: 'POST',
data,
})
}
/**
* @param {Number} data.id 试卷蓝图ID
* @param {Number} data.orgId 组织ID
* @param {String} data.name 试卷蓝图名称
* @param {String} data.profile 简介
* @param {String} data.startTime 启用起始时间
* @param {String} data.endTime 启用截止时间
* @param {Number} data.validDuration 考试时长
* @param {String} data.passScore 及格分
* @param {String} data.fullScore 满分
* @param {Object} data.ruleList 规则列表
* @param {Object} data.ruleList.id 规则id
* @param {Object} data.ruleList.pcId 试卷蓝图ID
* @param {Object} data.ruleList.type 试题类型
* @param {Object} data.ruleList.subtype 规则类型
* @param {Object} data.ruleList.tags 标签
* @param {Object} data.ruleList.amount 数量
* @param {Object} data.ruleList.score 每题分值
*/
export function editPaper(data) {
return request({
url: `/api/v2/paper/composition`,
method: 'PUT',
data,
})
}
/**
* @param {Number} pcId 试卷蓝图ID
*/
export function getPaperDetail(pcId) {
return request({
url: `/api/v2/paper/composition/${pcId}`,
method: 'GET',
})
}
/**
* @param {Number} data.orgId
* @param {Number} data.subtype
* @param {Array<String>} data.tags
*/
export function getQuestionAmount(data) {
return request({
url: `/api/v2/paper/${data.orgId}/question/count`,
method: 'POST',
data,
})
}

View File

@ -13,7 +13,7 @@ export function listQuestionPage(params) {
// 标签列表
export function getLableList() {
return request({
url: `/api/question/org/lable`,
url: `/api/question/org/label`,
method: 'get'
});
}
@ -49,11 +49,12 @@ export function updateOption(data) {
}
// 获取题目信息
export function getQuestionInfo(questionId) {
export function getQuestionInfo(questionId, params) {
return request({
// url: `/api/questionBank/questions/${questionId}`,
url: `/api/question/org/${questionId}`,
method: 'get'
method: 'get',
params
});
}
@ -65,3 +66,12 @@ export function importQuestion(data) {
data
});
}
// 预览答题
export function testAnswer(questionId, data) {
return request({
url: `/api/question/org/test/answer/${questionId}`,
method: 'post',
data
});
}

View File

@ -687,7 +687,7 @@ export const publicAsyncRoute = [
hidden: true
},
{
path: 'examRule/draft/:mode/:ruleId/:lessonId',
path: 'examRule/draft/:mode/:paperId',
component: PublishExamRuleDraft,
hidden: true
},
@ -1933,10 +1933,12 @@ export const asyncRouter = [
{
path: 'subsystem',
component: SubsystemManage,
hidden: true,
meta: {
i18n: 'newRouter.subsystemManage'
}
hidden: true
},
{
path: 'PublishMapDetail',
component: PublishMapDetail,
hidden: true
}
]
},

View File

@ -29,8 +29,8 @@ export function handlerUrl() {
// BASE_API = 'http://114.116.51.125/jlcloud';
// BASE_API = 'http://192.168.3.90:9100'; // 周寅
// BASE_API = 'http://192.168.3.94:9000'; // 旭强
BASE_API = 'http://192.168.3.15:9000'; // 张赛
// BASE_API = 'http://192.168.3.5:9000'; // 夏增彬
// BASE_API = 'http://192.168.3.15:9000'; // 张赛
BASE_API = 'http://192.168.3.5:9000'; // 夏增彬
// BASE_API = 'http://192.168.3.37:9000'; // 卫志宏
// BASE_API = 'http://b29z135112.zicp.vip';
// BASE_API = 'http://2925963m2a.zicp.vip'; // 杜康

View File

@ -2,6 +2,7 @@
<div>
<query-list-page ref="user" :pager-config="pagerConfig" :query-form="queryForm" :query-list="queryList" />
<dialog-detail ref="detail" />
<preview-answer ref="previewAnswer" :question-id="questionId" />
</div>
</template>
@ -9,17 +10,20 @@
// import { UrlConfig } from '@/scripts/ConstDic';
import { listQuestionPage, deleteQuestion, getLableList } from '@/api/questionBank.js';
import DialogDetail from './dialog-detail';
import PreviewAnswer from './previewAnswer';
import { convertSheetToList } from '@/jmapNew/theme/parser/util.js';
// import { getCompanyList } from '@/api/company';
import XLSX from 'xlsx';
export default {
components: {
DialogDetail
DialogDetail,
PreviewAnswer
},
data() {
return {
// companyList: [],
questionId: '',
companyMap: {},
pagerConfig: {
pageSize: 'pageSize',
@ -35,7 +39,7 @@ export default {
type: 'select',
label: '类 型',
config: {
data: this.$ConstSelect.QuestionTypeList
data: this.$ConstSelect.QuestionTypeList.filter(item => { return !['fill', 'answer'].includes(item.value); })
}
},
topic: {
@ -59,7 +63,8 @@ export default {
columns: [
{
title: '题 目',
prop: 'topic'
prop: 'topic',
type: 'html'
},
{
title: '标 签',
@ -114,9 +119,13 @@ export default {
// showControl: (row) => { return row.createUserId == this.userId; },
type: 'danger'
},
// {
// name: ' ',
// handleClick: this.doDetail
// },
{
name: '预 览',
handleClick: this.doDetail
name: '预答题',
handleClick: this.previewAnswer
}
]
}
@ -186,6 +195,11 @@ export default {
this.$refs.detail.doShow({index, row});
},
previewAnswer(index, row) {
this.questionId = row.id;
this.$refs.previewAnswer.doShow();
},
lableTags(row) {
return row.tags ? row.tags.split(',') : '';
},

View File

@ -0,0 +1,190 @@
<template>
<el-dialog v-dialogDrag :close-on-click-moda="false" :title="title" :visible.sync="show" width="860px" :close-on-click-modal="false" :before-close="doClose">
<div class="ql-editor" v-html="$escapeHTML(`${mapType[type] || ''} : ${form.topic}`)" />
<template v-if="checkType(form, 'judge')">
<div class="answer">
:
<div>
<el-radio-group v-model="active">
<el-radio v-for="(el,i) in options" :key="i" class="option" :label="el.id"> {{ el.content }} </el-radio>
</el-radio-group>
</div>
</div>
</template>
<template v-else-if="checkType(form, 'select')">
<div v-for="(el,i) in options" :key="i" class="option" :label="$str2number(el.id)">
<span>{{ $asc2chart(i+65) }}. </span>
<div class="ql-editor" style="display: inline; padding: 0" v-html="$escapeHTML(el.content)" />
</div>
<div class="answer">
:
<div>
<el-radio-group v-model="active">
<el-radio v-for="(el,i) in options" :key="i" class="option" :label="el.id"> {{ $asc2chart(65+i) }} </el-radio>
</el-radio-group>
</div>
</div>
</template>
<template v-else-if="checkType(form, 'multi')">
<div v-for="(el,i) in options" :key="i" class="option" :label="$str2number(el.id)">
<span>{{ $asc2chart(i+65) }}. </span>
<div class="ql-editor" style="display: inline; padding: 0" v-html="$escapeHTML(el.content)" />
</div>
<div class="answer">
:
<el-checkbox-group v-model="active">
<el-checkbox v-for="(el,i) in options" :key="i" class="option" :label="el.id">{{ $asc2chart(65+i) }} </el-checkbox>
</el-checkbox-group>
</div>
</template>
<template v-else-if="checkType(form, 'fill')">
<div class="answer">
:
<div v-for="(el, i) in options" :key="i" class="fillType">
<div class="fillTypeName">{{ `${i + 1}` }}</div>
<el-input v-model="active[i]" class="fillTypeInput" type="textarea" :autosize="{ minRows: 1, maxRows: 4}" placeholder="请输入答案" />
</div>
</div>
</template>
<template v-else-if="checkType(form, 'answer')">
<div class="answer">
:
<div>
<el-input v-model="active" type="textarea" :autosize="{ minRows: 2, maxRows: 4}" placeholder="请输入答案" />
</div>
</div>
</template>
<div v-if="showAnswer" class="show-answer">
<span :class="isCorrect? 'correct': 'error'">{{ isCorrect ? '答案正确!' : '答案错误!' }}</span>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="submit(true)">提交</el-button>
<el-button @click="show = false">关闭</el-button>
</span>
</el-dialog>
</template>
<script>
import {getQuestionInfo, testAnswer } from '@/api/questionBank.js';
export default {
props: {
questionId: {
type:[Number, String],
required: true
}
},
data() {
return {
active: '',
show: false,
showAnswer: false,
isCorrect: false,
form: {
type: '',
optionList: []
}
};
},
computed: {
title() {
return '详 情';
},
options() {
return this.form.optionList;
},
type() {
return this.form.type;
},
mapType() {
const obj = {};
const list = this.$ConstSelect.QuestionTypeList;
list.forEach(item => {
obj[item.value] = item.label;
});
return obj;
}
},
watch: {
questionId(val) {
this.showAnswer = false;
this.getQuestionInfo();
},
type(val) {
if (val == 'judge' || val == 'judge') {
this.active = 0;
} else if (val == 'multi' || val == 'fill') {
this.active = [];
} else {
this.active = '';
}
}
},
methods: {
checkType(option, type) {
return option.type == type;
},
appendIndex(str, index) {
return `${index + 1}. ${str}`;
},
doShow(node) {
// this.form = node.row || {};
this.show = true;
},
getQuestionInfo() {
if (!this.questionId) { return; }
getQuestionInfo(this.questionId, {random: false}).then(res => {
console.log(res, '---res===');
this.form = res.data;
}).catch(err => {
console.log(err, '---err=====');
this.form.optionList = [];
});
},
submit(val) {
console.log(this.active, this.questionId, this.form, '====');
let data = this.active;
if (!Array.isArray(data)) {
data = [data];
}
testAnswer(this.questionId, data).then(res => {
if (val) {
this.showAnswer = true;
this.isCorrect = res.data;
}
// this.doClose();
}).catch(err => {
console.log(err, '===err====');
});
},
doClose(done) {
this.show = false;
}
}
};
</script>
<style lang="scss" scoped>
.option {
line-height: 22px;
padding-left: 20px;
}
.answer {
line-height: 32px;
color: #000;
padding-left: 15px;
}
.show-answer {
padding: 15px;
span {
font-size: 18px;
}
.correct {
color: green;
}
.error {
color: red;
}
}
</style>

View File

@ -146,6 +146,7 @@ export default {
getLableList().then(res => {
this.labelList = res.data || [];
}).catch(err => {
console.log(err);
});
},
methods: {

View File

@ -90,7 +90,10 @@ export default {
this.doBack();
} else if (valid) {
// this.formModel.companyId = parseInt(this.companyId);
this.formModel.tags = this.tagsArr.join(',');
this.formModel.tags = this.tagsArr;
if (Array.isArray(this.tagsArr)) {
this.formModel.tags = this.tagsArr.join(',');
}
updateOption(this.formModel).then(resp => {
this.doBack();
}).catch(error => {

View File

@ -1,249 +1,272 @@
<template>
<div style="width: 100%;height: 100%;">
<QueryListPage
ref="examQueryListPage"
:query-form="examQueryForm"
:pager-config="pagerConfig"
:query-list="examQueryList"
style="width:96%;margin: 0 auto;"
/>
</div>
<div style="width: 100%;height: 100%;">
<QueryListPage
ref="examQueryListPage"
:query-form="examQueryForm"
:pager-config="pagerConfig"
:query-list="examQueryList"
style="width:96%;margin: 0 auto;"
/>
</div>
</template>
<script>
import { getExamListProject, setExamEffectivey, setExamEfficacy } from '@/api/management/exam';
import localStore from 'storejs';
import { getPublishMapListOnline } from '@/api/jmap/map';
const paperStateMap = {
'1': '正在编辑',
'2': '封存',
'3': '已使用',
}
import { getExamListProject, getPapaerListOfOrg, setExamEffectivey, setExamEfficacy } from '@/api/management/exam'
import { getPublishMapListOnline } from '@/api/jmap/map'
export default {
name: 'ExamManage',
data() {
return {
pagerConfig: {
pageSize: 'pageSize',
pageIndex: 'pageNum'
},
mapIdList: [],
examQueryForm: {
leftSpan: 14,
textAlign: 'right',
labelWidth: '90px',
reset: true,
columnNum: 3,
queryObject: {
name: {
type: 'text',
label: '试卷名称:'
},
creatorName: {
type: 'text',
label: '创建人:'
},
status: {
type: 'select',
label: '启用/禁用:',
config: {
data: [
{ label: '启用', value: '1' },
{ label: '禁用', value: '0' }
]
}
}
}
},
examQueryList: {
query: getExamListProject,
selectCheckShow: false,
indexShow: false,
columns: [
{
title: '试卷名称',
prop: 'name'
},
{
title: '归属地图',
prop: 'mapId',
type: 'tag',
width: '200',
columnValue: (row) => { return this.$convertField(row.mapId, this.mapIdList, ['id', 'name']); },
tagType: (row) => { return ''; }
},
{
title: '产品类型',
prop: 'prdType',
type: 'tag',
width: '110',
columnValue: (row) => { if (row.prdType === '01') { return '现地工作站'; } else if (row.prdType === '02') { return '行调工作站'; } },
tagType: (row) => { return ''; }
},
{
title: '启用/禁用',
prop: 'status',
type: 'tag',
width: '80',
columnValue: (row) => {
return row.status == '1' ? '启用' : '禁用';
},
tagType: (row) => { return ''; }
},
{
title: '试卷规则状态',
prop: 'abnormal',
type: 'tag',
width: '80',
columnValue: (row) => {
return row.abnormal ? '异常' : '正常';
},
tagType: (row) => { return row.abnormal ? 'danger' : 'success'; }
},
{
title: '开始时间',
prop: 'startTime'
},
{
title: '截止时间',
prop: 'endTime'
},
{
title: '满分',
prop: 'fullPoint',
width: '80'
},
{
title: '及格分',
prop: 'passingPoint',
width: '80'
},
{
title: '时长',
prop: 'duration',
type: 'tag',
width: '80',
columnValue: (row) => {
return Math.floor(row.duration / 60);
},
tagType: (row) => { }
},
{
title: '创建人',
prop: 'creatorName',
width: '150'
},
{
type: 'button',
title: this.$t('global.operate'),
width: '350',
buttons: [
{
name: '成绩查询',
handleClick: this.handleQueryGrade,
type: 'primary'
},
{
name: '成绩统计',
handleClick: this.handleGradeStatistics,
type: 'success'
},
{
name: '编辑',
handleClick: this.handleEditExam,
type: 'primary',
showControl: (row) => {
return row.creatorId == this.userId;
}
},
{
name: '启用',
handleClick: this.handleEnableExam,
type: 'warning',
showControl: (row) => {
return row.creatorId == this.userId && row.status == '0';
}
},
{
name: '禁用',
handleClick: this.handleDeleteExam,
type: 'danger',
showControl: (row) => {
return row.creatorId == this.userId && row.status == '1';
}
}
]
}
],
actions: [
{ text: '新建试卷', handler: this.examCreate }
]
}
};
},
computed: {
userId() {
return this.$store.state.user.id;
}
},
created() {
const params = localStore.get(this.$route.path) || {};
if (!params.status) { params.status = '1'; }
localStore.set(this.$route.path, params);
this.mapIdList = [];
getPublishMapListOnline().then(response => {
this.mapIdList = response.data;
});
},
methods: {
handleQueryGrade(index, row) {
this.$router.push({ path: '/info/gradeList', query: { examId: row.id, name: row.name } });
},
handleGradeStatistics(index, row) {
this.$router.push({ path: '/info/gradeStatistics', query: { examId: row.id, name: row.name } });
},
handleEditExam(index, row) {
this.$router.push({ path: `/info/examRule/draft/edit/${row.id}/0`, query: { source: 'org' } });
},
examCreate() {
this.$router.push({ path: `/info/examRule/draft/add/0/0`, query: { source: 'org' } });
},
handleEnableExam(index, data) {
setExamEffectivey(data).then(res => {
this.examRefresh();
this.$message.success('启用试卷成功!');
}).catch(error => {
this.$message.error('启用试卷失败:' + error.message);
});
},
handleDeleteExam(index, data) {
this.$confirm('该操作将禁用试卷,是否继续?', this.$t('global.tips'), {
confirmButtonText: this.$t('global.confirm'),
cancelButtonText: this.$t('global.cancel'),
type: 'warning'
}).then(() => {
setExamEfficacy(data).then(res => {
this.examRefresh();
this.$message({
type: 'success',
message: '禁用试卷成功!'
});
}).catch(res => {
if (res.code == '10004') {
this.$message({ type: 'error', message: '禁用失败:试卷已被使用,无法禁用!' });
} else if (res.code == '10003') {
this.$message({ type: 'warning', message: '禁用失败:无权限禁用!'});
} else {
this.$message({ type: 'error', message: '禁用试卷失败!' });
}
});
}).catch(() => { });
},
examRefresh() {
this.$nextTick(() => {
this.$refs.examQueryListPage.refresh(true);
});
}
}
};
name: 'ExamManage',
data() {
return {
pagerConfig: {
pageSize: 'pageSize',
pageIndex: 'pageNum',
},
mapIdList: [],
examQueryForm: {
leftSpan: 14,
textAlign: 'right',
labelWidth: '90px',
reset: true,
columnNum: 3,
queryObject: {
name: {
type: 'text',
label: '试卷名称:',
},
// creatorName: {
// type: 'text',
// label: ':'
// },
state: {
type: 'select',
label: '状态:',
config: {
data: Object.entries(paperStateMap).map(([k, v]) => ({ value: k, label: v })),
},
},
},
},
examQueryList: {
// query: getExamListProject,
query: obj => getPapaerListOfOrg({ ...obj, orgId: this.orgId }),
selectCheckShow: false,
indexShow: false,
columns: [
{
title: '试卷名称',
prop: 'name',
},
{
title: '归属地图',
prop: 'mapId',
type: 'tag',
width: '200',
columnValue: row => {
return this.$convertField(row.mapId, this.mapIdList, ['id', 'name'])
},
tagType: row => {
return ''
},
},
{
title: '产品类型',
prop: 'prdType',
type: 'tag',
width: '110',
columnValue: row => {
if (row.prdType === '01') {
return '现地工作站'
} else if (row.prdType === '02') {
return '行调工作站'
}
},
tagType: row => {
return ''
},
},
{
title: '状态',
prop: 'state',
type: 'tag',
width: '80',
columnValue: row => {
return paperStateMap[row.state]
},
tagType: row => {
return ''
},
},
{
title: '试卷规则状态',
prop: 'abnormal',
type: 'tag',
width: '80',
columnValue: row => {
return row.abnormal ? '异常' : '正常'
},
tagType: row => {
return row.abnormal ? 'danger' : 'success'
},
},
{
title: '开始时间',
prop: 'startTime',
},
{
title: '截止时间',
prop: 'endTime',
},
{
title: '满分',
prop: 'fullScore',
width: '80',
},
{
title: '及格分',
prop: 'passScore',
width: '80',
},
{
title: '时长',
prop: 'validDuration',
type: 'tag',
width: '80',
columnValue: row => row.validDuration,
tagType: row => {},
},
{
title: '创建人',
prop: 'creatorName',
width: '150',
},
{
type: 'button',
title: this.$t('global.operate'),
width: '350',
buttons: [
{
name: '成绩查询',
handleClick: this.handleQueryGrade,
type: 'primary',
},
{
name: '成绩统计',
handleClick: this.handleGradeStatistics,
type: 'success',
},
{
name: '编辑',
handleClick: this.handleEditExam,
type: 'primary',
showControl: row => {
return row.creatorId == this.userId
},
},
{
name: '启用',
handleClick: this.handleEnableExam,
type: 'warning',
showControl: row => {
return row.creatorId == this.userId /* && row.status == '0' */
},
},
{
name: '禁用',
handleClick: this.handleDeleteExam,
type: 'danger',
showControl: row => {
return row.creatorId == this.userId /* && row.status == '1' */
},
},
],
},
],
actions: [{ text: '新建试卷', handler: this.examCreate }],
},
}
},
computed: {
userId() {
return this.$store.state.user.id
},
orgId() {
return this.$store.state.user.companyId
},
},
created() {
// const params = localStore.get(this.$route.path) || {}
// if (!params.status) {
// params.status = '1'
// }
// localStore.set(this.$route.path, params)
this.mapIdList = []
getPublishMapListOnline().then(response => {
this.mapIdList = response.data
})
},
methods: {
handleQueryGrade(index, row) {
this.$router.push({ path: '/info/gradeList', query: { examId: row.id, name: row.name } })
},
handleGradeStatistics(index, row) {
this.$router.push({ path: '/info/gradeStatistics', query: { examId: row.id, name: row.name } })
},
handleEditExam(index, row) {
this.$router.push({ path: `/info/examRule/draft/edit/${row.id}`, query: { source: 'org' } })
},
examCreate() {
this.$router.push({ path: `/info/examRule/draft/add/0`, query: { source: 'org' } })
},
handleEnableExam(index, data) {
setExamEffectivey(data)
.then(res => {
this.examRefresh()
this.$message.success('启用试卷成功!')
})
.catch(error => {
this.$message.error('启用试卷失败:' + error.message)
})
},
handleDeleteExam(index, data) {
this.$confirm('该操作将禁用试卷,是否继续?', this.$t('global.tips'), {
confirmButtonText: this.$t('global.confirm'),
cancelButtonText: this.$t('global.cancel'),
type: 'warning',
})
.then(() => {
setExamEfficacy(data)
.then(res => {
this.examRefresh()
this.$message({
type: 'success',
message: '禁用试卷成功!',
})
})
.catch(res => {
if (res.code == '10004') {
this.$message({ type: 'error', message: '禁用失败:试卷已被使用,无法禁用!' })
} else if (res.code == '10003') {
this.$message({ type: 'warning', message: '禁用失败:无权限禁用!' })
} else {
this.$message({ type: 'error', message: '禁用试卷失败!' })
}
})
})
.catch(() => {})
},
examRefresh() {
this.$nextTick(() => {
this.$refs.examQueryListPage.refresh(true)
})
},
},
}
</script>
<style scoped>
</style>
<style scoped></style>

View File

@ -1,175 +1,194 @@
<template>
<el-dialog v-dialogDrag :title="title" :visible.sync="dialogShow" :before-close="handleCancel" :close-on-click-modal="false">
<el-form ref="form" :model="form" :rules="rules" label-width="140px">
<el-form-item :label="$t('publish.trainingType')" prop="trainingType">
<el-select v-model="form.trainingType" :placeholder="$t('publish.selectTypeScope')" style="width:240px;" @change="changeCourse">
<el-option v-for="nor in trainingTypeList" :key="nor.value" :label="nor.label" :value="nor.value" :disabled="nor.disabled" />
</el-select>
</el-form-item>
<el-form-item :label="$t('publish.operationType')" prop="operateType">
<el-select v-model="form.operateType" clearable :placeholder="$t('publish.selectScope')" @change="changeOperation">
<el-option v-for="nor in operationTypeList" :key="nor.value" :label="nor.label" :value="nor.value" :disabled="nor.disabled" />
</el-select>
</el-form-item>
<el-form-item :label="$t('publish.questionNumbers')" prop="number">
<el-input-number
v-model="form.number"
:precision="0"
:min="0"
style="width: calc(100% - 280px); float: left; margin-right: 10px;"
/>
<span style="width: 190px; float: left;">{{ $t('publish.allNumberTipOne') }} {{ topicNum }} {{ $t('publish.allNumberTipTwo') }}</span>
</el-form-item>
<el-form-item :label="$t('publish.scorePerQuestion')" prop="mark">
<el-input-number v-model="form.mark" :precision="0" :min="0" style="width:200px" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="handleCancel">{{ $t('global.cancel') }}</el-button>
<el-button type="primary" @click="handleOk">{{ $t('global.confirm') }}</el-button>
</div>
</el-dialog>
<el-dialog
v-dialogDrag
:title="title"
:visible.sync="dialogShow"
:before-close="handleCancel"
:close-on-click-modal="false"
>
<el-form ref="form" :model="form" :rules="rules" label-width="140px">
<el-form-item label="试题类型" prop="type">
<el-select
v-model="form.type"
placeholder="请选择试题类型"
style="width:240px;"
@change="getQuestionAmount"
>
<el-option
v-for="item in types"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="规则类型" prop="subtype">
<el-select
v-model="form.subtype"
placeholder="请选择规则类型"
style="width:240px;"
@change="getQuestionAmount"
>
<el-option
v-for="item in subtypes"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="标签" prop="tags">
<el-select v-model="form.tags"></el-select>
</el-form-item>
<el-form-item label="题目数量" prop="amount">
<el-input-number
v-model="form.amount"
:precision="0"
:min="0"
:max="this.topicNum"
style="width: calc(100% - 280px); float: left; margin-right: 10px;"
/>
<span v-if="this.form.type === 1" style="width: 190px; float: left;"
>{{ $t('publish.allNumberTipOne') }} {{ topicNum }} {{ $t('publish.allNumberTipTwo') }}</span
>
</el-form-item>
<el-form-item :label="$t('publish.scorePerQuestion')" prop="score">
<el-input-number v-model="form.score" :precision="0" :min="0" style="width:200px" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="handleCancel">{{ $t('global.cancel') }}</el-button>
<el-button type="primary" @click="handleOk">{{ $t('global.confirm') }}</el-button>
</div>
</el-dialog>
</template>
<script>
import { getQuestionAmount } from '@/api/management/exam'
export default {
name: 'EditRule',
props: {
operationTypeMap: {
type: Object,
required:true
},
trainingOperateTypeMap: {
type: Object,
required:true
},
trainingTypeNums: {
type: Object,
required: true
},
operationTypeNums: {
type: Object,
required: true
},
trainingTypeList: {
type: Array,
required: true
}
},
data() {
var number = (rule, value, callback) => {
if (!value) {
return callback(new Error(this.$t('publish.inputQuestionNumber')));
}
setTimeout(() => {
if (Number(value) == 0) {
callback(new Error(this.$t('publish.inputQuestionNumberError')));
} else if (!Number(value)) {
callback(new Error(this.$t('publish.inputValidNumber')));
} else if (Number(value) > this.topicNum) {
callback(new Error(this.$t('publish.inputNumberError')));
} else {
callback();
}
}, 100);
};
var mark = (rule, value, callback) => {
if (!value) {
return callback(new Error(this.$t('publish.inputScorePerQuestion')));
} else {
callback();
}
};
return {
title: this.$t('publish.addRules'),
form: {
trainingType: '',
operateType: '',
number: '',
mark: 0
},
topicNum: 0,
dialogShow: false,
editOk: false,
rules: {
trainingType: [
{ required: true, message: this.$t('publish.selectTestType'), trigger: 'change' }
],
number: [
{ required: true, validator: number, trigger: 'blur' }
],
mark: [
{ required: true, validator: mark, trigger: 'blur' }
]
},
typeList: [],
operationTypeList: []
};
},
mounted() {},
methods: {
show(detail) {
this.dialogShow = true;
this.$nextTick(() => {
this.$refs.form.resetFields();
if (detail) {
this.title = this.$t('publish.modifyRules');
this.editOk = true;
this.changeCourse(detail.trainingType);
this.form = {
trainingType: detail.trainingType,
operateType: detail.operateType,
number: detail.num,
mark: detail.point
};
this.changeOperation(detail.operateType);
} else {
this.title = this.$t('publish.addRules');
}
});
},
handleOk() {
this.$refs['form'].validate((valid) => {
if (valid) {
this.$emit( this.editOk ? 'editRuleList' : 'addRuleList', this.form);
this.handleCancel();
}
});
},
handleCancel() {
this.editOk = false;
this.topicNum = 0;
this.operationTypeList = [];
this.dialogShow = false;
},
changeCourse(val) {
this.operationTypeList = this.operationTypeMap[val];
this.topicNum = this.trainingTypeNums[val];
this.form.operateType = '';
},
changeOperation(val) {
if (val) {
this.topicNum = this.operationTypeNums[this.form.trainingType][val];
} else {
this.topicNum = this.trainingTypeNums[this.form.trainingType];
}
}
}
};
name: 'EditRule',
props: {},
computed: {
types() {
return [{ value: 1, label: '理论题' }, { value: 2, label: '实训题' }]
},
subtypes() {
const data = {
'1': [{ value: 1, label: '单选题' }, { value: 2, label: '多选题' }, { value: 3, label: '判断题' }],
'2': [{ value: 4, label: '单操实训' }, { value: 5, label: '场景实训' }],
}
return data[this.form.type]
},
title() {
return this.isEditMode ? this.$t('publish.modifyRules') : this.$t('publish.addRules')
},
},
data() {
var number = (rule, value, message) => {
if (!value) {
return message(new Error(this.$t('publish.inputQuestionNumber')))
}
setTimeout(() => {
if (Number(value) == 0) {
message(new Error(this.$t('publish.inputQuestionNumberError')))
} else if (!Number(value)) {
message(new Error(this.$t('publish.inputValidNumber')))
} else if (Number(value) > this.topicNum && this.form.type === 1) {
message(new Error(this.$t('publish.inputNumberError')))
} else {
message()
}
}, 100)
}
var score = (rule, value, message) => {
if (!value) {
return message(new Error(this.$t('publish.inputScorePerQuestion')))
} else {
message()
}
}
return {
form: {
id: '',
type: '',
subtype: '',
tags: [],
amount: 1,
score: 1,
},
topicNum: 0,
dialogShow: false,
rules: {
type: [{ required: true, message: this.$t('publish.selectTestType'), trigger: 'change' }],
subtype: [{ required: true, message: '请选择规则类型', trigger: 'change' }],
amount: [{ required: true, validator: number, trigger: 'blur' }],
score: [{ required: true, validator: score, trigger: 'blur' }],
},
}
},
created() {
},
mounted() {},
methods: {
show(detail) {
this.dialogShow = true
this.$nextTick(() => {
this.$refs.form.resetFields()
if (detail) {
this.isEditMode = true
this.form = {
type: detail.type,
subtype: detail.subtype,
amount: detail.amount,
score: detail.score,
id: detail.id || '',
}
this.topicNum = detail.topicNum
} else {
this.isEditMode = false
}
})
},
getQuestionAmount() {
if (!(this.form.type && this.form.subtype)) return
if (this.form.type === 2) return //
const param = {
orgId: this.$store.state.user.companyId,
groupType: this.form.type,
subType: this.form.subtype,
}
getQuestionAmount(param).then(resp => {
this.topicNum = resp.data
})
},
handleOk() {
this.$refs['form'].validate(valid => {
if (valid) {
this.$emit('submit', { ...this.form, topicNum: this.topicNum }, this.isEditMode)
this.handleCancel()
}
})
},
handleCancel() {
this.topicNum = 0
this.dialogShow = false
},
},
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
/deep/ {
.el-dialog {
width: 600px;
}
/deep/ {
.el-dialog {
width: 600px;
}
.el-form-item__content {
width: calc(100% - 80px);
}
.el-form-item__content {
width: calc(100% - 80px);
}
.el-cascader {
width: 100%;
}
}
.el-cascader {
width: 100%;
}
}
</style>

View File

@ -1,214 +1,146 @@
<template>
<div class="exam-rule">
<el-form ref="form" :model="examData" :rules="rules" label-width="120px" class="demo-form">
<el-form-item :label="$t('publish.testName')" prop="name">
<el-input v-model="examData.name" :placeholder="$t('publish.inputTestName')" />
</el-form-item>
<el-form-item label="归属地图" prop="mapId">
<el-select v-model="examData.mapId" placeholder="请选择归属地图" :disabled="isEdit">
<el-option v-for="map in mapList" :key="map.id" :label="map.name" :value="map.id" />
</el-select>
</el-form-item>
<el-form-item label="工作站类型" prop="prdType">
<el-select v-model="examData.prdType" placeholder="请选择工作站类型" :disabled="isEdit">
<el-option v-for="prd in prdList" :key="prd.value" :label="prd.label" :value="prd.value" />
</el-select>
</el-form-item>
<el-form-item :label="$t('publish.testDuration')" prop="duration">
<el-input-number v-model="examData.duration" placeholder="请输入" style="float: left; width: calc(100% - 80px);" :disabled="isEdit" :min="1" />
<span style="width:80px; display: block;float: left; text-align: center;">&nbsp;{{ $t('publish.durationMinutes') }}</span>
</el-form-item>
<el-form-item label="开放时间要求" prop="haveDate">
<el-switch v-model="haveDate" />
</el-form-item>
<el-form-item v-if="haveDate" :label="$t('publish.testDate')">
<el-col :span="11">
<el-form-item prop="startDate">
<el-date-picker
v-model="examData.startDate"
type="datetime"
:placeholder="$t('publish.startTestTime')"
style="width: 100%;"
value-format="yyyy-MM-dd HH:mm:ss"
:default-value="new Date()"
:picker-options="pickerOptions"
/>
</el-form-item>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="11">
<el-form-item prop="endDate">
<el-date-picker
v-model="examData.endDate"
value-format="yyyy-MM-dd HH:mm:ss"
type="datetime"
:placeholder="$t('publish.endTestTime')"
style="width: 100%;"
/>
</el-form-item>
</el-col>
</el-form-item>
<el-form-item :label="$t('publish.fullScore')" prop="fullMark">
<el-input-number v-model="examData.fullMark" placeholder="" :disabled="isEdit" :min="1" @change="fullMarkChange" />
</el-form-item>
<el-form-item :label="$t('publish.passingScore')" prop="passMark">
<el-input-number v-model="examData.passMark" placeholder="" :disabled="isEdit" :min="1" />
</el-form-item>
<el-form-item v-if="!$route.path.includes('info')" :label="$t('publish.whetherToTry')" required>
<el-radio-group v-model="trial">
<el-radio label="1">{{ $t('publish.trialNo') }}</el-radio>
<el-radio label="2">{{ $t('publish.trialYes') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="$t('publish.testDescription')" prop="desc">
<el-input v-model="examData.desc" type="textarea" :placeholder="$t('publish.inputTestDescription')" :disabled="isEdit" />
</el-form-item>
</el-form>
</div>
<div class="exam-rule">
<el-form ref="form" :model="examData" :rules="rules" label-width="120px" class="demo-form">
<el-form-item :label="$t('publish.testName')" prop="name">
<el-input v-model="examData.name" :placeholder="$t('publish.inputTestName')" />
</el-form-item>
<el-form-item label="简介" prop="profile">
<el-input v-model="examData.profile" placeholder="请输入简介" />
</el-form-item>
<el-form-item :label="$t('publish.testDuration')" prop="validDuration">
<el-input-number
v-model="examData.validDuration"
placeholder="请输入"
style="float: left; width: calc(100% - 80px);"
:min="1"
/>
<span style="width:80px; display: block;float: left; text-align: center;"
>&nbsp;{{ $t('publish.durationMinutes') }}</span
>
</el-form-item>
<el-form-item label="开放时间要求" prop="haveDate">
<el-switch v-model="haveDate" />
</el-form-item>
<el-form-item v-if="haveDate" :label="$t('publish.testDate')">
<el-col :span="11">
<el-form-item prop="startTime">
<el-date-picker
v-model="examData.startTime"
type="datetime"
:placeholder="$t('publish.startTestTime')"
style="width: 100%;"
value-format="yyyy-MM-dd HH:mm:ss"
:default-value="new Date()"
:picker-options="pickerOptions"
/>
</el-form-item>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="11">
<el-form-item prop="endTime">
<el-date-picker
v-model="examData.endTime"
value-format="yyyy-MM-dd HH:mm:ss"
type="datetime"
:placeholder="$t('publish.endTestTime')"
style="width: 100%;"
/>
</el-form-item>
</el-col>
</el-form-item>
<el-form-item :label="$t('publish.fullScore')" prop="fullScore">
<el-input-number v-model="examData.fullScore" placeholder="" :min="1" @change="fullScoreChange" />
</el-form-item>
<el-form-item :label="$t('publish.passingScore')" prop="passScore">
<el-input-number v-model="examData.passScore" placeholder="" :min="1" />
</el-form-item>
<!-- <el-form-item v-if="!$route.path.includes('info')" :label="$t('publish.whetherToTry')" required>
<el-radio-group v-model="trial">
<el-radio label="1">{{ $t('publish.trialNo') }}</el-radio>
<el-radio label="2">{{ $t('publish.trialYes') }}</el-radio>
</el-radio-group>
</el-form-item> -->
</el-form>
</div>
</template>
<script>
import { updateExamRules } from '@/api/management/exam';
import { getMapListByProjectCode } from '@/api/jmap/map';
import { getSessionStorage } from '@/utils/auth';
import { ProjectCode } from '@/scripts/ProjectConfig';
export default {
name: 'ExamFrom',
props: {
examData: {
type: Object,
default() {
return {};
}
}
},
data() {
var checkEndDate = (rule, value, callback) => {
if (this.examData.startDate && value) {
const startTime = new Date(this.examData.startDate).getTime();
const endTime = new Date(value).getTime();
if (startTime > endTime) {
callback(new Error('开始时间必须小于截止时间'));
} else {
callback();
}
} else {
callback();
}
};
var checkPassMark = (rule, value, callback) => {
if (value > this.examData.fullMark) {
callback(new Error('及格分必须小于等于满分'));
} else {
callback();
}
};
return {
pickerOptions: {
disabledDate(time) {
return time.getTime() < new Date(new Date().toLocaleDateString()).getTime();
}
},
haveDate: false,
mapList: [],
prdList: [{ label: 'ATS现地工作站', value: '01' }, { label: 'ATS行调工作站', value: '02' }],
trial: '1',
options: [],
selectDisable: false,
rules: {
name: [
{ required: true, message: this.$t('publish.inputTestName'), trigger: 'blur' }
],
prdType: [
{ required: true, message: '请选择产品类型', trigger: 'change' }
],
mapId: [
{ required: true, message: '请选择归属地图', trigger: 'change' }
],
duration: [
{ required: true, message: this.$t('publish.inputTestDuration'), trigger: 'blur' }
],
fullMark: [
{ required: true, message: this.$t('publish.inputFullScore'), trigger: 'blur' }
],
trial: [
{ required: true, message: this.$t('publish.selectWetherTrial'), trigger: 'blur' }
],
passMark: [
{ required: true, message: this.$t('publish.inputPassingScore'), trigger: 'blur' },
{ validator: checkPassMark, trigger: 'blur' }
],
endDate: [
{ validator: checkEndDate, trigger: 'change' }
]
}
};
},
computed: {
isEdit() {
return this.$route.params.mode == 'edit';
}
},
created() {
this.refresh();
},
mounted() {
},
methods: {
checkedForm(type) {
this.$refs['form'].validate((valid) => {
if (valid) {
this.$emit(type);
}
});
},
fullMarkChange() {
this.$refs.form.validateField('passMark');
},
getDate(date) {
const now = new Date(date);
const y = now.getFullYear();
const m = now.getMonth() + 1;
const d = now.getDate();
return y + '-' + (m < 10 ? '0' + m : m) + '-' + (d < 10 ? '0' + d : d) + ' ' + now.toTimeString().substr(0, 8);
},
updateForm() {
this.$refs['form'].validate(async (valid) => {
if (valid) {
const model = {
id: this.$route.params.ruleId,
name: this.examData.name,
endTime: this.examData.endDate,
startTime: this.examData.startDate,
trial: this.trial == 2
};
try {
await updateExamRules(model);
this.$message.success(this.$t('publish.updateExamRuleSuccess'));
} catch (error) {
this.$messageBox(this.$t('publish.updateExamRuleFailed'));
}
}
});
},
refresh() {
const project = ProjectCode[getSessionStorage('project')];
getMapListByProjectCode(project).then(resp => {
this.mapList = resp.data;
}).catch(e => {
this.$message.error('获取地图列表数据异常:' + e.message);
});
}
}
};
name: 'ExamFrom',
props: {
examData: {
type: Object,
default() {
return {}
},
},
},
data() {
var checkendTime = (rule, value, message) => {
if (this.examData.startTime && value) {
const startTime = new Date(this.examData.startTime).getTime()
const endTime = new Date(value).getTime()
if (startTime > endTime) {
message(new Error('开始时间必须小于截止时间'))
} else {
message()
}
} else {
message()
}
}
var checkPassScore = (rule, value, message) => {
if (value > this.examData.fullScore) {
message(new Error('及格分必须小于等于满分'))
} else {
message()
}
}
return {
pickerOptions: {
disabledDate(time) {
return time.getTime() < new Date(new Date().toLocaleDateString()).getTime()
},
},
haveDate: false,
options: [],
selectDisable: false,
rules: {
name: [{ required: true, message: this.$t('publish.inputTestName'), trigger: 'blur' }],
validDuration: [{ required: true, message: this.$t('publish.inputTestDuration'), trigger: 'blur' }],
fullScore: [{ required: true, message: this.$t('publish.inputFullScore'), trigger: 'blur' }],
passScore: [
{ required: true, message: this.$t('publish.inputPassingScore'), trigger: 'blur' },
{ validator: checkPassScore, trigger: 'blur' },
],
endTime: [{ validator: checkendTime, trigger: 'change' }],
},
}
},
computed: {
isEdit() {
return this.$route.params.mode === 'edit'
},
},
created() {},
mounted() {},
methods: {
checkForm() {
return this.$refs['form'].validate()
},
fullScoreChange() {
this.$refs.form.validateField('passScore')
},
},
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.exam-rule {
height: 100%;
}
.exam-rule {
height: 100%;
}
.line {
font-size: 16px;
text-align: center;
}
.line {
font-size: 16px;
text-align: center;
}
</style>

View File

@ -1,220 +1,199 @@
<template>
<div class="joylink-card">
<div class="exam-box">
<el-steps class="steps" :active="currentStep">
<el-step :title="$t('publish.testDefinitionMaking')" icon="el-icon-edit" />
<el-step :title="$t('publish.examRuleMaking')" icon="el-icon-setting" />
</el-steps>
<div class="joylink-card forms">
<template v-if="currentStep == 1" class="definition">
<exam-from ref="exam" :exam-data="examData" @goNextStep="goNextStep" @createQuickly="createQuickly" />
</template>
<template v-else class="rule">
<rule-from ref="rule" :rule-list="ruleList" :exam-data="examData" @regulation="regulation" />
</template>
</div>
<div class="draft">
<el-button-group>
<el-button v-if="isPrevStep" type="primary" @click="prevStep">{{ this.$t('global.lastStep') }}</el-button>
<el-button v-if="isNextStep" type="primary" @click="nextStep">{{ this.$t('global.nextStep') }}</el-button>
<el-button v-if="isUpdate" type="warning" @click="update">{{ $t('global.update') }}</el-button>
<el-button v-if="isCreate" type="primary" @click="create">{{ $t('global.create') }}</el-button>
<el-button type="primary" @click="turnback">{{ $t('global.back') }}</el-button>
<el-button v-if="isFastCreate" type="primary" @click="goToCheckForm">快速创建</el-button>
</el-button-group>
</div>
</div>
</div>
<div class="joylink-card">
<div class="exam-box">
<el-steps class="steps" :active="currentStep">
<el-step :title="$t('publish.testDefinitionMaking')" icon="el-icon-edit" />
<el-step :title="$t('publish.examRuleMaking')" icon="el-icon-setting" />
</el-steps>
<div class="joylink-card forms">
<exam-from v-show="currentStep === 1" ref="exam" :exam-data="examData" />
<rule-from
:is-edit-mode="isEditMode"
v-show="currentStep === 2"
ref="rule"
:rule-list="ruleList"
:exam-data="examData"
/>
</div>
<div class="draft">
<el-button-group>
<el-button v-if="showPrevStep" type="primary" @click="prevStep">{{
this.$t('global.lastStep')
}}</el-button>
<el-button v-if="showNextStep" type="primary" @click="nextStep">{{
this.$t('global.nextStep')
}}</el-button>
<el-button v-if="currentStep === 2" type="primary" @click="submit">提交</el-button>
<el-button type="primary" @click="turnback">{{ $t('global.back') }}</el-button>
</el-button-group>
</div>
</div>
</div>
</template>
<script>
import RuleFrom from './rule';
import ExamFrom from './examFrom';
import { getExamLessonDetail, createExam } from '@/api/management/exam';
import { UrlConfig } from '@/scripts/ConstDic';
import RuleFrom from './rule'
import ExamFrom from './examFrom'
import { getPaperDetail } from '@/api/management/exam'
import { UrlConfig } from '@/scripts/ConstDic'
import { createPaper, editPaper } from '@/api/management/exam'
export default {
name: 'ExamRule',
components: {
ExamFrom,
RuleFrom
},
data() {
return {
currentStep: 1,
examData: {
name: '',
mapId: '',
prdType: '',
startDate: '',
endDate: '',
desc: '',
type: '',
duration: '',
fullMark: '',
passMark: ''
},
ruleList: []
};
},
computed: {
isPrevStep() {
return this.currentStep == 2;
},
isNextStep() {
return this.currentStep == 1;
},
isUpdate() {
return this.$route.params.mode == 'edit';
},
isCreate() {
return this.currentStep == 2 && this.$route.params.mode !== 'edit';
},
isFastCreate() {
return this.currentStep == 1 && this.$route.params.mode != 'edit' && Number(this.$route.params.ruleId);
}
},
created() {
if (this.$route.params.ruleId != 0) {
getExamLessonDetail(this.$route.params.ruleId).then(res => {
this.examData = {
name: res.data.name,
mapId: res.data.mapId + '',
prdType: res.data.prdType,
startDate: res.data.startTime,
endDate: res.data.endTime,
desc: res.data.remarks,
type: res.data.type,
duration: Number(res.data.duration) / 60,
fullMark: res.data.fullPoint,
passMark: res.data.passingPoint
};
this.ruleList = res.data.examDefinitionRulesVOList;
this.$nextTick(() => {
this.$refs.exam.haveDate = !!this.examData.startDate;
});
});
}
},
methods: {
regulation() {
this.currentStep = 1;
this.$nextTick(() => {
this.$refs.exam.haveDate = !!this.examData.startDate;
});
},
async createQuickly() {
const resp = await getExamLessonDetail(this.$route.params.ruleId);
const ruleList = resp.data.examDefinitionRulesVOList;
const result = {
duration: Number(this.examData.duration) * 60, //
examDefinitionRulesVOList: ruleList, //
fullPoint: Number(this.examData.fullMark), //
mapId: this.examData.mapId, // id
prdType: this.examData.prdType,
name: this.examData.name, //
passingPoint: Number(this.examData.passMark), //
remarks: this.examData.desc, //
endTime: this.examData.endDate,
startTime: this.examData.startDate,
type: this.examData.type, //
trial: this.examData.trial == 2 //
};
let res = {};
try {
res = await createExam(result);
this.$message.success({ message: res.message });
this.$store.dispatch('exam/setRuleList', []); //
const path = `${this.$route.path.match(/(\/.*)\/examRule/)[1]}${UrlConfig.examRuleManage}`;
this.$router.replace({ path: `${path}`, query: { mapId: this.$route.query.mapId, noPreLogout: this.$route.query.noPreLogout } });
name: 'ExamRule',
components: {
ExamFrom,
RuleFrom,
},
data() {
return {
currentStep: 1,
examData: {
name: '',
profile: '',
startTime: '',
endTime: '',
validDuration: 30,
fullScore: 100,
passScore: 60,
},
ruleList: [],
}
},
computed: {
orgId() {
return this.$store.state.user.companyId
},
showPrevStep() {
return this.currentStep == 2
},
showNextStep() {
return this.currentStep == 1
},
isEditMode() {
return this.$route.params.mode == 'edit'
},
},
created() {
if (this.isEditMode) {
getPaperDetail(this.$route.params.paperId).then(res => {
this.examData = {
name: res.data.name,
profile: res.data.profile,
startTime: res.data.startTime,
endTime: res.data.endTime,
validDuration: Number(res.data.validDuration),
fullScore: res.data.fullScore,
passScore: res.data.passScore,
}
this.ruleList = res.data.ruleList
this.$nextTick(() => {
this.$refs.exam.haveDate = !!this.examData.startTime
})
})
}
},
methods: {
prevStep() {
this.currentStep = 1
},
nextStep() {
this.$refs.exam
.checkForm()
.then(() => {
this.currentStep = 2
})
.catch(() => {})
},
submit() {
const scoreValid = this.$refs.rule.checkTotolScores()
if (!scoreValid) {
this.$message.warning('规则满分与试题定义不匹配')
return
}
const examData = { ...this.examData, ...{ orgId: this.orgId } }
const ruleData = this.ruleList
const uploadData = { ...examData, ruleList: ruleData }
console.log(JSON.stringify(uploadData))
const uploadMethodMap = {
add: createPaper,
edit: editPaper,
}
if (this.isEditMode) {
uploadData.id = this.$route.params.paperId
}
} catch (error) {
if (error) {
this.$messageBox(`${this.$t('publish.saveRuleFailed')} ${error.message}`);
} else {
this.$messageBox(`${this.$t('publish.saveRuleFailed')}`);
}
}
},
goToCheckForm() {
this.$refs.exam.checkedForm('createQuickly');
},
prevStep() {
this.$refs.rule.regulation();
},
goNextStep() {
this.currentStep = 2;
},
nextStep() {
this.$refs.exam.checkedForm('goNextStep');
},
update() {
if(this.currentStep === 1) {
this.$refs.exam.updateForm();
} else if (this.currentStep === 2) {
this.$refs.rule.updateOk();
}
},
create() {
this.$refs.rule.creatOk();
},
turnback() {
const path = `${this.$route.path.match(/(\/.*)\/examRule/)[1]}${UrlConfig.examRuleManage}`;
if (this.$route.query.source === 'org') {
this.$router.go(-1);
} else {
this.$router.replace({ path: `${path}`, query: { mapId: this.$route.query.mapId, noPreLogout: this.$route.query.noPreLogout} });
}
}
}
};
uploadMethodMap[this.$route.params.mode](uploadData).then(resp => {
if (resp.code === 200) {
this.$message.success(`${this.isEditMode ? '修改' : '创建'}成功`)
this.turnback()
} else {
this.$message.error(resp.message)
console.log(uploadData)
console.log(resp)
}
})
},
turnback() {
const path = `${this.$route.path.match(/(\/.*)\/examRule/)[1]}${UrlConfig.examRuleManage}`
if (this.$route.query.source === 'org') {
this.$router.go(-1)
} else {
this.$router.replace({
path: `${path}`,
query: { mapId: this.$route.query.mapId, noPreLogout: this.$route.query.noPreLogout },
})
}
},
},
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.joylink-card{
.card-title{
text-align: center;
height: 47px;
line-height: 47px;
border-bottom: 1px solid #e6e6e6;
font-weight:bold;
}
}
.card-box{
overflow: hidden;
height: 100%;
}
.exam-box {
padding-top: 10px;
overflow: auto;
.joylink-card {
.card-title {
text-align: center;
height: 47px;
line-height: 47px;
border-bottom: 1px solid #e6e6e6;
font-weight: bold;
}
}
.card-box {
overflow: hidden;
height: 100%;
}
.exam-box {
padding-top: 10px;
overflow: auto;
/deep/ {
.el-step__icon.is-icon {
width: 95px;
}
}
/deep/ {
.el-step__icon.is-icon {
width: 95px;
}
}
.steps {
width: 980px;
margin: 0 auto;
padding-top: 5px;
}
.steps {
width: 980px;
margin: 0 auto;
padding-top: 5px;
}
.forms {
width: 800px;
margin: 0 auto;
margin-top: 20px;
padding: 40px;
}
}
.forms {
width: 800px;
margin: 0 auto;
margin-top: 20px;
padding: 40px;
}
}
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
.draft {
width: 500px;
text-align: center;
margin: 20px auto;
}
.draft {
width: 500px;
text-align: center;
margin: 20px auto;
}
</style>

View File

@ -1,342 +1,205 @@
<template>
<div class="exam-rule">
<span>{{ $t('publish.fullScoreTips') }} {{ examData.fullMark }} {{ $t('publish.scorePoints') }}</span>
<el-button class="addList" size="small" @click="handleAdd">{{ $t('publish.addRules') }}</el-button>
<el-table :data="ruleList" border show-summary style="width: 100%; min-height: 300px;" :summary-method="getSummaries">
<el-table-column prop="name" :label="$t('publish.trainingType')">
<template slot-scope="scope">
<span>{{ getOperateName(scope.row) }}</span>
</template>
</el-table-column>
<el-table-column prop="num" :label="$t('publish.questionsNumber')" width="100">
<template slot-scope="scope">
<span>{{ scope.row.num }}</span>
<el-tooltip v-if="checkNum(scope.row)" effect="dark" content="题库数量不足" placement="top">
<i class="el-icon-warning-outline"></i>
</el-tooltip>
</template>
</el-table-column>
<el-table-column prop="point" :label="$t('publish.eachScore')" width="100" />
<el-table-column :label="$t('publish.totalScore')" width="100">
<template slot-scope="scope">
<span>{{ Number(scope.row.num) * Number(scope.row.point) }}</span>
</template>
</el-table-column>
<el-table-column label="题库题数">
<template slot-scope="scope">
<span>{{ getTopicNum(scope.row) }}</span>
</template>
</el-table-column>
<el-table-column :label="$t('global.operate')" width="100">
<template slot-scope="scope">
<el-button type="text" size="small" @click="handleForm(scope)">{{ $t('global.edit') }}</el-button>
<el-button type="text" size="small" @click="deleteForm(scope)">{{ $t('global.delete') }}</el-button>
</template>
</el-table-column>
</el-table>
<edit-rule
ref="addRule"
:map-id="examData.mapId"
:operation-type-map="operationTypeMap"
:training-operate-type-map="trainingOperateTypeMap"
:training-type-nums="trainingTypeNums"
:operation-type-nums="operationTypeNums"
:training-type-list="trainingTypeList"
:prd-type="examData.prdType"
@addRuleList="addRuleList"
@editRuleList="editRuleList"
/>
</div>
<div class="exam-rule">
<span>{{ $t('publish.fullScoreTips') }} {{ examData.fullScore }} {{ $t('publish.scorePoints') }}</span>
<el-button class="addList" size="small" @click="handleAdd">{{ $t('publish.addRules') }}</el-button>
<el-table
:data="ruleList"
border
style="width: 100%; min-height: 300px;"
show-summary
:summary-method="getSummaries"
>
<el-table-column prop="type" label="试题类型">
<template slot-scope="scope">
<span>{{ types[scope.row.type] }}</span>
</template>
</el-table-column>
<el-table-column prop="subtype" label="规则类型">
<template slot-scope="scope">
<span>{{ subtypes[scope.row.subtype] }}</span>
</template>
</el-table-column>
<el-table-column prop="amount" label="题目数量" width="100">
<template slot-scope="scope">
<span>{{ scope.row.amount }}</span>
</template>
</el-table-column>
<el-table-column prop="score" :label="$t('publish.eachScore')" width="100" />
<el-table-column :label="$t('publish.totalScore')" width="100">
<template slot-scope="scope">
<span>{{ Number(scope.row.amount) * Number(scope.row.score) }}</span>
</template>
</el-table-column>
<el-table-column label="题库题数">
<template slot-scope="scope">
<span>{{ scope.row.topicNum }}</span>
</template>
</el-table-column>
<el-table-column :label="$t('global.operate')" width="100">
<template slot-scope="scope">
<el-button type="text" size="small" @click="editRow(scope)">{{ $t('global.edit') }}</el-button>
<el-button type="text" size="small" @click="deleteRule(scope)">{{ $t('global.delete') }}</el-button>
</template>
</el-table-column>
</el-table>
<edit-rule @submit="handleRuleSubmit" ref="addRule" />
</div>
</template>
<script>
import { createExam, updateExamRule } from '@/api/management/exam';
import { UrlConfig, getOperateTypeMap } from '@/scripts/ConstDic';
import editRule from './editRule';
import ConstConfig from '@/scripts/ConstConfig';
import { getTrainingTypeAndNumByMapIdAndPrdType } from '@/api/jmap/training';
import editRule from './editRule'
export default {
name: 'Rule',
components: {
editRule
},
props: {
examData: {
type: Object,
default: null
},
ruleList: {
type: Array,
default() {
return [];
}
}
},
data() {
return {
typeList: [],
operationTypeMap: {},
trainingOperateTypeMap: {},
trainingTypeNums:{}, //
operationTypeNums: {}, //
trainingTypeList: [] //
};
},
computed: {
},
watch: {
},
async created() {
getTrainingTypeAndNumByMapIdAndPrdType({ mapId: this.examData.mapId, prdType: this.examData.prdType }).then(res => {
const list = [];
this.trainingTypeNums = {};
const operateTypeMap = {};
this.operationTypeNums = res.data;
let val;
for (val in ConstConfig.ConstSelect.trainingDeviceType) {
if (res.data[val]) {
list.push({ value: val, label: ConstConfig.ConstSelect.trainingDeviceType[val].label, disabled: false});
this.trainingTypeNums[val] = 0;
const operateLabelMap = getOperateTypeMap(val);
operateTypeMap[val] = [];
let item;
for (item in res.data[val]) {
this.trainingTypeNums[val] += res.data[val][item];
operateTypeMap[val].push({ value: item, label:operateLabelMap[item], disabled: false });
}
}
}
this.trainingTypeList = list;
this.operationTypeMap = operateTypeMap;
}).catch(() => {
this.$messageBox(this.$t('publish.refreshFailed'));
});
},
methods: {
handleAdd() {
this.changeCourseDisable();
this.$refs.addRule.show();
},
async creatOk() {
if (this.ruleList.length) {
let flag = 0;
this.ruleList.forEach(rule => {
flag = flag + (Number(rule.num) * Number(rule.point));
});
if (flag == this.examData.fullMark) {
const result = {
duration: Number(this.examData.duration) * 60, //
examDefinitionRulesVOList: this.ruleList, //
fullPoint: Number(this.examData.fullMark), //
mapId: this.examData.mapId,
prdType: this.examData.prdType,
name: this.examData.name, //
passingPoint: Number(this.examData.passMark), //
remarks: this.examData.desc, //
endTime: this.examData.endDate,
startTime: this.examData.startDate,
type: this.examData.type, //
trial: this.examData.trial == 2 //
};
await this.save(result);
} else {
this.$messageBox(this.$t('publish.addExamRluesError'));
}
} else {
this.$messageBox(this.$t('publish.addExamRules'));
}
},
async updateOk() {
if (this.ruleList.length) {
let flag = 0;
this.ruleList.forEach(rule => {
flag = flag + (Number(rule.num) * Number(rule.point));
});
if (flag == this.examData.fullMark) {
const result = {
id: this.$route.params.ruleId,
duration: Number(this.examData.duration) * 60, //
examDefinitionRulesVOList: this.ruleList, //
fullPoint: Number(this.examData.fullMark), //
mapId: this.examData.mapId,
prdType: this.examData.prdType,
name: this.examData.name, //
passingPoint: Number(this.examData.passMark), //
remarks: this.examData.desc, //
endTime: this.examData.endDate,
startTime: this.examData.startDate,
type: this.examData.type, //
trial: this.examData.trial == 2 //
};
await this.update(result);
} else {
this.$messageBox(this.$t('publish.addExamRluesError'));
}
} else {
this.$messageBox(this.$t('publish.addExamRules'));
}
},
async save(data) {
try {
const res = await createExam(data);
this.$message.success({ message: res.message });
this.$store.dispatch('exam/setRuleList', []); //
const path = `${this.$route.path.match(/(\/.*)\/examRule/)[1]}${UrlConfig.examRuleManage}`;
if (this.$route.query.source === 'org') {
this.$router.go(-1);
} else {
this.$router.replace({ path: `${path}`, query: { mapId: this.$route.query.mapId, noPreLogout: this.$route.query.noPreLogout} });
}
} catch (error) {
this.$messageBox(`${this.$t('publish.saveRuleFailed')} ${error.message}`);
}
},
async update(data) {
try {
const res = await updateExamRule(data);
this.$message.success({ message: res.message });
this.$store.dispatch('exam/setRuleList', []); //
const path = `${this.$route.path.match(/(\/.*)\/examRule/)[1]}${UrlConfig.examRuleManage}`;
if (this.$route.query.source === 'org') {
this.$router.go(-1);
} else {
this.$router.replace({ path: `${path}`, query: { mapId: this.$route.query.mapId, noPreLogout: this.$route.query.noPreLogout} });
}
} catch (error) {
this.$messageBox(`${this.$t('publish.saveRuleFailed')} ${error.message}`);
}
},
addRuleList(data) {
const element = {
trainingType: data.trainingType,
operateType: data.operateType,
num: Number(data.number),
point: Number(data.mark)
};
this.ruleList.push(element);
},
deleteForm(data) {
const index = data.$index;
this.ruleList.splice(index, 1);
},
editRuleList(data) {
const element = {
trainingType: data.trainingType,
operateType: data.operateType,
num: Number(data.number),
point: Number(data.mark)
};
this.$set(this.ruleList, this.indexCourse, element);
},
//
changeCourseDisable() {
this.trainingTypeList.forEach(item => { item.disabled = false; });
for (const val in this.operationTypeMap) {
this.operationTypeMap[val].forEach( item => { item.disabled = false; });
}
this.ruleList.forEach(ele => {
this.trainingTypeList.forEach(item => {
if (ele.trainingType == item.value && !ele.operateType) {
item.disabled = true;
}
});
(this.operationTypeMap[ele.trainingType] || []).forEach(item => {
if (ele.operateType && ele.operateType == item.value) {
item.disabled = true;
}
});
});
},
getOperateName(row) {
const trainingName = ConstConfig.ConstSelect.trainingDeviceType[row.trainingType].label;
if (row.operateType) {
const operateName = getOperateTypeMap(row.trainingType)[row.operateType];
return `${trainingName}-${operateName}`;
} else {
return trainingName;
}
},
getTopicNum(row) {
//this.operationTypeNums
//console.log(row, this.operationTypeNums);
return this.operationTypeNums[row.trainingType] ? (this.operationTypeNums[row.trainingType][row.operateType]||0): 0;
},
checkNum(row) {
if(!this.operationTypeNums[row.trainingType]) {
return true;
} else if(!this.operationTypeNums[row.trainingType][row.operateType]){
return true;
} else if(row.num > this.operationTypeNums[row.trainingType][row.operateType]) {
return true;
} else {
return false;
}
},
handleForm(data) {
this.changeCourseDisable();
this.indexCourse = data.$index;
const list = JSON.stringify(data.row);
const detail = JSON.parse(list);
this.$refs.addRule.show(detail);
},
regulation() {
this.$emit('regulation', this.course);
},
getSummaries({ columns, data }) {
const sums = [];
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = '合计';
return;
} else if (index === 1) {
const values = data.map(item => Number(item.num));
sums[1] = values.reduce((prev, curr) => {
const value = Number(curr);
if (!isNaN(value)) {
return prev + curr;
} else {
return prev;
}
}, 0);
} else if ( index === 3) {
const values = data.map(item => Number(item.num) * Number(item.point));
sums[3] = values.reduce((prev, curr) => {
const value = Number(curr);
if (!isNaN(value)) {
return prev + curr;
} else {
return prev;
}
}, 0) + '分';
}
});
return sums;
}
}
};
name: 'Rule',
components: {
editRule,
},
props: {
examData: {
type: Object,
default: null,
},
ruleList: {
type: Array,
default() {
return []
},
},
isEditMode: {
type: Boolean,
},
},
data() {
return {
currentTotalScore: 0,
operationTypeMap: {},
trainingOperateTypeMap: {},
trainingTypeNums: {}, //
operationTypeNums: {}, //
trainingTypeList: [], //
}
},
computed: {
types() {
return ['', '理论题', '实训题']
},
subtypes() {
return ['', '单选题', '多选题', '判断题', '单操实训', '场景实训']
},
},
watch: {},
created() {},
methods: {
handleAdd() {
this.changeCourseDisable()
this.$refs.addRule.show()
},
handleRuleSubmit(formData, isEdit) {
const data = {
type: formData.type,
subtype: formData.subtype,
amount: formData.amount,
score: formData.score,
topicNum: formData.topicNum,
}
if (isEdit) {
this.$set(this.ruleList, this.editingIndex, data)
} else {
this.ruleList.push(data)
}
},
deleteRule(data) {
const index = data.$index
this.ruleList.splice(index, 1)
},
//
changeCourseDisable() {
this.trainingTypeList.forEach(item => {
item.disabled = false
})
for (const val in this.operationTypeMap) {
this.operationTypeMap[val].forEach(item => {
item.disabled = false
})
}
this.ruleList.forEach(ele => {
this.trainingTypeList.forEach(item => {
if (ele.trainingType == item.value && !ele.operateType) {
item.disabled = true
}
})
;(this.operationTypeMap[ele.trainingType] || []).forEach(item => {
if (ele.operateType && ele.operateType == item.value) {
item.disabled = true
}
})
})
},
checkTotolScores() {
console.log(this.currentTotalScore === this.examData.fullScore)
return this.currentTotalScore === this.examData.fullScore
},
editRow(data) {
this.changeCourseDisable()
this.editingIndex = data.$index
const list = JSON.stringify(data.row)
const detail = JSON.parse(list)
this.$refs.addRule.show(detail)
},
getSummaries({ columns, data }) {
const sums = []
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = '合计'
return
} else if (index === 2) {
const values = data.map(item => Number(item.amount))
sums[2] = values.reduce((prev, curr) => {
const value = Number(curr)
if (!isNaN(value)) {
return prev + curr
} else {
return prev
}
}, 0)
} else if (index === 4) {
const values = data.map(item => Number(item.amount) * Number(item.score))
this.currentTotalScore = sums[4] = values.reduce((prev, curr) => {
const value = Number(curr)
if (!isNaN(value)) {
return prev + curr
} else {
return prev
}
}, 0)
}
})
return sums
},
},
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.exam-rule {
.addList {
float: right;
font-size: 14px;
color: #000;
margin-bottom: 8px;
cursor: pointer;
}
.exam-rule {
.addList {
float: right;
font-size: 14px;
color: #000;
margin-bottom: 8px;
cursor: pointer;
}
.btn-footer {
width: 100%;
display: flex;
justify-content: center;
margin-top: 20px;
}
.btn-footer {
width: 100%;
display: flex;
justify-content: center;
margin-top: 20px;
}
/deep/ .el-table__footer-wrapper {
.is-leaf:nth-child(3) {
font-size: 0;
}
}
}
/deep/ .el-table__footer-wrapper {
.is-leaf:nth-child(3) {
font-size: 0;
}
}
}
</style>

View File

@ -276,7 +276,8 @@ export default {
},
publicList(index, row) {
this.$router.push({ path: `/publish/map/detail`, query: { mapId: row.id } });
// this.$router.push({ path: `/publish/map/detail`, query: { mapId: row.id } });
this.$router.push({ path: `/systemManagement/lineDataManage/PublishMapDetail`, query: { mapId: row.id } });
},
handlePutaway(index, row) {