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

 Conflicts:
	src/views/publish/publishMap/editSubsystem.vue
This commit is contained in:
fan 2022-10-31 14:34:14 +08:00
commit e67d26ddf9
37 changed files with 2441 additions and 1146 deletions

View File

@ -6,7 +6,7 @@
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"start": "vue-cli-service serve --open", "start": "vue-cli-service serve --open",
"dev": "node --max_old_space_size=4096 node_modules/@vue/cli-service/bin/vue-cli-service.js serve", "dev": "node --max_old_space_size=4096 node_modules/@vue/cli-service/bin/vue-cli-service.js serve --open",
"build": "vue-cli-service build --mode production", "build": "vue-cli-service build --mode production",
"test": "vue-cli-service build --mode staging", "test": "vue-cli-service build --mode staging",
"local": "vue-cli-service build --mode", "local": "vue-cli-service build --mode",

View File

@ -251,7 +251,8 @@ export default {
this.updateButtonShow(val, old); this.updateButtonShow(val, old);
}, },
'$store.state.menuOperation.selectedCount': function (val) { '$store.state.menuOperation.selectedCount': function (val) {
const station = this.$store.getters['map/getDeviceByCode'](this.$store.state.map.showCentralizedStationCode); // debugger;
const station = this.$store.getters['map/getDeviceByCode'](this.$store.state.training.roleDeviceCode);
if (!station || station.controlMode === 'Interlock') { return; } if (!station || station.controlMode === 'Interlock') { return; }
this.selectedChange(); this.selectedChange();
}, },
@ -404,7 +405,7 @@ export default {
}); });
}, },
buttonDown(operation, commandTypeList) { buttonDown(operation, commandTypeList) {
const station = this.$store.getters['map/getDeviceByCode'](this.$store.state.map.showCentralizedStationCode); const station = this.$store.getters['map/getDeviceByCode'](this.$store.state.training.roleDeviceCode);
if (!station || station.controlMode === 'Interlock') { return; } if (!station || station.controlMode === 'Interlock') { return; }
this.clearOperate(); this.clearOperate();
if (operation != this.Command.cancel.clearMbm.operation) { if (operation != this.Command.cancel.clearMbm.operation) {
@ -679,7 +680,7 @@ export default {
selectedChange() { selectedChange() {
// //
const model = this.selected; // const model = this.selected; //
if ((this.$store.state.training.prdType != '01' && this.$store.state.training.prdType != '10') || this.selected._event !== MouseEvent.Left || (!model._type && !model._code)) { if (this.selected._event !== MouseEvent.Left || (!model._type && !model._code)) {
return; return;
} }
const buttonOperation = this.$store.state.menuOperation.buttonOperation; const buttonOperation = this.$store.state.menuOperation.buttonOperation;

View File

@ -193,9 +193,9 @@ class Handler {
stepOrder = JSON.parse(stepOrder); stepOrder = JSON.parse(stepOrder);
let operateOrder = getLocalStorage('operateOrder') || `1`; let operateOrder = getLocalStorage('operateOrder') || `1`;
operateOrder = JSON.parse(operateOrder); operateOrder = JSON.parse(operateOrder);
const step = stepList[stepOrder - 1]; // const step = stepList[stepOrder - 1];
// const index = stepOrder - 1 >= 0 ? stepOrder - 1 : 0; const index = stepOrder - 1 >= 0 ? stepOrder - 1 : 0;
// const step = stepList[index]; const step = stepList[index];
const stepOperation = step.operations[operateOrder]; const stepOperation = step.operations[operateOrder];
return stepOperation; return stepOperation;
} catch (e) { } catch (e) {

View File

@ -129,7 +129,8 @@ const training = {
}, },
handleCheckNewTrainingResult:({commit, state}, valid) => { handleCheckNewTrainingResult:({commit, state}, valid) => {
const stepList = JSON.parse(state.trainingDetail.stepJson); const stepList = JSON.parse(state.trainingDetail.stepJson);
const step = stepList[state.stepOrder - 1]; const index = state.stepOrder > 0 ? state.stepOrder - 1 : 0;
const step = stepList[index];
if (valid && step.operations.length === (state.operateOrder + 1 )) { if (valid && step.operations.length === (state.operateOrder + 1 )) {
commit('stepOverCountChange'); commit('stepOverCountChange');
} else if (valid) { } else if (valid) {

View File

@ -27,7 +27,7 @@ export function handlerUrl() {
// BASE_API = 'https://joylink.club/jlcloud'; // BASE_API = 'https://joylink.club/jlcloud';
// BASE_API = 'https://test.joylink.club/jlcloud'; // BASE_API = 'https://test.joylink.club/jlcloud';
// BASE_API = 'http://114.116.51.125/jlcloud'; // BASE_API = 'http://114.116.51.125/jlcloud';
// BASE_API = 'http://192.168.3.90:9000'; // 周寅 BASE_API = 'http://192.168.3.90:9000'; // 周寅
// BASE_API = 'http://192.168.3.94:9000'; // 旭强 // BASE_API = 'http://192.168.3.94:9000'; // 旭强
BASE_API = 'http://192.168.3.15:9000'; // 张赛 BASE_API = 'http://192.168.3.15:9000'; // 张赛
// BASE_API = 'http://192.168.3.5:9000'; // 夏增彬 // BASE_API = 'http://192.168.3.5:9000'; // 夏增彬

View File

@ -10,9 +10,9 @@
<div class="eachBTRpMenuBar">工作区选择</div> <div class="eachBTRpMenuBar">工作区选择</div>
<div class="eachBTRpMenuBar">帮助</div> <div class="eachBTRpMenuBar">帮助</div>
</div> </div>
<div class="BTRunplanClose" @click="quit"> <!-- <div class="BTRunplanClose" @click="quit">
<i class="el-icon-close" /> <i class="el-icon-close" />
</div> </div> -->
</div> </div>
<div class="BTRpTabs"> <div class="BTRpTabs">
<el-tabs v-model="activeTab" type="card" closable @tab-remove="removeTab"> <el-tabs v-model="activeTab" type="card" closable @tab-remove="removeTab">
@ -110,9 +110,9 @@ export default {
} }
this.activeTab = name; this.activeTab = name;
}, },
quit() { // quit() {
window.close(); // window.close();
}, // },
initLoadData() { initLoadData() {
loadMapDataById(this.$route.query.mapId, 'parse'); loadMapDataById(this.$route.query.mapId, 'parse');
}, },

View File

@ -51,7 +51,7 @@ export default {
type: 'select', type: 'select',
label: '分 类', label: '分 类',
config: { config: {
multiple: true, // multiple: true,
data: [] data: []
} }
} }
@ -70,7 +70,8 @@ export default {
{ {
title: '分 类', title: '分 类',
prop: 'tags', prop: 'tags',
type: 'tagMore', // type: 'tagMore',
type: 'tag',
width: '200', width: '200',
columnValue: (row) => { return this.lableTags(row); }, columnValue: (row) => { return this.lableTags(row); },
tagType: (row) => { tagType: (row) => {
@ -165,7 +166,7 @@ export default {
}, },
methods: { methods: {
beforeQuery(obj) { beforeQuery(obj) {
obj.labels = obj.labels ? obj.labels.join(',') : ''; // obj.labels = obj.labels ? obj.labels.join(',') : '';
return obj; return obj;
}, },
doCreate() { doCreate() {
@ -204,7 +205,8 @@ export default {
}, },
lableTags(row) { lableTags(row) {
return row.tags ? row.tags.split(',') : ''; // return row.tags ? row.tags.split(',') : '';
return row.tags || '';
}, },
answerTags(row) { answerTags(row) {
@ -310,7 +312,8 @@ export default {
const param = { const param = {
type: questionTypeMap[item], type: questionTypeMap[item],
topic: dataList[topicIndex][index], topic: dataList[topicIndex][index],
tags: dataList[tagsIndex][index] ? dataList[tagsIndex][index].replace(/\s+/g, ',') : '', // tags: dataList[tagsIndex][index] ? dataList[tagsIndex][index].replace(/\s+/g, ',') : '',
tags: dataList[tagsIndex][index] || '',
optionList: [] optionList: []
}; };
if (param.type === 'fill') { if (param.type === 'fill') {
@ -448,7 +451,7 @@ export default {
exportTemplate() { exportTemplate() {
const wb = XLSX.utils.book_new(); const wb = XLSX.utils.book_new();
const data1 = [{A: '理论试题导入模板', B: '', C:'', D:'', E:'', F: '', G: '', H: '', I: '', J: '', K: ''}]; const data1 = [{A: '理论试题导入模板', B: '', C:'', D:'', E:'', F: '', G: '', H: '', I: '', J: '', K: ''}];
const data2 = [{A: '说明1、本表表头第一行到第三行内容不能修改删除;\n 2、支持批量导入的题型单选题多选题判断题题型不能自定义只能按照表格提供的进行录入;\n 3、【判断题】在选项A中可填写√ 或正确选项B中填写× 或错误答案填写A或B\n 4、【分类】多个分类项使用空格隔开', B: '', C:'', D:'', E:'', F: '', G: '', H: '', I: '', J: '', K: ''}]; const data2 = [{A: '说明1、本表表头第一行到第三行内容不能修改删除;\n 2、支持批量导入的题型单选题多选题判断题题型不能自定义只能按照表格提供的进行录入;\n 3、【判断题】在选项A中可填写√ 或正确选项B中填写× 或错误答案填写A或B', B: '', C:'', D:'', E:'', F: '', G: '', H: '', I: '', J: '', K: ''}];
const data3 = [{A: '序号', B: '题干(必填)', C:'题型(必填)', D:'选项A必填', E:'选项B必填', F: '选项C', G: '选项D', H: '选项E', I: '选项F', J: '正确答案(必填)', K: '分类'}]; const data3 = [{A: '序号', B: '题干(必填)', C:'题型(必填)', D:'选项A必填', E:'选项B必填', F: '选项C', G: '选项D', H: '选项E', I: '选项F', J: '正确答案(必填)', K: '分类'}];
const data = [...data1, ...data2, ...data3]; const data = [...data1, ...data2, ...data3];
const mapType = { const mapType = {
@ -483,7 +486,8 @@ export default {
H: item.optionList[4] ? item.optionList[4].content : '', H: item.optionList[4] ? item.optionList[4].content : '',
I: item.optionList[5] ? item.optionList[5].content : '', I: item.optionList[5] ? item.optionList[5].content : '',
J: as, J: as,
K: item.tags ? item.tags.replace(',', ' ') : '' // K: item.tags ? item.tags.replace(',', ' ') : ''
K: item.tags || ''
}; };
data.push(obj); data.push(obj);
}); });

View File

@ -20,7 +20,8 @@
</el-table-column> </el-table-column>
<el-table-column prop="tags" label="分类" width="200"> <el-table-column prop="tags" label="分类" width="200">
<template slot-scope="scope"> <template slot-scope="scope">
<el-tag v-for="item in getTagesArr(scope.row.tags)" :key="item" type="primary" disable-transitions style="margin-right: 10px;">{{ item }}</el-tag> <!-- <el-tag v-for="item in getTagesArr(scope.row.tags)" :key="item" type="primary" disable-transitions style="margin-right: 10px;">{{ item }}</el-tag> -->
<el-tag v-if="scope.row.tags" type="primary" disable-transitions style="margin-right: 10px;">{{ scope.row.tags }}</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="type" label="类型" width="100"> <el-table-column prop="type" label="类型" width="100">

View File

@ -80,8 +80,7 @@ export default {
this.$message.warning('选项不能为空!'); this.$message.warning('选项不能为空!');
return; return;
} }
// this.formModel.companyId = parseInt(this.companyId); // this.formModel.tags = this.tagsArr.join(',');
this.formModel.tags = this.tagsArr.join(',');
createQuestion(this.formModel).then(resp => { createQuestion(this.formModel).then(resp => {
authUtils.setSessionStorage(this.path, JSON.stringify({ authUtils.setSessionStorage(this.path, JSON.stringify({
type: this.formModel.type type: this.formModel.type

View File

@ -12,7 +12,8 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="分 类"> <el-form-item label="分 类">
<el-select v-model="tagsArr" multiple filterable allow-create default-first-option placeholder="请选择分类" @change="tagsChange"> <el-select v-model="option.tags" filterable allow-create default-first-option placeholder="请选择分类">
<!-- <el-select v-model="tagsArr" multiple filterable allow-create default-first-option placeholder="请选择分类" @change="tagsChange"> -->
<el-option v-for="item in labelList" :key="item" :label="item" :value="item" /> <el-option v-for="item in labelList" :key="item" :label="item" :value="item" />
</el-select> </el-select>
</el-form-item> </el-form-item>

View File

@ -99,11 +99,10 @@ export default {
this.$store.state.race.preTheoryData[this.questionId] = this.formModel; this.$store.state.race.preTheoryData[this.questionId] = this.formModel;
this.doBack(); this.doBack();
} else if (valid) { } else if (valid) {
// this.formModel.companyId = parseInt(this.companyId); // this.formModel.tags = this.tagsArr;
this.formModel.tags = this.tagsArr; // if (Array.isArray(this.tagsArr)) {
if (Array.isArray(this.tagsArr)) { // this.formModel.tags = this.tagsArr.join(',');
this.formModel.tags = this.tagsArr.join(','); // }
}
updateOption(this.formModel).then(resp => { updateOption(this.formModel).then(resp => {
this.doBack(); this.doBack();
}).catch(error => { }).catch(error => {

View File

@ -48,9 +48,9 @@ export default {
}, },
{ {
title: this.$t('orderAuthor.belongsToMap'), title: this.$t('orderAuthor.belongsToMap'),
prop: 'mapId', prop: 'mapName',
type: 'tag', type: 'tag',
columnValue: (row) => { return this.$convertField(row.mapId, this.mapList, ['value', 'label']); }, columnValue: (row) => { return row.mapName || ''; },
tagType: (row) => { return ''; } tagType: (row) => { return ''; }
}, },
{ {

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="main" :style="{width: canvasWidth+'px'}"> <div class="main">
<transition name="el-zoom-in-bottom"> <transition name="el-zoom-in-bottom">
<!-- v-show="!specialDispatch" --> <!-- v-show="!specialDispatch" -->
<!-- <map-system-draft ref="mapCanvas" @back="back" />--> <!-- <map-system-draft ref="mapCanvas" @back="back" />-->
@ -143,5 +143,7 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
.main{ .main{
height: 100%; height: 100%;
width: 100%;
overflow: hidden;
} }
</style> </style>

File diff suppressed because it is too large Load Diff

View File

@ -128,7 +128,7 @@ export default {
{ {
name: '数字沙盘', name: '数字沙盘',
code: 'digitalStand', code: 'digitalStand',
roleList: ['STATION_SUPERVISOR'], roleList: ['STATION_SUPERVISOR', 'DISPATCHER'],
click: this.noEvent click: this.noEvent
}, },
{ // {label:'', name:'messageBoard', click:this.messageBoard, isShow:false}, { // {label:'', name:'messageBoard', click:this.messageBoard, isShow:false},

View File

@ -110,7 +110,7 @@ export default {
{ {
name: '数字沙盘', name: '数字沙盘',
code: 'digitalStand', code: 'digitalStand',
roleList: ['STATION_SUPERVISOR'], roleList: ['STATION_SUPERVISOR', 'DISPATCHER'],
click: this.changePictureShow click: this.changePictureShow
}, },
{ {
@ -187,7 +187,7 @@ export default {
} else if (this.roles === 'DISPATCHER') { } else if (this.roles === 'DISPATCHER') {
if (this.$route.query.lineCode === '16') { if (this.$route.query.lineCode === '16') {
this.changePictureShow('dispatcherManage'); this.changePictureShow('dispatcherManage');
this.$store.dispatch('app/ animationsClose'); this.$store.dispatch('app/animationsClose');
} else { } else {
this.changePictureShow('dispatchWork'); this.changePictureShow('dispatchWork');
} }

View File

@ -1,7 +1,7 @@
<template> <template>
<div> <div>
<component :is="menus" :selected="selected" @setSelected="setSelected" /> <component :is="menus" :selected="selected" />
<station-diagram ref="stationDiagram" /> <station-diagram ref="stationDiagram" @setSelected="setSelected" />
</div> </div>
</template> </template>

View File

@ -0,0 +1,176 @@
<template>
<div id="pop_tip_dialog" class="pop-dialog" :style="{ height: 'auto', left: tPosition.x+'px', top: tPosition.y+'px' }">
<div ref="tipRef" class="pop-content" :style="{ width: width + 'px',textAlign: textAlign }">
<p style="color: black;" v-html="tip" />
<div v-show="tPosition.align === 'top'" x-arrow class="popper__arraw_top" :style="{left: arrawLeft+'px'}" />
<div v-show="tPosition.align === 'bottom'" x-arrow class=" popper__arraw_bottom" :style="{left: arrawLeft+'px'}" />
</div>
</div>
</template>
<script>
export default {
name: 'PopTip',
props: {
position: {
type: Object,
required: true,
default: function () {
return {
x: 0,
y: 0
};
}
},
tip: {
type: String,
required: true
}
},
data() {
return {
defaultFontSize: 14,
maxWidth: 300,
tPosition: {
x: -300,
y: -300,
align: 'bottom'
},
offset: 7,
textAlign: 'center'
};
},
computed: {
width() {
let width = this.tip.length * this.defaultFontSize + 40;
if (width > this.maxWidth) {
width = this.maxWidth;
}
let parentWidth = 0;
if (this.position.fontNumber) {
parentWidth = this.position.fontNumber * this.defaultFontSize + 40;
}
return parentWidth || width;
},
arrawLeft() {
return this.width / 5;
}
},
watch: {
'position.x': function (val) {
this.resetShowPosition();
},
'position.y': function (val) {
this.resetShowPosition();
},
'tip': function (val) {
this.resetShowPosition();
}
},
mounted() {
this.resetShowPosition();
},
methods: {
resetShowPosition() {
this.$nextTick(() => {
//
const height = this.$el.clientHeight;
this.tPosition.align = this.position.align || 'bottom';
this.tPosition.x = this.position.x - (this.arrawLeft + this.offset);
this.textAlign = this.position.textAlign || 'center';
if (this.tPosition.align == 'top') {
const distance = 47;
this.tPosition.y = this.position.y + (distance);
} else if (this.tPosition.align == 'bottom') {
const distance = 5;
this.tPosition.y = this.position.y - (height + distance);
}
if (this.tPosition.x < 0) this.tPosition.x = 0;
if (this.tPosition.y < 0) this.tPosition.y = 0;
});
},
reset() {
this.tPosition = {
x: -300,
y: -300
};
}
}
};
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
$bg: #FFDD00;
$hoverBg: #f5f7fa;
.pop-dialog {
background-color: $bg;
border-radius: 6px;
position: fixed;
padding: 7px 0px;
z-index: 9998;
.pop-content {
.popper__arraw_bottom {
position: absolute;
height: 14px;
width: 14px;
background: $bg;
-moz-transform: rotate(45deg);
-webkit-transform: rotate(45deg);
-o-transform: rotate(45deg);
transform: rotate(45deg);
}
.popper__arraw_top {
position: absolute;
height: 14px;
width: 14px;
top: -7px;
background: $bg;
-moz-transform: rotate(45deg);
-webkit-transform: rotate(45deg);
-o-transform: rotate(45deg);
transform: rotate(45deg);
}
.popper__arraw_left {
position: absolute;
height: 14px;
width: 14px;
left: -7px;
background: $bg;
-moz-transform: rotate(45deg);
-webkit-transform: rotate(45deg);
-o-transform: rotate(45deg);
transform: rotate(45deg);
}
.popper__arraw_right {
position: absolute;
height: 14px;
width: 14px;
right: -7px;
background: $bg;
-moz-transform: rotate(45deg);
-webkit-transform: rotate(45deg);
-o-transform: rotate(45deg);
transform: rotate(45deg);
}
}
.dsp-block {
display: block;
text-align: left;
padding: 6px 15px;
width: 100%;
border-radius: unset;
}
.dsp-block:hover {
background-color: $hoverBg;
}
}
</style>

View File

@ -0,0 +1,101 @@
<template>
<el-dialog
title="角色扮演"
:visible.sync="dialogVisible"
width="30%"
append-to-body
:before-close="doClose"
center
>
<template v-for="user in userList">
<div :key="user.id" style="display: flex;justify-content: space-between;">
<div>{{ user.nickName }}</div>
<el-select v-model="user.memberId" size="mini" placeholder="请选择">
<el-option
v-for="item in roleList"
:key="item.id"
:label="item.label"
:value="item.id"
/>
</el-select>
</div>
</template>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="commit"> </el-button>
</span>
</el-dialog>
</template>
<script>
import {covertMemberData} from '@/views/newMap/displayNew/utils';
import { assignUsersPlayRoles } from '@/api/jointSimulation';
export default {
name: 'ScenePlayRole',
data() {
return {
dialogVisible: false,
userList: [],
roleList: []
};
},
computed: {
trainingDetail() {
return this.$store.state.trainingNew.trainingDetail;
}
},
watch: {
'$store.state.training.simulationUserList': function(val) {
this.userList = [];
this.$store.state.training.simulationUserList.forEach(user => {
this.userList.push({id: user.userId, nickName: user.nickName, memberId: ''});
});
}
},
mounted() {
if (this.$store.state.training.simulationUserList && this.$store.state.training.simulationUserList.length) {
this.userList = [];
this.$store.state.training.simulationUserList.forEach(user => {
this.userList.push({id: user.userId, nickName: user.nickName, memberId: ''});
});
}
},
methods: {
doClose() {
this.dialogVisible = false;
},
doShow() {
const playerList = JSON.parse(this.trainingDetail.playerIdJson);
const memberData = this.$store.state.training.memberData;
const activeTrainList = this.$store.state.map.activeTrainList || [];
const newMemberData = {};
playerList.forEach(playerId => {
newMemberData[playerId] = memberData[playerId];
});
const result = covertMemberData(activeTrainList, Object.values(newMemberData));
let list = [];
result.deviceListData.forEach(item => {
list = list.concat(item);
});
this.roleList = list;
this.dialogVisible = true;
},
commit() {
const list = [];
this.userList.forEach(user => {
list.push({userId: user.id, memberId: user.memberId});
});
assignUsersPlayRoles(list, this.$route.query.group).then(resp => {
this.$emit('startTraining');
this.doClose();
}).catch(() => {
this.$message.error('扮演角色失败!');
});
}
}
};
</script>
<style scoped>
</style>

View File

@ -0,0 +1,308 @@
<template>
<!-- v-drag 拖拽 调整宽高 -->
<div v-quickMenuDrag class="reminder-drag" :style="{bottom: offsetBottom + 'px'}">
<div ref="drapBox" class="reminder-box">
<div class="tip-title">
<div>
<i v-show="isShrink" class="icon el-icon-minus" @click="shrink" />
<i v-show="!isShrink" class="icon el-icon-plus" @click="shrink" />
<i v-show="!isShrink && !trainingSwitch && trainingDetail" class="icon el-icon-video-play" @click="handlerStart" />
<i v-show="!isShrink && trainingSwitch" class="icon el-icon-switch-button" @click="handlerEnd" />
</div>
<p style="color: #fff;">
<span>{{ trainingDetail.name }}</span>
</p>
</div>
<div v-if="isShrink" class="reminder-box-content">
<div class="zhezhao" />
<div ref="dragBody" class="tip-body-box">
<div class="tip-body">
<el-scrollbar wrap-class="scrollbar-wrapper">
<p class="list-item">
<span class="list-label">{{ $t('display.training.trainingName') }}</span>
<span class="list-elem">{{ trainingDetail.name }}</span>
</p>
<p v-if="demoMode === TrainingMode.TEST" class="list-item">
<span class="list-label">{{ $t('display.lesson.score') }}</span>
<span class="list-elem">{{ trainingScore }}</span>
</p>
<p class="list-item">
<span class="list-label">实训模式</span>
<span class="list-elem">
<el-radio-group v-model="demoMode" :disabled="trainingSwitch" class="mode" size="small" @change="changeMode">
<el-radio :label="TrainingMode.TEACH" border>{{ $t('display.lesson.teachingMode') }}</el-radio>
<el-radio :label="TrainingMode.PRACTICE" border>{{ $t('display.lesson.practiceMode') }}</el-radio>
<el-radio :label="TrainingMode.TEST" border>{{ $t('display.lesson.testMode') }}</el-radio>
</el-radio-group>
</span>
</p>
<p class="list-item">
<span class="list-label" style="vertical-align: top;"> {{ $t('display.training.trainingInstructions') }}</span>
<span class="list-elem elem-span">{{ trainingDetail.description }}</span>
</p>
<p class="list-item">
<span class="list-label">操作按钮</span>
<span class="list-elem">
<el-button v-if="!trainingSwitch && trainingDetail" size="small" type="success" @click="handlerStart">开始</el-button>
<el-button v-if="trainingSwitch" size="small" type="danger" @click="handlerEnd">结束</el-button>
</span>
</p>
</el-scrollbar>
</div>
<div class="drag-right" />
<div class="drag-left" />
<div class="drag-bottom" />
<div class="drag-top" />
</div>
</div>
</div>
<scene-play-role ref="scenePlayRole" @startTraining="startTraining" />
</div>
</template>
<script>
import { ScriptMode } from '@/scripts/ConstDic';
import { clearSimulation } from '@/api/simulation';
import { startTraining, endTraining } from '@/api/jmap/training';
import ScenePlayRole from './scenePlayRole';
export default {
name: 'TipTrainingDetail',
components: {
ScenePlayRole
},
props: {
offsetBottom: {
type: Number,
required: true
}
},
data() {
return {
isShrink: true,
showSumbit: false,
demoMode: ScriptMode.TEACH,
TrainingMode: ScriptMode
};
},
computed: {
trainingSwitch() {
return this.$store.state.trainingNew.trainingSwitch;
},
trainingScore() {
return this.$store.state.trainingNew.trainingScore;
},
trainingDetail() {
return this.$store.state.trainingNew.trainingDetail;
},
group() {
return this.$route.query.group;
},
teachMode() {
return this.$store.state.trainingNew.teachMode;
}
},
watch: {},
mounted() {
this.loadInitData();
},
methods: {
loadInitData() {
this.showSumbit = false;
},
shrink() {
if (this.isShrink) {
this.isShrink = false;
} else {
this.isShrink = true;
this.$nextTick(()=>{
const dragDom = document.querySelector('.reminder-drag').style.bottom;
if (document.body.clientHeight - 300 - parseInt(dragDom.replace('px', '')) < 0) {
document.querySelector('.reminder-drag').style.bottom = `${document.body.clientHeight - 300}px`;
}
});
}
},
changeMode(val) {
this.demoMode = val;
this.$store.dispatch('trainingNew/changeTeachMode', this.demoMode);
},
handlerStart() {
if (this.trainingDetail.type === 'SCENE') {
this.$refs.scenePlayRole.doShow();
} else {
this.startTraining();
}
},
startTraining() {
this.$store.dispatch('trainingNew/changeTeachMode', this.demoMode);
startTraining(this.group, {mode: this.demoMode}).then(() => {
this.$store.dispatch('trainingNew/trainingStart');
this.$store.dispatch('trainingNew/setTrainingScore', '');
}).catch(() => {
this.$message.error('开始实训失败!');
});
},
handlerEnd() {
endTraining(this.group).then((resp) => {
this.$store.dispatch('trainingNew/trainingEnd');
this.$store.dispatch('socket/clearTrainingStepTip');
this.$store.dispatch('trainingNew/clearStepOrder');
this.$store.dispatch('trainingNew/clearOperateOrder');
this.$store.dispatch('trainingNew/setTrainingScore', resp.data);
}).catch(() => {
this.$message.error('结束实训失败!');
});
},
back() {
if (this.group) {
clearSimulation(this.group);
}
}
}
};
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
@import "src/styles/mixin.scss";
.tip-body-box {
height: 260px;
position: absolute;
left: 0;
top: 0;
width: 100%;
}
.reminder-drag{
position: absolute;
bottom: 0px;
left: 15px;
z-index: 10;
}
.elem-span{
display:inline-block;width:77%;line-height:26px;margin-top:-4px;
}
.zhezhao{
width: 100%;
height: 100%;
filter: blur(8px);
background: rgba(255,255,255,0.9);
position:absolute;
}
.reminder-box-content{
width: 500px;
height: 260px;
left: 0;
top: 0;
z-index: 2;
background: rgba(255,255,255,0.8);
position: relative;
}
.reminder-box {
border-radius: 5px;
overflow: hidden;
z-index: 10;
font-size: 18px;
.tip-title {
width: 500px;
overflow: hidden;
height: 40px;
display: flex;
align-items: center;
flex-direction: row-reverse;
background-color: rgba(64, 158, 255,1);
border-radius: 5px 5px 0 0;
justify-content: space-between;
padding: 0 10px;
}
.drag-right,
.drag-left {
width: 10px;
cursor: e-resize;
background-color: yellow;
height: 100%;
position: absolute;
right: 0;
top: 0;
opacity: 0;
}
.drag-left {
left: 0;
}
.drag-bottom {
position: absolute;
bottom: 0;
width: 100%;
height: 10px;
cursor: s-resize;
background-color: yellow;
opacity: 0;
}
.drag-top {
position: absolute;
top: -45px;
left: 0;
width: 100%;
height: 10px;
cursor: s-resize;
background-color: yellow;
opacity: 0;
}
.tip-body {
height: 260px;
padding: 10px;
.list-label {
width: 105px;
}
}
.tip-foot {
width: 100%;
position: absolute;
right: 0px;
bottom: 0px;
background-color: #fff;
padding: 10px 0 10px 10px;
.foot-detail {
height: 100%;
float: right;
margin-top: 9px;
padding-right: 15px;
}
.foot-submit {
float: right;
margin-top: 9px;
padding-right: 15px;
}
}
.icon {
float: right;
margin-right: 10px;
cursor: pointer;
background-color: #f3f3f3;
border-radius: 50%;
}
/deep/ {
.el-tree-node__content {
margin-bottom: 4px;
}
.el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content {
background-color: #d6e5f7;
}
}
}
</style>

View File

@ -0,0 +1,198 @@
<template>
<div v-if="tipShow">
<pop-tip v-show="popShow" :position="position" :tip="tip" />
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import PopTip from './poptip';
import OperationHandler from '@/scripts/cmdPlugin/OperationHandler';
import { getDomOffset } from '@/utils/index';
import { ScriptMode } from '@/scripts/ConstDic';
export default {
name: 'TrainingTips',
components: { PopTip },
data() {
return {
tipShow: false,
popShow: false,
position: {
x: 0,
y: 0
},
tip: ''
};
},
computed: {
...mapGetters([
'canvasWidth',
'canvasHeight'
]),
trainingDetail() {
return this.$store.state.trainingNew.trainingDetail;
},
teachMode() {
return this.$store.state.trainingNew.teachMode;
}
},
watch: {
'$store.state.socket.trainingStepTip': function(val) {
if (val && this.trainingDetail.type === 'SINGLE') {
const member = this.$store.state.training.memberData[val.memberId];
this.$nextTick(function() {
this.$store.dispatch('trainingNew/clearOperateOrder');
this.$store.dispatch('trainingNew/stepOrderIncrease');
if (member.userId == this.$store.state.user.id) {
this.tipInit();
}
});
}
},
'$store.state.socket.trainingOverCount': function(val) {
this.tip = '';
this.popShow = false;
this.tipShow = false;
this.position = { x: 0, y: 0 };
},
'$store.state.trainingNew.trainingSwitch': function(val) {
this.tip = '';
this.popShow = false;
this.tipShow = false;
this.position = { x: 0, y: 0 };
}
},
methods: {
tipInit() {
if (this.teachMode === ScriptMode.TEACH) {
this.tipShow = true;
const offset = this.$store.state.config.canvasOffset;
const trainingDetail = this.$store.state.trainingNew.trainingDetail;
const stepOrder = this.$store.state.trainingNew.stepOrder;
const steps = JSON.parse(trainingDetail.stepJson);
if (steps && steps.length) {
const step = steps[stepOrder - 1];
const distance = 5;
this.tip = this.$store.state.socket.trainingStepTip.content;
if (step && step.tipPosition && step.tipPosition.deviceCode) {
const position = this.getShapeTipPoint(step.tipPosition);
if (position) {
this.position = {
x: position.x + offset.x,
y: position.y + offset.y - distance
};
this.popTipShow();
}
} else if (step && step.tipPosition && step.tipPosition.domId) {
const position = this.getOtherTipPoint(step.tipPosition);
if (position) {
this.position = position;
this.position.y -= distance;
this.popTipShow();
}
} else {
this.popTipHide();
}
} else {
this.tipShow = false;
}
} else {
this.tipShow = false;
}
},
popTipShow() {
this.popShow = true;
},
popTipHide() {
this.popShow = false;
},
//
getShapeTipPoint(tipPosition) {
var position = null;
//
const newTipPosition = Object.assign({}, tipPosition);
if (newTipPosition.deviceCode.includes('Cycle')) {
const buttonList = this.$store.state.map.map.cycleButtonList;
if (buttonList && buttonList.length > 0) {
buttonList.forEach(element => {
if (element.cycleCode == newTipPosition.code) {
newTipPosition.deviceCode = element.code;
}
});
}
}
let subDeviceType = '';
if (newTipPosition.subType) { subDeviceType = newTipPosition.subType; } else { subDeviceType = newTipPosition.type; }
position = this.$jlmap.getShapeTipPoint({
code: newTipPosition.deviceCode,
subDeviceType: subDeviceType
});
if (position) {
if (position.x < 0) {
position.x = 0;
}
if (position.x > this.canvasWidth) {
position.x = this.canvasWidth;
}
if (position.y < 0) {
position.y = 0;
}
if (position.y > this.canvasHeight) {
position.y = this.canvasHeight;
}
}
return position;
},
//
getOtherTipPoint(tipPosition) {
const domId = OperationHandler.getDomIdByOperation(tipPosition.domId);
const btnDom = document.getElementById(domId);
if (btnDom) {
const offset = getDomOffset(btnDom);
if (offset.x == 0 && offset.y == 0) {
return null;
}
let align = 'bottom';
if (this.tipAlignIsTop(tipPosition, domId)) {
align = 'top';
}
return {
align: align,
x: offset.x + btnDom.clientWidth / 2,
y: offset.y
};
}
return null;
},
tipAlignIsTop(step, domId) {
// tip
// if (step.type.toUpperCase() === 'bar'.toUpperCase()) {
// return true;
// }
const Dom = document.getElementById(domId);
if (Dom.parentElement.id == 'menuButtons_box') { //
return false;
}
if (/{TOP}/.test(domId)) {
return true;
}
if (/{BOTTOM}/.test(domId)) {
return false;
}
// domId
const keyList = ['choose', 'select'];
for (var key in keyList) {
if (domId.toUpperCase().indexOf(keyList[key].toUpperCase()) !== -1) {
return false;
}
}
//
return true;
}
}
};
</script>

View File

@ -0,0 +1,84 @@
<template>
<div v-if="trainingTipMessage!=''" class="trainingTipMessage" :style="{top:offset + 55 +'px'}">{{ trainingTipMessage }}</div>
</template>
<script>
import { ScriptMode } from '@/scripts/ConstDic';
export default {
name: 'TrainingTip',
data() {
return {
offset: 0,
trainingTipMessage: ''
};
},
computed: {
teachMode() {
return this.$store.state.trainingNew.teachMode;
},
trainingDetail() {
return this.$store.state.trainingNew.trainingDetail;
}
},
watch: {
'$store.state.socket.trainingStepTip': function(val) {
if (val && this.trainingDetail.type === 'SCENE') {
const member = this.$store.state.training.memberData[val.memberId];
this.$nextTick(function() {
this.$store.dispatch('trainingNew/clearOperateOrder');
this.$store.dispatch('trainingNew/stepOrderIncrease');
if (member.userId == this.$store.state.user.id && (this.teachMode === ScriptMode.TEACH || this.teachMode === ScriptMode.PRACTICE)) {
this.trainingTipMessage = val.content;
}
});
}
},
'$store.state.trainingNew.trainingSwitch': function(val) {
if (!val) {
this.trainingTipMessage = '';
}
},
'$store.state.socket.trainingStepFinishCount': function(val) {
this.trainingTipMessage = '';
},
'$store.state.socket.trainingOverCount': function(val) {
if (this.teachMode === ScriptMode.TEACH) {
this.trainingTipMessage = '实训完成,请点击结束按钮。';
}
},
'$store.state.training.operateErrMsg': function (val) {
this.tipInfo({ color: val.color, message: val.errMsg });
}
},
methods: {
tipInfo(opt) {
if (opt && opt.hasOwnProperty('color') && opt.hasOwnProperty('message')) {
const h = this.$createElement;
this.$notify({
title: this.$t('global.tips'),
message: h('i', { style: 'color:' + opt.color }, opt.message)
});
}
}
}
};
</script>
<style lang="scss" scoped>
.trainingTipMessage{
position: absolute;
width: 400px;
padding: 15px;
background: rgb(255, 221, 0);
left: 50%;
border-radius: 8px;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
color: #000;
line-height: 180%;
// z-index: 1501;
z-index: 35;
font-size: 14px;
}
</style>

View File

@ -13,10 +13,10 @@
<i class="el-icon-user" /> <i class="el-icon-user" />
<span class="teachMenuTitle" :style="{color: $route.path.includes('studentManage')?'#5BDBFF': '#000'}">学生管理</span> <span class="teachMenuTitle" :style="{color: $route.path.includes('studentManage')?'#5BDBFF': '#000'}">学生管理</span>
</el-menu-item> </el-menu-item>
<el-menu-item index="6" @click="clickMenu"> <!-- <el-menu-item index="6" @click="clickMenu">
<img :src="ruleIcon" class="teachMenu"> <img :src="ruleIcon" class="teachMenu">
<span class="teachMenuTitle" :style="{color: $route.path.includes('trainingDesign')?'#5BDBFF': '#000'}">实训设计</span> <span class="teachMenuTitle" :style="{color: $route.path.includes('trainingDesign')?'#5BDBFF': '#000'}">实训设计</span>
</el-menu-item> </el-menu-item> -->
<el-menu-item index="7" @click="clickMenu"> <el-menu-item index="7" @click="clickMenu">
<img :src="ruleIcon" class="teachMenu"> <img :src="ruleIcon" class="teachMenu">
<span class="teachMenuTitle" :style="{color: $route.path.includes('trainingManage')?'#5BDBFF': '#000'}">实训管理</span> <span class="teachMenuTitle" :style="{color: $route.path.includes('trainingManage')?'#5BDBFF': '#000'}">实训管理</span>
@ -98,9 +98,11 @@ export default {
this.$router.replace('/teaching/organization/ruleManage'); this.$router.replace('/teaching/organization/ruleManage');
} else if (val.index === '5') { } else if (val.index === '5') {
this.$router.replace('/teaching/organization/studentManage'); this.$router.replace('/teaching/organization/studentManage');
} else if (val.index === '6') { }
this.$router.push('/teaching/organization/trainingDesign'); // // else if (val.index === '6') {
} else if (val.index === '7') { // this.$router.push('/teaching/organization/trainingDesign'); //
// }
else if (val.index === '7') {
this.$router.replace('/teaching/organization/trainingManage'); // this.$router.replace('/teaching/organization/trainingManage'); //
} else if (val.index === '8') { } else if (val.index === '8') {
this.$router.replace('/teaching/organization/theoryManage'); this.$router.replace('/teaching/organization/theoryManage');

View File

@ -1,5 +1,219 @@
<template> <template>
<div style="width: 100%;height: 100%;"> <div style="width: 100%;height: 100%;">
{{}} <QueryListPage v-if="showList" ref="queryListPage" :card-padding="10" :pager-config="pagerConfig" :query-form="queryForm" :query-list="queryList" />
</div> </div>
</template> </template>
<script>
import {queryMapListByUser} from '@/api/jmap/map';
import Cookies from 'js-cookie';
import ConstConfig from '@/scripts/ConstConfig';
// import { getPublishSingleList, getPublishScenesList } from '@/api/jmap/training';
import { deleteTraining } from '@/api/trainingManage';
import { getTrainingList } from '@/api/trainingManage';
// getPublishTrainingDetail, loadPublishTraining,
export default {
name:'TrainingManage',
data() {
return {
mapList:[],
showList: false,
pagerConfig: {
pageSize: 'pageSize',
pageIndex: 'pageNum'
},
queryForm: {
labelWidth: '100px',
reset: false,
initLoadCallback: this.initLoadCallback,
queryObject: {
mapId: {
type: 'select',
label: '地图名称',
config: {
noClear:true,
data: []
}
}
}
},
queryList:{
height: 500,
query: this.queryFunction,
selectCheckShow: false,
indexShow: true,
columns: [
{
title: this.$t('trainingManage.name'),
prop: 'name'
},
{
title: this.$t('trainingManage.description'),
prop: 'description'
},
{
title: this.$t('trainingManage.type'),
width: '70',
prop: 'type',
type: 'tag',
columnValue: (row) => { return this.covertData(row); },
tagType: (row) => { return ''; }
},
{
title: this.$t('trainingManage.labelJson'),
width: '200',
prop: 'labelJson',
type: 'tagMore',
columnValue: (row) => { return this.labelJsonData(row); },
tagType: (row) => { return ''; }
},
{
type: 'button',
title: this.$t('trainingManage.operate'),
width: '500',
buttons: [
{
name: this.$t('trainingManage.record'),
handleClick: this.drawUp,
type: 'success',
showControl:(row) => { return row.id; }
},
{
name: this.$t('trainingManage.modify'),
handleClick: this.handleModify,
type: 'primary',
showControl:(row) => { return row.id; }
},
{
name: this.$t('trainingManage.delete'),
handleClick: this.deleteScript,
type: 'danger',
showControl:(row) => { return row.id; }
},
{
name: this.$t('trainingManage.publish'),
handleClick: this.publishScript,
type: 'primary',
showControl:(row) => { return row.id; }
},
{
name: this.$t('trainingManage.preview'),
handleClick: this.previewScript,
type: 'primary',
showControl:(row) => { return row.id; }
},
{
name: this.$t('trainingManage.gradeRules'),
handleClick: this.gradeRules,
type: 'success',
showControl:(row) => { return row.id; }
},
{
name: this.$t('trainingManage.publishTrack'),
handleClick: this.publishTrack,
type: 'primary',
showControl:(row) => { return row.id; }
}
]
}
]
}
};
},
created() {
queryMapListByUser().then(res=>{
this.mapList = [];
res.data.forEach(element => {
this.mapList.push({label:element.name, value:element.id});
});
this.queryForm.queryObject.mapId.config.data = [...this.mapList];
this.queryForm.queryObject.mapId.config.default = this.mapList[0].value;
this.showList = true;
});
},
methods: {
initLoadCallback(form) {
if (!form.trainingType) {
form.trainingType = 'training';
}
if (!form.mapId) {
form.mapId = this.mapList[0] ? this.mapList[0].value : '';
}
},
queryFunction(param) {
if (param.mapId) {
return getTrainingList(param);
} else {
return new Promise((resolve, reject)=>{
const result = {data:{list:[], total:0, pageNum:0}};
resolve(result);
});
}
},
covertData(row) {
const releaseReview = ConstConfig.ConstSelect.trainingType;
const lastData = Object.assign({}, row);
if (Cookies.get('user_lang') == 'en') {
releaseReview.forEach(function(element) {
const rolename = element.value;
if (lastData.type == rolename) {
lastData.type = element.enlabel;
}
});
} else {
releaseReview.forEach(function(element) {
const rolename = element.value;
if (lastData.type == rolename) {
lastData.type = element.label;
}
});
}
return lastData.type;
},
labelJsonData(row) {
const sList = row.labelJson ? JSON.parse(row.labelJson) : [];
const list = Object.prototype.toString.call(sList) === '[object Array]' ? sList : [sList];
return list;
},
drawUp(index, row) {
},
deleteScript(index, row) {
console.log('删除', index, row);
this.$confirm('确定删除该条实训数据?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
if (!row.id) { return; }
deleteTraining([row.id]).then(res => {
console.log('删除实训成功', res);
this.getListData();
}).catch(err => {
console.log('删除实训失败', err);
this.getListData();
});
}).catch(e => {});
},
handleModify(index, row) {
// console.log('', index, row);
// if (!row.id) { return; }
// this.$refs.create.doShow(row);
},
loadScript(index, data) {
},
publishScript(index, row) {
},
previewScript(index, row) {
},
gradeRules(index, row) {
},
publishTrack(index, row) {
}
}
};
</script>

View File

@ -1,32 +1,37 @@
<template> <template>
<div style="width: 100%;height: 100%;"> <div style="width: 100%;height: 100%;">
<QueryListPage ref="queryListPage" :card-padding="10" :pager-config="pagerConfig" :query-form="queryForm" :query-list="queryList" /> <QueryListPage v-if="showList" ref="queryListPage" :card-padding="10" :pager-config="pagerConfig" :query-form="queryForm" :query-list="queryList" />
</div> </div>
</template> </template>
<script> <script>
import {queryMapListByUser} from '@/api/jmap/map'; import {queryMapListByUser, getPublishMapDetailById} from '@/api/jmap/map';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import { createSimulation } from '@/api/simulation';
import ConstConfig from '@/scripts/ConstConfig'; import ConstConfig from '@/scripts/ConstConfig';
import { getPublishSingleList, getPublishScenesList } from '@/api/jmap/training'; import { getSessionStorage } from '@/utils/auth';
// getPublishTrainingDetail, loadPublishTraining, import { launchFullscreen } from '@/utils/screen';
import { getPublishSingleList, getPublishScenesList} from '@/api/jmap/training';
export default { export default {
name:'TrainingManage', name:'TrainingManage',
data() { data() {
return { return {
loadingProjectList: ['login', 'design', 'xty', 'designxty', 'gzb', 'designxty', 'xadt', 'designxadt', 'drts', 'designdrts', 'hlsdrts', 'designhlsdrts', 'teaching', 'designteaching'],
mapList:[], mapList:[],
showList: false,
pagerConfig: { pagerConfig: {
pageSize: 'pageSize', pageSize: 'pageSize',
pageIndex: 'pageNum' pageIndex: 'pageNum'
}, },
queryForm: { queryForm: {
labelWidth: '100px', labelWidth: '100px',
reset: true, reset: false,
initLoadCallback: this.initLoadCallback, initLoadCallback: this.initLoadCallback,
queryObject: { queryObject: {
mapId: { mapId: {
type: 'select', type: 'select',
label: '地图名称', label: '地图名称',
config: { config: {
default: '',
noClear:true, noClear:true,
data: [] data: []
} }
@ -35,6 +40,7 @@ export default {
type: 'select', type: 'select',
label: '实训类型', label: '实训类型',
config: { config: {
default: '',
noClear:true, noClear:true,
data: [ data: [
{label: '单操实训', value: 'training'}, {label: '单操实训', value: 'training'},
@ -87,6 +93,11 @@ export default {
} }
}; };
}, },
computed: {
project() {
return getSessionStorage('project');
}
},
created() { created() {
queryMapListByUser().then(res=>{ queryMapListByUser().then(res=>{
this.mapList = []; this.mapList = [];
@ -94,7 +105,8 @@ export default {
this.mapList.push({label:element.name, value:element.id}); this.mapList.push({label:element.name, value:element.id});
}); });
this.queryForm.queryObject.mapId.config.data = [...this.mapList]; this.queryForm.queryObject.mapId.config.data = [...this.mapList];
// this.queryForm.queryObject.mapId.config.default = this.mapList[0].value; this.queryForm.queryObject.mapId.config.default = this.mapList[0].value;
this.showList = true;
}); });
}, },
methods: { methods: {
@ -102,9 +114,9 @@ export default {
if (!form.trainingType) { if (!form.trainingType) {
form.trainingType = 'training'; form.trainingType = 'training';
} }
// if (!form.mapId) { if (!form.mapId) {
// form.mapId = this.mapList[0].value; form.mapId = this.mapList[0] ? this.mapList[0].value : '';
// } }
}, },
queryFunction(param) { queryFunction(param) {
if (param.mapId) { if (param.mapId) {
@ -140,8 +152,39 @@ export default {
} }
return lastData.type; return lastData.type;
}, },
loadScript(index, data) { loadScript(index, row) {
// mapSystem terminal
// row.mapSystem
let memberId = '1';
if (row.playerIdJson) {
memberId = JSON.parse(row.playerIdJson)[0];
}
const data = {mapId: row.mapId, type:row.mapSystem || 'METRO', memberId: memberId};
// domConfig: Object
// hasExam: false
// hasTraining: false
// singleClient: false
// singleMember: true
getPublishMapDetailById(row.mapId).then(res=>{
const lindeCode = res.data.lineCode;
createSimulation(data).then(resp => {
const query = { lineCode:lindeCode, group: resp.data, mapId: row.mapId, project: this.project, trainingId:row.id};
if (this.loadingProjectList.includes(this.project)) {
this.$store.dispatch('app/transitionAnimations');
}
this.$router.push({ path: `/display/demon`, query: query });
launchFullscreen();
}).catch(error=>{
if (error.code == 10003) {
this.$messageBox(this.$t('error.createSimulationFailed') + ':您的仿真权限不足!');
} else {
this.$messageBox(this.$t('error.createSimulationFailed') + error.message);
}
this.disabled = false;
});
}).catch(()=>{
console.log('获取地图详情失败');
});
} }
} }
}; };

View File

@ -105,7 +105,7 @@ export default {
}).catch((err) => { }).catch((err) => {
console.log('err', err); console.log('err', err);
this.loading = false; this.loading = false;
this.$message.error(`${this.isEdit ? '编辑' : '新建'}失败!`); this.$message.error(`${this.isEdit ? '编辑' : '新建'}失败!${err.message}`);
}); });
}); });
} }

View File

@ -32,9 +32,14 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="分类" prop="tags"> <el-form-item label="分类" required>
<el-select multiple v-model="form.tags" @change="getQuestionAmount"> <el-select v-model="form.tags" @change="getQuestionAmount">
<el-option v-for="label in labels" :key="label" :label="label" :value="label"></el-option> <el-option
v-for="item in labels"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="题目数量" prop="amount"> <el-form-item label="题目数量" prop="amount">
@ -44,8 +49,7 @@
style="width: calc(100% - 280px); float: left; margin-right: 10px;" style="width: calc(100% - 280px); float: left; margin-right: 10px;"
/> />
<span v-if="this.form.type === 1" style="width: 190px; float: left;"> <span v-if="this.form.type === 1" style="width: 190px; float: left;">
{{ $t('publish.allNumberTipOne') }} {{ topicNum }} {{ $t('publish.allNumberTipTwo') }}, 剩余 {{ $t('publish.allNumberTipOne') }} {{ topicNum }} {{ $t('publish.allNumberTipTwo') }}
{{ remainNum }}
</span> </span>
</el-form-item> </el-form-item>
<el-form-item :label="$t('publish.scorePerQuestion')" prop="score"> <el-form-item :label="$t('publish.scorePerQuestion')" prop="score">
@ -94,7 +98,7 @@ export default {
message(new Error(this.$t('publish.inputQuestionNumberError'))) message(new Error(this.$t('publish.inputQuestionNumberError')))
} else if (!Number(value)) { } else if (!Number(value)) {
message(new Error(this.$t('publish.inputValidNumber'))) message(new Error(this.$t('publish.inputValidNumber')))
} else if (Number(value) > this.remainNum && this.form.type === 1) { } else if (Number(value) > this.topicNum && this.form.type === 1) {
message(new Error(this.$t('publish.inputNumberError'))) message(new Error(this.$t('publish.inputNumberError')))
} else { } else {
message() message()
@ -108,18 +112,20 @@ export default {
message() message()
} }
} }
const tagsValidator = (rule, value, message) => {
message()
}
return { return {
form: { form: {
id: '', id: '',
type: '', type: '',
subtype: '', subtype: '',
tags: [], tags: '',
amount: 1, amount: 1,
score: 1, score: 1,
}, },
labels: [], labels: [],
topicNum: 0, topicNum: 0,
remainNum: 0,
index: -1, index: -1,
dialogShow: false, dialogShow: false,
rules: { rules: {
@ -127,12 +133,13 @@ export default {
subtype: [{ required: true, message: '请选择规则类型', trigger: 'change' }], subtype: [{ required: true, message: '请选择规则类型', trigger: 'change' }],
amount: [{ required: true, validator: number, trigger: 'blur' }], amount: [{ required: true, validator: number, trigger: 'blur' }],
score: [{ required: true, validator: score, trigger: 'blur' }], score: [{ required: true, validator: score, trigger: 'blur' }],
tags: [{ validator: tagsValidator, trigger: 'blur' }],
}, },
} }
}, },
created() { created() {
getLabelList().then(resp => { getLabelList().then(resp => {
this.labels = resp.data this.labels = [{ label: '无', value: '' }, ...resp.data.map(item => ({ label: item, value: item }))]
}) })
}, },
mounted() {}, mounted() {},
@ -150,13 +157,11 @@ export default {
amount: detail.amount, amount: detail.amount,
score: detail.score, score: detail.score,
id: detail.id || '', id: detail.id || '',
tags: detail.tags tags: detail.tags,
} }
this.topicNum = detail.topicNum this.topicNum = detail.topicNum
this.remainNum = detail.remainNum
} else { } else {
this.isEditMode = false this.isEditMode = false
this.remainNum = 0
} }
}) })
}, },
@ -167,56 +172,23 @@ export default {
rule => rule =>
rule.type === this.form.type && rule.type === this.form.type &&
rule.subtype === this.form.subtype && rule.subtype === this.form.subtype &&
rule.tags.length === this.form.tags.length && rule.tags &&
rule.tags.every(tag => this.form.tags.includes(tag)) this.form.tags &&
rule.tags.includes(this.form.tags)
) )
return isDuplicated return isDuplicated
}, },
getQuestionAmount(e) { getQuestionAmount(e) {
if (!(this.form.type && this.form.subtype)) return if (!(this.form.type && this.form.subtype)) return
if (this.form.type === 2) return // if (this.form.type === 2) return //
// if (this.isDuplicated()) {
// this.$message.warning(', ')
// return
// }
const param = { const param = {
orgId: this.$store.state.user.companyId, orgId: this.$store.state.user.companyId,
groupType: this.form.type, groupType: this.form.type,
subType: this.form.subtype, subType: this.form.subtype,
tags: this.form.tags,
} }
if (this.form.tags !== '') param.tags = [this.form.tags]
getQuestionAmount(param).then(resp => { getQuestionAmount(param).then(resp => {
const num = resp.data this.topicNum = resp.data
this.topicNum = num
const { type, subtype, tags } = this.form
if (this.ruleList.length > 0) {
const smallerRangeRules = this.ruleList.filter(
(rule, i) =>
rule.type === type &&
rule.subtype === subtype &&
rule.tags.length >= tags.length &&
(tags.every(tag => rule.tags.includes(tag)) || tags.length === 0) &&
(this.isEditMode ? this.index !== i : true) //
)
//()
const amount1 = smallerRangeRules.reduce((prev, curr) => prev + curr.amount, 0)
const largerRangeRules = this.ruleList.filter(
(rule, i) =>
rule.type === type &&
rule.subtype === subtype &&
rule.tags.length < tags.length &&
(rule.tags.every(tag => tags.includes(tag)) || rule.tags.length === 0) &&
(this.isEditMode ? this.index !== i : true)
)
//
const amount2 = largerRangeRules.reduce(
(prev, curr) => (curr.topicNum - curr.amount < prev ? curr.topicNum - curr.amount : prev),
num
)
this.remainNum = amount2 - amount1
} else {
this.remainNum = num
}
}) })
}, },
clearSubtype() { clearSubtype() {
@ -231,11 +203,7 @@ export default {
return return
} }
} }
this.$emit( this.$emit('submit', { ...this.form, topicNum: this.topicNum }, this.isEditMode)
'submit',
{ ...this.form, topicNum: this.topicNum, remainNum: this.remainNum },
this.isEditMode
)
this.handleCancel() this.handleCancel()
} }
}) })

View File

@ -1,6 +1,16 @@
<template> <template>
<div class="exam-rule"> <div class="exam-rule">
<el-form ref="form" :model="examData" :rules="rules" label-width="120px" class="demo-form"> <el-form ref="form" :model="examData" :rules="rules" label-width="120px" class="demo-form">
<el-form-item label="关联线路" prop="mapId" required>
<el-select v-model="examData.mapId">
<el-option
v-for="option in mapOptionList"
:key="option.value"
:label="option.label"
:value="option.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item :label="$t('publish.testName')" prop="name"> <el-form-item :label="$t('publish.testName')" prop="name">
<el-input v-model="examData.name" :maxlength="50" :placeholder="$t('publish.inputTestName')" /> <el-input v-model="examData.name" :maxlength="50" :placeholder="$t('publish.inputTestName')" />
</el-form-item> </el-form-item>
@ -54,17 +64,12 @@
<el-form-item :label="$t('publish.passingScore')" prop="passScore"> <el-form-item :label="$t('publish.passingScore')" prop="passScore">
<el-input-number v-model="examData.passScore" placeholder="" :min="1" /> <el-input-number v-model="examData.passScore" placeholder="" :min="1" />
</el-form-item> </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> </el-form>
</div> </div>
</template> </template>
<script> <script>
import { queryMapListByUser } from '@/api/jmap/map'
export default { export default {
name: 'ExamFrom', name: 'ExamFrom',
props: { props: {
@ -103,9 +108,10 @@ export default {
}, },
}, },
haveDate: false, haveDate: false,
options: [], mapOptionList: [],
selectDisable: false, selectDisable: false,
rules: { rules: {
mapId: [{ required: true, message: '请选择线路', trigger: 'blur' }],
name: [{ required: true, message: this.$t('publish.inputTestName'), trigger: 'blur' }], name: [{ required: true, message: this.$t('publish.inputTestName'), trigger: 'blur' }],
validDuration: [{ required: true, message: this.$t('publish.inputTestDuration'), trigger: 'blur' }], validDuration: [{ required: true, message: this.$t('publish.inputTestDuration'), trigger: 'blur' }],
fullScore: [{ required: true, message: this.$t('publish.inputFullScore'), trigger: 'blur' }], fullScore: [{ required: true, message: this.$t('publish.inputFullScore'), trigger: 'blur' }],
@ -122,7 +128,11 @@ export default {
return this.$route.params.mode === 'edit' return this.$route.params.mode === 'edit'
}, },
}, },
created() {}, created() {
queryMapListByUser().then(resp => {
this.mapOptionList = resp.data.map(item => ({ label: item.name, value: Number(item.id) }))
})
},
mounted() {}, mounted() {},
methods: { methods: {
checkForm() { checkForm() {

View File

@ -56,6 +56,7 @@ export default {
validDuration: 30, validDuration: 30,
fullScore: 100, fullScore: 100,
passScore: 60, passScore: 60,
mapId: '',
}, },
ruleList: [], ruleList: [],
} }
@ -78,6 +79,7 @@ export default {
if (this.isEditMode) { if (this.isEditMode) {
getPaperDetail(this.$route.params.paperId).then(res => { getPaperDetail(this.$route.params.paperId).then(res => {
this.examData = { this.examData = {
mapId: res.data.mapId,
name: res.data.name, name: res.data.name,
profile: res.data.profile, profile: res.data.profile,
startTime: res.data.startTime, startTime: res.data.startTime,

View File

@ -37,7 +37,12 @@
</el-table-column> </el-table-column>
<el-table-column label="分类"> <el-table-column label="分类">
<template slot-scope="scope"> <template slot-scope="scope">
<el-tag v-for="tag in scope.row.tags" :key="tag">{{ tag }}</el-tag> <template v-if="scope.row.tags">
<el-tag v-for="tag in scope.row.tags" :key="tag">{{ tag }}</el-tag>
</template>
<template v-else>
<el-tag></el-tag>
</template>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="$t('global.operate')" width="100"> <el-table-column :label="$t('global.operate')" width="100">
@ -92,7 +97,6 @@ export default {
return ['', '单选题', '多选题', '判断题', '单操实训', '场景实训'] return ['', '单选题', '多选题', '判断题', '单操实训', '场景实训']
}, },
}, },
watch: {},
created() {}, created() {},
methods: { methods: {
handleAdd() { handleAdd() {
@ -105,8 +109,7 @@ export default {
amount: formData.amount, amount: formData.amount,
score: formData.score, score: formData.score,
topicNum: formData.topicNum, topicNum: formData.topicNum,
remainNum: formData.remainNum, tags: [formData.tags],
tags: formData.tags,
} }
if (isEdit) { if (isEdit) {
this.$set(this.ruleList, this.editingIndex, data) this.$set(this.ruleList, this.editingIndex, data)

View File

@ -287,10 +287,10 @@ export default {
/deep/ .el-dialog__wrapper { /deep/ .el-dialog__wrapper {
width: 1px; width: 1px;
height: 1px; height: 1px;
top: auto; top: 0;
right: auto; right: 0;
bottom: auto; bottom: 0;
left: auto; left: 0;
overflow: visible !important; overflow: visible !important;
} }
// .conditionTab{ // .conditionTab{

View File

@ -397,10 +397,11 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.editContent { .editContent {
position: absolute; position: fixed;
right: 0; right: 0;
top: 0; top: 0;
height: 100%; bottom: 0;
// height: 100%;
width: 800px; width: 800px;
transform: translateX(800px); transform: translateX(800px);
transition: all 0.4s; transition: all 0.4s;
@ -410,20 +411,12 @@ export default {
transform: translateX(0px); transform: translateX(0px);
} }
} }
/deep/ .el-dialog__wrapper {
width: 1px;
height: 1px;
top: auto;
right: auto;
bottom: auto;
left: auto;
overflow: visible !important;
}
.editContentTab{ .editContentTab{
position: absolute; position: absolute;
z-index: 10; z-index: 10;
left: -12px; left: -12px;
top: calc(45% + 100px); // top: calc(45% + 200px);
top: 200px;
} }
.editContentTabLable{ .editContentTabLable{
position: absolute; position: absolute;
@ -435,7 +428,7 @@ export default {
left: 50%; left: 50%;
transform: translateX(-50%); transform: translateX(-50%);
cursor: pointer; cursor: pointer;
top:-28px; top: 0px;
} }
.tabPaneBox { .tabPaneBox {
padding: 0 20px; padding: 0 20px;

View File

@ -1,10 +1,10 @@
<template> <template>
<div> <div class="operate-main">
<div class="editContentTab"> <!-- <div class="editContentTab">
<div v-if="dialogVisible" class="editContentTabLable" @click="minisize"> <div v-if="dialogVisible" class="editContentTabLable" @click="minisize">
<span class="titleStyle">{{ $t('trainingManage.editTagTitle') }}</span> <span class="titleStyle">{{ $t('trainingManage.editTagTitle') }}</span>
</div> </div>
</div> </div> -->
<el-dialog :title="title" :visible.sync="dialogVisible" width="500" :modal="false" :close-on-click-modal="false" :show-close="false" center style="margin-left: 200px"> <el-dialog :title="title" :visible.sync="dialogVisible" width="500" :modal="false" :close-on-click-modal="false" :show-close="false" center style="margin-left: 200px">
<el-row style="font-size: 16px;padding: 5px;"> <el-row style="font-size: 16px;padding: 5px;">
<el-col :span="4">步骤描述</el-col> <el-col :span="4">步骤描述</el-col>
@ -147,35 +147,37 @@ export default {
}; };
</script> </script>
<style scoped> <style lang="scss" scoped>
/deep/ .el-dialog__wrapper { .operate-main {
width: 1px; /deep/ .el-dialog__wrapper {
height: 1px; width: 1px;
top: auto; height: 1px;
right: auto; top: 0;
bottom: auto; right: 0;
left: auto; bottom: 0;
overflow: visible !important; left: 0;
} overflow: visible !important;
/deep/ .el-dialog--center{ }
width: 600px; /deep/ .el-dialog--center{
} width: 600px;
.editContentTab{ }
position: absolute;
z-index: 10;
right: 12px;
top: calc(45% + 100px);
}
.editContentTabLable{
position: absolute;
background: #fff;
border-radius: 5px 0 0 5px ;
padding: 5px 0;
width: 23px;
text-align: center;
left: 50%;
transform: translateX(-50%);
cursor: pointer;
top:-28px;
} }
// .editContentTab{
// position: absolute;
// z-index: 10;
// right: 12px;
// top: calc(45% + 100px);
// }
// .editContentTabLable{
// position: absolute;
// background: #fff;
// border-radius: 5px 0 0 5px ;
// padding: 5px 0;
// width: 23px;
// text-align: center;
// left: 50%;
// transform: translateX(-50%);
// cursor: pointer;
// top:-28px;
// }
</style> </style>

View File

@ -0,0 +1,115 @@
<template>
<div class="main">
<TrainingList ref="trainingList" @updateDetails="updateDetails" @gradeRules="gradeRules" @closeAllDialog="closeAllDialog" @draftTracK="draftTracK" />
<EditDetails ref="editDetails" :edit-data="editData" @openEditOperate="openEditOperate" @handleCondition="handleCondition" @publish="publish" @preview="preview" @gradeRules="gradeRules" />
<EditCondition ref="editCondition" v-dialogDrag :materials-list="materialsList" @editConditionFn="editConditionFn" @backStep="backStep" />
<edit-operate ref="editOperate" v-dialogDrag @backStepList="backStepList" />
<grade-rules ref="gradeRules" />
<TrackList ref="trackList" />
</div>
</template>
<script>
import TrainingList from './trainingList.vue';
import TrackList from './trackList.vue';
import EditDetails from './editDetails.vue';
import EditCondition from './editCondition.vue';
import EditOperate from './editOperate.vue';
import GradeRules from './gradeRules.vue';
import { getTrainingMaterials } from '@/api/trainingManage';
export default {
name:'TrainingIndex',
components:{
TrainingList,
TrackList,
EditDetails,
EditCondition,
EditOperate,
GradeRules
},
props:{
},
data() {
return {
hoverBtn: false,
btnWidth: -600,
materialsList: [],
refsList: ['editDetails', 'editCondition', 'trackList'],
editData: {}
};
},
computed:{
group() {
return this.$route.query.group;
},
mapId() {
return this.$route.query.mapId;
},
lineCode() {
return this.$route.query.lineCode;
}
},
mounted() {
this.getMaterials();
},
methods:{
publish(data) {
this.$refs.trainingList.publishScript(null, data);
},
preview(data) {
this.$refs.trainingList.previewScript(null, data);
},
editConditionFn(data, index, key) {
this.$refs.editDetails.editConditionFn(data, index, key);
},
backStep() {
this.$refs.editDetails.backStep();
},
handleCondition(index, row, key) {
this.$refs.editCondition.doShow(row, index, key);
},
getMaterials() {
getTrainingMaterials().then(res => {
this.materialsList = res.data;
}).catch(err => {
console.log(err, 'Materials----');
this.materialsList = [];
});
},
draftTracK(row) {
this.$refs.trackList.doShow(row);
},
doShow() {
this.$refs.trainingList.doShow();
},
updateDetails(data) {
this.editData = data;
this.closeAllDialog('editDetails');
this.$refs.editDetails.doShow(data);
},
closeAllDialog(noCloseName) {
this.refsList.forEach(key => {
if (key != noCloseName && this.$refs[key]) {
this.$refs[key].doClose();
}
});
},
openEditOperate(data) {
this.$refs.editOperate.doShow(data);
},
backStepList(data) {
this.$refs.editDetails.setOperations(data);
this.$refs.editDetails.minisize();
},
gradeRules(data) {
this.$refs.gradeRules.doShow(data);
}
}
};
</script>
<style lang="scss" scoped>
.main {
position: relative;
z-index: 2001;
}
</style>

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog v-dialogDrag title="草稿发布轨迹" :visible.sync="dialogVisible" width="1050px" :before-close="doClose" center> <el-dialog v-dialogDrag title="草稿发布轨迹" :visible.sync="dialogVisible" append-to-body width="1050px" :before-close="doClose" center>
<div> <div>
<QueryListPage ref="queryListPage" :card-padding="10" :pager-config="pagerConfig" :query-form="queryForm" :query-list="queryList" /> <QueryListPage ref="queryListPage" :card-padding="10" :pager-config="pagerConfig" :query-form="queryForm" :query-list="queryList" />
</div> </div>

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog v-dialogDrag title="实训管理" :visible.sync="dialogVisible" width="1250px" :before-close="doClose" center> <el-dialog v-dialogDrag title="实训管理" :visible.sync="dialogVisible" append-to-body width="1250px" :before-close="doClose" center>
<div> <div>
<div class="trainingHeader"> <div class="trainingHeader">
<div class="trainingList">实训草稿列表</div> <div class="trainingList">实训草稿列表</div>