vue常用的置顶上下移和置底
<div class="sort">
顺序:
<a class="font-18 margin-r-4" @click="changeSort('top', index)"><a-icon type="vertical-align-top"></a-icon></a>
<a class="font-14 margin-r-4" @click="changeSort('up', index)"><a-icon type="arrow-up"></a-icon></a>
<a class="font-14 margin-r-4" @click="changeSort('down', index)"><a-icon type="arrow-down"></a-icon></a>
<a class="font-18" @click="changeSort('bottom', index)"><a-icon type="vertical-align-bottom"></a-icon></a>
</div>
changeSort(type, index) {
let leng = this.list.length;
if (
(type == "top" && index == 0) ||
(type == "up" && index == 0) ||
(type == "down" && index == leng - 1) ||
(type == "bottom" && index == leng - 1)
) {
return;
}
console.log(this.list,"/his.list");
let item = this.list.splice(index, 1);
console.log('item',item);
if (type == "top") {
this.list.unshift(item[0]);
} else if (type == "bottom") {
this.list.push(item[0]);
} else if (type == "up") {
this.list.splice(index - 1, 0, item[0]);
} else {
this.list.splice(index + 1, 0, item[0]);
}
},
function handlePosition(flag: string, index: number) {
let list = examInfoQuestionsSetTable.getDataSource().map(item => {
item.extractQuestions = item.editValueRefs.extractQuestions
return item
})
let length = list.length;
if (flag == 'up') {
if (index == 0) {
showMessage('已经处于置顶,无法上移', 'warning');
return;
}
} else {
if (index == length) {
showMessage('已经处于置底,无法下移', 'warning');
return;
}
}
let prev = Object.assign({}, list[index - 1]);
let next = Object.assign({}, list[index]);
prev.sort = index + 1;
list[index] = prev;
next.sort = index;
list[index - 1] = next;
examInfoQuestionsSetTable.setTableData(list);
}
考试参考
<template>
<div class="container">
<div class="section section-top flex flex-jus-sp flex-align-c">
<div class="top-left flex flex-align-c">
<el-button icon="el-icon-arrow-left" style="margin-right: 20px" @click="back">退出</el-button>
</div>
</div>
<div class="section section-content flex">
<div class="section-left" :style="{height}">
<div class="section-box" :style="{height:leftHeight}">
<div class="num-list flex flex-wrap-w">
<span
class="num-item"
:class="{'active': activeIndex == index, 'no': subjectList[index].check==0, 'error': subjectList[index].checkPoint==0}"
v-for="(item, index) in subjectList.length"
:key="index"
@click="handleSelectNum(index)"
>{{index+1}}</span>
</div>
</div>
<div class="left-bottom" ref="left_bottom">
<template v-if="progress == 1">
<div class="time">{{time}}</div>
<el-button size="medium" type="primary" @click="handleSubmit(2)">提交</el-button>
</template>
<template v-if="progress == 2 && !showRes">
<el-button size="medium" type="info" @click="handleShowRes">返回结果页面</el-button>
</template>
<div class="colot-tag flex">
<template v-for="(item,index) in colorStatus">
<div class="tag-item flex" v-if="item.error == progress || item.error == 0">
<span :style="{background:item.color}"></span>
<span>{{progress==2&&item.error==0?item.label:item.name}}</span>
</div>
</template>
</div>
</div>
</div>
<div class="section-right" :style="{height}">
<div class="right-content" :style="{height:rightHeight}">
<template v-if="activeIndex!=-1">
<div class="flex flex-align-c" style="margin-bottom: 18px;">
<el-tag effect="plain" size="small" class="sub-tag">{{subjectType[subjectInfo.titleType]}}</el-tag>
<span class="sub-num">{{subjectInfo.point}}分</span>
</div>
<div class="flex">
<div class="right-head" ref="right_head">
<span>{{activeIndex + 1}}.</span>
</div>
<div class="flex flex-wrap-c">
<div class="sub-title" v-html="subjectInfo.name"></div>
</div>
</div>
</template>
<div class="sub-content" v-if="activeIndex>=0" :style="{'padding-left':sub_padding}">
<template v-if="subjectInfo.titleType == 'single'">
<el-radio-group v-model="singleData" :disabled="progress==2">
<el-radio
:label="item.id"
v-for="(item, index) in subjectInfo.topic"
:key="index"
size="medium"
>
<span class="title-key">{{item.key}}.</span>
<template v-if="item.type == 1">
<img :src="item.option.view" class="img" alt />
</template>
<template v-if="item.type == 0">
<span>{{item.option}}</span>
</template>
</el-radio>
</el-radio-group>
</template>
<template v-if="subjectInfo.titleType == 'multi'">
<el-checkbox-group v-model="multiData" :disabled="progress==2">
<el-checkbox
:label="item.id"
v-for="(item, index) in subjectInfo.topic"
:key="index"
size="medium"
>
<span class="title-key">{{item.key}}.</span>
<template v-if="item.type == 1">
<img :src="item.option.view" class="img" alt />
</template>
<template v-if="item.type == 0">
<span>{{item.option}}</span>
</template>
</el-checkbox>
</el-checkbox-group>
</template>
<template v-if="subjectInfo.titleType == 'judge'">
<el-radio-group v-model="judgeData" :disabled="progress==2">
<el-radio
:label="item.id"
v-for="(item, index) in subjectInfo.topic"
:key="index"
size="medium"
>
<span class="title-key">{{item.key}}.</span>
<template v-if="item.type == 1">
<img :src="item.option.view" class="img" alt />
</template>
<template v-if="item.type == 0">
<span>{{item.option}}</span>
</template>
</el-radio>
</el-radio-group>
</template>
<div class="suc-title" v-if="progress==2&&isError==1">
<div class="flex suc-list">
<i class="el-icon-success" style="color:#4db14e"></i>
<div v-for="item in answer" class="suc-item" style="color:#4db14e">
<span class="title-key">{{item.key}}</span>
</div>
</div>
<div class="flex suc-list">
<i class="el-icon-error" style="color:#e54d4c"></i>
<div v-for="item in solution" class="suc-item" style="color:#e54d4c">
<span class="title-key">{{item.key}}</span>
</div>
<span class="suc-item" style="color:#e54d4c" v-if="solution.length==0">未选</span>
</div>
</div>
</div>
<template v-if="showRes">
<div class="flex-c" :style="{'margin-bottom':right_m_b+'px'}">
<div class="res-content">
<span class="res-title">考试结果</span>
<div
class="res-circle flex"
:style="{'background-color': examInfo.grade == 0 ?'#FFD1D1':'',color: examInfo.grade == 0 ?'#e53535':''}"
>
<span class="res-sub">{{examInfo.grade?'合格':'不合格'}}</span>
<span>{{examInfo.point}}</span>
</div>
<div class="res-time">
用时:
<span>{{time}}</span>
</div>
</div>
</div>
<div class="res-table" ref="res_bottom">
<div class="res-tab-list">
<span class="key">考试名称:</span>
<span>{{examInfo.exam}}</span>
<span class="key">参考人数:</span>
<span>{{examInfo.person}}</span>
</div>
<div class="res-tab-list">
<span class="key">答对题数:</span>
<span>{{examInfo.topicCheck}}</span>
<span class="key">正确率:</span>
<span>{{examInfo.rate}}</span>
</div>
<div class="res-tab-list">
<span class="key">排名:</span>
<span>{{examInfo.no}}</span>
<span class="key">考试结果:</span>
<span>{{examInfo.grade?'合格':'不合格'}}</span>
</div>
<div class="res-tab-list">
<span class="key">考试开始时间:</span>
<span>{{examInfo.begin}}</span>
<span class="key">考试结束时间:</span>
<span>{{examInfo.end}}</span>
</div>
</div>
</template>
</div>
<div
class="right-bottom flex flex-jus-sp"
:class="{'flex-jus-e': activeIndex == 0}"
ref="right_bottom"
v-if="progress == 1"
>
<el-button
size="medium"
icon="el-icon-caret-left"
@click="handleChangeSub(0)"
v-if="activeIndex != 0"
>上一题</el-button>
<el-button
size="medium"
@click="handleChangeSub(1)"
v-if="activeIndex != subjectList.length-1"
>
下一题
<i class="el-icon-caret-right"></i>
</el-button>
</div>
</div>
</div>
</div>
</template>
<script>
var times = 0;
var solutionData = {};
var theoryTip = -1;
var fromPath = "";
export default {
name: "",
data() {
return {
loading: false,
examId: "",
purpose: 1,
type: 1,
height: "100px",
leftHeight: "200px",
rightHeight: "200px",
right_m_b: "10",
sub_padding: "10px",
numList: [],
activeIndex: -1,
colorStatus: [
{ color: "#94CAFF", name: "已答", error: 0, label: "正确" },
{ color: "#FFB532", name: "当前", error: 0, label: "当前" },
{ color: "#DDE2EB", name: "未答", error: 1 },
{ color: "#fd7272", name: "错误", error: 2 },
],
partakeId: "",
subjectList: [],
subjectInfo: {},
subjectType: { multi: "多选题", single: "单选题", judge: "判断题" },
singleData: -1,
multiData: [],
judgeData: -1,
timeIntertval: null,
time: "00:00:00",
progress: 1,
isError: 0,
answer: [],
solution: [],
showRes: false,
examInfo: {},
};
},
created() {
this.init();
window.addEventListener("resize", this.getHeight, false);
},
destroyed() {
theoryTip = -1;
if (this.timeIntertval) clearInterval(this.timeIntertval);
times = 0;
solutionData = {};
window.removeEventListener("resize", this.getHeight, false);
},
mounted() {
this.getHeight();
},
methods: {
init() {
this.getHeight();
times = 0;
let { progress, id, type, purpose, partakeId, from } =
this.$route.query;
fromPath = from;
this.examId = id;
this.progress = progress == 0 ? 1 : 2;
this.type = type;
this.purpose = purpose;
this.partakeId = partakeId;
if (this.progress == 1) {
this.getData();
this.timeOut();
} else {
this.getResult();
}
},
timeOut() {
this.timeIntertval = setInterval(() => {
times += 1;
this.setTime(times);
}, 1000);
},
setTime(times) {
let h = parseInt(times / 60 / 60);
let h_s = h >= 10 ? h : "0" + h;
let m = parseInt((times - 3600 * h) / 60);
let m_s = m >= 10 ? m : "0" + m;
let s = times - h * 3600 - m * 60;
s = s >= 10 ? s : "0" + s;
this.time = h_s + ":" + m_s + ":" + s;
},
handleSelectNum(index) {
if (this.progress == 2) {
this.showRes = false;
this.reSubjectInfo(index);
} else {
this.sureResult((res) => {
if (res == "success") {
this.reSubjectInfo(index);
}
});
}
},
handleChangeSub(index) {
this.sureResult((res) => {
if (res == "success") {
if (index == 1) {
this.activeIndex++;
} else {
this.activeIndex--;
}
this.reSubjectInfo(this.activeIndex);
}
});
},
reSubjectInfo(index) {
this.activeIndex = index;
this.subjectInfo = JSON.parse(
JSON.stringify(this.subjectList[this.activeIndex])
);
let elem = document.createElement("div");
elem.innerHTML = this.subjectInfo.name;
this.foreachImg(elem.getElementsByTagName("img"), elem);
let { titleType, topic, checkPoint } = this.subjectInfo;
this.isError = checkPoint ? 0 : 1;
this.multiData = [];
let answer = [];
let solution = [];
this.judgeData = -1;
this.singleData = -1;
topic.forEach((item) => {
if (item.solution == 1) {
if (titleType == "multi") {
this.multiData.push(item.id);
} else {
this[titleType + "Data"] = item.id;
}
solution.push(item);
}
if (item.answer == 1) {
answer.push(item);
}
});
this.answer = answer;
this.solution = solution;
setTimeout(() => {
this.getWidth();
}, 200);
},
foreachImg(imgs, elem, index) {
if (!imgs.length) return;
index = index || 0;
let sign = imgs[index].getAttribute("sign");
if (sign) {
imgs[index].src = "";
this.ajax
.get("/view", { sign, d: new Date().getTime })
.then((res) => {
if (res.code == 1) {
imgs[index].src = res.data.entry[0].view;
}
})
.then(() => {
this.subjectInfo.name = elem.innerHTML;
index++;
if (imgs.length > index) {
this.timer = setTimeout(() => {
this.foreachImg(imgs, elem, index);
}, 150);
}
});
} else {
index++;
if (imgs.length > index) {
this.foreachImg(imgs, elem, index);
}
}
},
sureResult(cal) {
if (this.loading) {
return;
}
this.loading = true;
let type = this.subjectInfo.titleType;
let info = this.subjectList[this.activeIndex];
let option = [];
if (type == "single" && this.singleData != -1) {
info.check = 1;
info.topic.forEach((item) => {
if (item.id == this.singleData) {
item.solution = 1;
}
});
option.push(this.singleData);
} else if (type == "multi" && this.multiData.length) {
info.check = 1;
info.topic.forEach((item) => {
if (this.multiData.indexOf(item.id) != -1) {
item.solution = 1;
}
});
option = this.multiData;
} else if (type == "judge" && this.judgeData != -1) {
info.check = 1;
info.topic.forEach((item) => {
if (item.id == this.judgeData) {
item.solution = 1;
}
});
option.push(this.judgeData);
}
if (
option.length &&
solutionData[info.id] != JSON.stringify(option)
) {
let params = {
partakeId: this.partakeId,
id: info.id,
option: JSON.stringify(option),
};
this.ajax
.post("/student/exam/theory/answer", params)
.then((res) => {
this.loading = false;
if (res.code == 1) {
this.singleData = -1;
this.judgeData = -1;
this.multiData = [];
solutionData[params.id] = params.option;
cal("success");
} else {
this.$message(res.msg, {
title: "错误",
type: "error",
});
}
});
} else {
this.loading = false;
cal("success");
}
},
getData() {
this.ajax
.post("/student/exam/theory", { examId: this.examId })
.then((res) => {
theoryTip = res.code;
if (res.code == 1) {
let data = res.data.entry;
this.setSubList(data);
} else {
if (this.timeIntertval)
clearInterval(this.timeIntertval);
this.$message(res.msg, {
title: "错误",
type: "error",
});
}
});
},
setSubList(data, flag) {
let list = [];
data.singleOption.forEach((ele) => {
ele.titleType = "single";
list.push(ele);
});
data.multiOption.forEach((ele) => {
ele.titleType = "multi";
list.push(ele);
});
data.judgeOption.forEach((ele) => {
ele.titleType = "judge";
list.push(ele);
});
list.sort((a, b) => {
return Number(a.id) - Number(b.id);
});
this.partakeId = data.partakeId;
this.subjectList = list;
if (this.progress == 1) {
this.activeIndex = 0;
this.reSubjectInfo(0);
} else {
this.activeIndex = -1;
}
if (flag) {
this.activeIndex = -1;
}
},
back() {
if (this.progress == 1) {
this.sureResult((res) => {
let flag = this.purpose == 2 ? 1 : 0;
if (res == "success") {
if (this.type == 2 && theoryTip == 1) {
this.$confirm(
`当前正在${
flag ? "训练" : "考试"
}中,点击确定,将提交答案并退出`,
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}
)
.then(() => {
this.submitResult();
})
.catch(() => {
this.exitPage();
});
} else {
this.exitPage(flag);
}
}
});
} else {
this.exitPage(1);
}
},
exitPage(flag) {
if (flag == 1 || theoryTip != 1) {
if (fromPath == "home") {
this.$router.replace({
path: "/student/examTest/index",
query: { purpose: this.purpose },
});
} else {
this.$router.go(-1);
}
}
},
handleSubmit(flag) {
this.sureResult((res) => {
if (res == "success") {
this.submitResult(flag);
}
});
},
submitResult(flag) {
this.ajax
.post("/student/exam/theory/submitted", {
partakeId: this.partakeId,
})
.then((res) => {
if (res.code == 1) {
if (flag == 2) {
if (this.timeIntertval) {
clearInterval(this.timeIntertval);
}
this.progress = 2;
this.activeIndex = -1;
this.showRes = true;
times = 0;
this.getResult();
} else {
theoryTip = -1;
this.exitPage();
}
} else {
this.$message(res.msg, {
title: "错误",
type: "error",
});
}
});
},
getResult() {
let url =
fromPath == "manage"
? "/admin/invigilate/result"
: "/student/exam/theory/result";
let ajaxType = fromPath == "manage" ? "get" : "post";
this.ajax[ajaxType](url, {
partakeId: this.partakeId,
}).then((res) => {
if (res.code == 1) {
this.examInfo = res.data.entry;
let { time, total, point, topic } = this.examInfo;
this.examInfo.rate = parseInt((point / total) * 100) + "%";
this.showRes = true;
this.setTime(time);
this.setSubList(topic, 1);
this.getHeight();
} else {
this.$message(res.msg, {
title: "错误",
type: "error",
});
}
});
},
handleShowRes() {
this.activeIndex = -1;
this.showRes = true;
},
reset() {},
getHeight() {
let h = window.innerHeight;
this.height = h - 180 + "px";
let left_bottom_h = this.$refs.left_bottom
? this.$refs.left_bottom.offsetHeight
: 20;
let right_bottom_h = this.$refs.right_bottom
? this.$refs.right_bottom.offsetHeight
: 0;
let res_bottom_h = this.$refs.res_bottom
? this.$refs.res_bottom.offsetHeight
: 160;
this.leftHeight = h - 180 - left_bottom_h + "px";
this.rightHeight = h - 180 - right_bottom_h + "px";
let right_m_b = h - 180 - 550 - res_bottom_h;
this.right_m_b = right_m_b > 0 ? right_m_b : 10;
},
getWidth() {
let w = this.$refs.right_head
? this.$refs.right_head.offsetWidth
: 10;
this.$nextTick(() => {
this.sub_padding = w + "px";
});
},
},
};
</script>
<style lang="scss" scoped>
::v-deep .el-radio,
.el-checkbox {
.el-checkbox__label,
.el-radio__label {
word-break: normal;
width: auto;
white-space: pre-wrap;
word-wrap: break-word;
overflow: hidden;
}
span {
color: #43515e;
font-size: 18px;
}
.el-radio__inner {
width: 18px;
height: 18px;
background-color: #fff;
&::after {
background-color: #298def;
width: 16px;
height: 16px;
}
}
&.is-checked {
span {
color: #298def;
}
.el-radio__inner {
background-color: #fff;
border-color: #298def;
&::after {
background-color: #298def;
}
}
}
&.is-disabled {
span {
color: #43515e;
}
&.is-checked {
span {
color: #298def;
}
.el-radio__inner,
.el-checkbox__inner {
background-color: #fff;
border-color: #298def;
&::after {
background-color: #298def;
}
}
}
}
}
::v-deep .el-checkbox__input {
+ span.el-checkbox__label {
word-break: normal;
width: auto;
white-space: pre-wrap;
word-wrap: break-word;
overflow: hidden;
}
.el-checkbox__inner {
width: 18px;
height: 18px;
background-color: #fff;
border-radius: 18px;
}
&.is-checked {
.el-checkbox__inner {
background-color: #298def;
&::after {
border-color: #fff;
transform: rotate(45deg) scale(1.2);
left: 6px;
top: 3px;
}
}
}
&.is-disabled {
&.is-checked {
.el-checkbox__inner {
background-color: #298def;
&::after {
border-color: #fff;
}
}
}
}
}
.container {
width: 100%;
height: 100%;
padding: 20px;
.section {
position: relative;
}
.section-top {
background: #fff;
margin-bottom: 20px;
}
.section-content {
.section-left {
position: relative;
width: 320px;
height: 100%;
padding: 10px;
margin-right: 20px;
background: #fff;
box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
.section-box {
width: 100%;
overflow-y: auto;
}
.num-list {
width: 100%;
padding-left: 5px;
.num-item {
width: 50px;
height: 50px;
text-align: center;
line-height: 50px;
font-size: 16px;
color: #fff;
background-color: #94caff;
margin: 0 10px 5px 0;
cursor: pointer;
border-radius: 4px;
font-weight: bold;
&:nth-child(5n) {
margin-right: 0;
}
}
.active {
background-color: #ffb532 !important;
}
.no {
background-color: #dde2eb;
}
.error {
background-color: #fd7272;
}
}
.left-bottom {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
padding: 10px;
overflow: hidden;
.time {
width: 100%;
text-align: center;
font-weight: bolder;
font-size: 32px;
padding: 10px 0 16px 0;
}
.el-button {
width: 100%;
}
.colot-tag {
width: 100%;
height: 30px;
align-items: center;
justify-content: center;
margin-top: 8px;
}
.tag-item {
align-items: center;
margin-right: 20px;
font-size: 16px;
color: #a7a9bf;
&:nth-last-child(1) {
margin: 0;
}
& > span:nth-child(1) {
display: inline-block;
width: 16px;
height: 16px;
margin-right: 8px;
}
}
}
}
.section-right {
position: relative;
width: calc(100% - 340px);
height: 100%;
overflow: hidden;
background: #fff;
box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
.right-content {
padding: 20px;
overflow: auto;
.sub-tag {
padding: 0 20px;
border-radius: 20px;
&.el-tag--plain {
color: #298def;
border-color: #298def;
}
}
.sub-num {
color: #fd7272;
font-size: 20px;
margin-left: 12px;
font-weight: 400;
}
.right-head {
color: #43515e;
> span:nth-last-child(1) {
display: inline-block;
padding-right: 10px;
font-size: 22px;
}
}
.sub-title {
font-size: 22px;
color: #43515e;
::v-deep p {
margin: 0 !important;
}
}
.sub-content {
margin-top: 20px;
.suc-title {
color: #43515e;
font-size: 18px;
padding-top: 20px;
i {
margin-right: 12px;
padding-top: 4px;
}
.suc-list {
width: 100%;
margin-top: 20px;
flex-wrap: wrap;
&:nth-last-child(1) {
margin-top: 20px;
}
.suc-item {
display: inline-block;
font-size: 18px;
margin-right: 4px;
}
}
}
.title-key {
margin-right: 4px;
}
.el-radio,
.el-checkbox {
width: 100%;
margin-left: 0 !important;
margin-right: 0;
height: auto;
padding: 10px 10px 10px 0;
display: flex;
}
.img {
max-height: 200px;
}
}
.flex-c {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-bottom: 20px;
}
.res-content {
display: flex;
flex-direction: column;
align-items: center;
width: 350px;
height: 480px;
padding: 26px 0;
color: #384452;
overflow: hidden;
.res-title {
font-size: 36px;
font-weight: bold;
margin-bottom: 45px;
}
.res-circle {
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 260px;
height: 260px;
background-color: #e1ffe1;
color: #4db14e;
font-size: 98px;
font-weight: bold;
border-radius: 50%;
margin-bottom: 30px;
.res-sub {
font-size: 36px;
font-weight: bold;
line-height: 1.3;
}
}
.res-time {
display: flex;
justify-content: space-between;
align-items: center;
color: #384452;
font-size: 18px;
font-weight: bold;
width: 350px;
height: 60px;
background-color: #edf0f5;
padding: 0 20px;
border-radius: 4px;
span {
font-size: 24px;
color: #384452;
}
}
}
.res-table {
border: 1px solid #e2e3e5;
border-radius: 4px;
.res-tab-list {
display: flex;
width: 100%;
background-color: #fff;
span {
display: inline-block;
padding: 10px 10px 10px 10px;
width: calc(50% - 160px);
font-size: 16px;
color: #444;
background-color: #fff;
&.key {
font-weight: bold;
width: 160px;
text-align: right;
background-color: #eeeff3 !important;
color: #666;
}
}
&:nth-child(2n + 1) {
span {
background-color: #f7f7f7;
}
}
&:nth-child(2n) {
.key {
background-color: #f7f7f7 !important;
}
}
}
}
}
.right-bottom {
position: absolute;
width: 100%;
padding: 10px 20px;
bottom: 0;
left: 0;
}
}
}
.flex-jus-e {
-moz-box-pack: end !important;
-webkit-box-pack: end !important;
-webkit-justify-content: flex-end !important;
justify-content: flex-end !important;
}
}
</style>