WIP: 试卷管理

This commit is contained in:
Yuan 2022-10-17 10:02:21 +08:00
parent 0b080e2466
commit 5e634f08f8
8 changed files with 1134 additions and 1216 deletions

View File

@ -1,114 +1,233 @@
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 满分
*/
export function createPaper(data) {
return request({
url: `/api/v2/paper/composition/`,
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 满分
*/
export function editPaperBasic(data) {
return request({
url: `/api/v2/paper/composition/basic`,
method: 'PUT',
data,
})
}
/**
* @param {Number} pcId 试卷蓝图ID
*/
export function getPaperDetail(pcId) {
return request({
url: `/api/v2/paper/composition/${pcId}`,
method: 'GET',
})
}
/**
* @param {Number} params.orgId
* @param {Number} params.subtype
* @param {Array<String>} params.tags
*/
export function getQuestionAmount(params) {
return request({
url: ``,
method: 'GET',
params,
})
}
/**
* 试卷蓝图添加规则
* @param {Number} pcId 试卷蓝图ID
* @param {Number} type 试题类型(1-理论题2-实训题)
* @param {Number} subtype 规则类型 (理论题(1-单选题2-多选题3-判断题);实训题(4-单操实训5-场景实训))
* @param {Number} score 每题分值
* @param {Number} amount 题目数量
*/
export function addPaperRule(data) {
return request({
url: `/api/v2/paper/composition/rule`,
method: 'POST',
data,
})
}
/**
* 更新(保存)试卷蓝图的规则
* @param {Number} id 规则ID
* @param {Number} pcId 试卷蓝图ID
* @param {Number} type 试题类型(1-理论题2-实训题)
* @param {Number} subtype 规则类型 (理论题(1-单选题2-多选题3-判断题);实训题(4-单操实训5-场景实训))
* @param {Number} score 每题分值
* @param {Number} amount 题目数量
*/
export function editPaperRule(data) {
return request({
url: `/api/v2/paper/composition/rule`,
method: 'PUT',
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
},

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

@ -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,165 @@
<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;">
<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;">
<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" disabled></el-select>
</el-form-item> -->
<el-form-item label="题目数量" prop="amount">
<el-input-number
v-model="form.amount"
: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="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>
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) {
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: {
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,
}
} else {
this.isEditMode = false
}
})
},
handleOk() {
this.$refs['form'].validate(valid => {
if (valid) {
this.$emit('submit', this.form, 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,203 @@
<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, editPaperBasic, addPaperRule, editPaperRule } 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.$route.params.paperId != 0) {
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() {
console.log('step1 data: ', JSON.stringify(this.examData))
console.log('orgId:', this.orgId)
console.log('isEditMode:', this.isEditMode)
console.log('ruleList:', JSON.stringify(this.ruleList))
const examData = { ...this.examData, ...{ orgId: this.orgId } }
const ruleData = this.ruleList
} 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} });
}
}
}
};
const scoreValid = this.$refs.rule.checkTotolScores()
if (!scoreValid) {
this.$message.warning('规则满分与试题定义不匹配')
return
}
const uploadMethodMap = {
add: {
exam: createPaper,
rules: addPaperRule,
},
edit: {
exam: editPaperBasic,
rules: editPaperRule,
},
}
if (!this.isEditMode) {
uploadMethodMap.add.exam(examData).then(res => {
uploadMethodMap.add.rules()
})
} else {
uploadMethodMap.edit.exam({ ...examData, id: this.$route.params.paperId }).then(res => {
uploadMethodMap.edit.rules()
})
}
},
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,213 @@
<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>
<!-- <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="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>{{ getTopicNum(scope.row) }}</span> -->
<span>N/A</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,
}
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
}
})
})
},
getTopicNum(row) {
return this.operationTypeNums[row.trainingType]
? this.operationTypeNums[row.trainingType][row.operateType] || 0
: 0
},
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>