4 changed files with 7477 additions and 44 deletions
File diff suppressed because it is too large
@ -0,0 +1,658 @@ |
|||
<template> |
|||
<div class="appClass" v-if="isVip"> |
|||
<template v-for="(perItem, perIndex) in personList" :key="perIndex"> |
|||
<div :class="`parent${perIndex}`"> |
|||
<div :class="`avatar${perIndex}`"> |
|||
<el-avatar size="large" shape="square"> |
|||
<img :src="perItem.ava" alt="头像" /> |
|||
</el-avatar> |
|||
</div> |
|||
<div :class="`usetime${perIndex}`" style="display: inline-block"> |
|||
<el-progress type="circle" striped striped-flow :stroke-width="10" :color="colors" :width="80" |
|||
:percentage="timeObj[`time${perIndex}`]"> |
|||
<span style="color: #000; font-size: 3em">{{ timeObj[`time${perIndex}`] }}</span> |
|||
</el-progress> |
|||
</div> |
|||
<div :class="`result${perIndex}`" style="display: inline-block"> |
|||
<span v-if="perItem.time"> |
|||
耗时 {{ perItem.time / 100 }}秒,答对 |
|||
<el-text :type="type[_.compact(perItem.sure).length]" style="font-size: 1.2em"> |
|||
{{ _.compact(perItem.sure).length }} |
|||
</el-text> |
|||
道题 |
|||
</span> |
|||
<span v-else>第{{ perItem.currentTi + 1 }}题</span> |
|||
</div> |
|||
<div :id="`yanmo${perIndex}`"></div> |
|||
<template v-for="(item, index) in perItem.questionList" :key="index"> |
|||
<template v-if="perItem.currentTi === index"> |
|||
<div :class="`question${perIndex}`"> |
|||
<div class="title"> |
|||
{{ item.title }} |
|||
</div> |
|||
</div> |
|||
<div class="options"> |
|||
<div v-for="(optionItem, optionIndex) in item.options" :class="`option${perIndex}`" :key="optionIndex"> |
|||
<el-tag v-if="optionItem.disabled" :type="optionItem.type" effect="dark"> |
|||
{{ optionItem.text }} |
|||
</el-tag> |
|||
<el-check-tag :checked="optionItem.checked" :type="optionItem.type" v-else |
|||
@change="onChange1(optionItem, optionIndex, item, perItem, perIndex)" effect="dark"> |
|||
{{ optionItem.text }} |
|||
</el-check-tag> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
</template> |
|||
<div :class="`next${perIndex}`"> |
|||
<div> |
|||
<el-button size="large" type="primary" v-if="!perItem.time" @click="nextTi(perItem, perIndex)" :disabled="perItem.questionList[perItem.currentTi].answer === -1 || perItem.clickDisable |
|||
"> |
|||
<span style="font-size: 2em; margin: 18px 8px"> 确定 </span> |
|||
</el-button> |
|||
<el-button size="large" type="primary" v-else @click="submit(perItem, perIndex)" :disabled="!!perItem.time"> |
|||
<span style="font-size: 2em; padding: 8px"> 已结束 </span> |
|||
</el-button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
</div> |
|||
<div v-else class="noVip"> |
|||
<h3> |
|||
<el-tag type="danger" class="noVipTag">体验已过期,请联系管理员。</el-tag> |
|||
</h3> |
|||
</div> |
|||
<el-dialog v-model="dialogInfo.show" :title="dialogInfo.title" width="80%" center :before-close="handleClose"> |
|||
<div> |
|||
<el-row> |
|||
<el-col :span="12" v-for="(perItem, perIndex) in personList" :key="perIndex" style="text-align: center"> |
|||
<div class="mt-10"> |
|||
<el-avatar size="large" shape="square"> |
|||
<img :src="perItem.ava" alt="头像" /> |
|||
</el-avatar> |
|||
</div> |
|||
<div class="mt-20"> |
|||
<span style="font-size: 3em"> |
|||
您一共耗时 {{ perItem.time / 100 }}秒,答对 |
|||
<el-text :type="type[_.compact(perItem.sure).length]"> |
|||
<span style="font-size: 3em"> |
|||
{{ _.compact(perItem.sure).length }} |
|||
</span> |
|||
</el-text> |
|||
道题 |
|||
</span> |
|||
</div> |
|||
<div class="mt-20"> |
|||
<el-progress type="circle" v-if="dialogInfo.winIndex === perIndex" :percentage="100" status="success"> |
|||
<span style="color: #000;font-size: 3em;">赢</span> |
|||
</el-progress> |
|||
<el-progress type="circle" v-else :percentage="100" status="exception"> |
|||
<span style="color: #000;font-size: 3em;">输</span> |
|||
</el-progress> |
|||
</div> |
|||
</el-col> |
|||
</el-row> |
|||
</div> |
|||
<template #footer> |
|||
<div class="dialogFooter"> |
|||
<el-button type="primary" @click="continuePk" style="font-size: 2.5em;height: 2em;"> 继续比赛 </el-button> |
|||
</div> |
|||
</template> |
|||
</el-dialog> |
|||
<div v-if="diolag" class="el-overlay-dialog" @click="handleCloseDialog" |
|||
style="text-align: center; align-content: center"> |
|||
<div><img src="/src/assets/bgimg/bgimg.gif" alt="pk" style="margin-top: 25vh" /></div> |
|||
</div> |
|||
|
|||
</template> |
|||
|
|||
<script> |
|||
import config from './config.js' |
|||
import _ from 'lodash' |
|||
import useConfigStore from './stores/config.js' |
|||
import dayjs from 'dayjs' |
|||
import { ElMessage, ElMessageBox } from 'element-plus' |
|||
export default { |
|||
name: 'app', |
|||
data() { |
|||
return { |
|||
_: _, |
|||
ava0: '', |
|||
ava1: '', |
|||
timeObj: { |
|||
timer0: null, |
|||
timer1: null, |
|||
time0: 100, |
|||
time1: 100 |
|||
}, |
|||
personList: [], |
|||
colors: [ |
|||
{ color: '#ff0000', percentage: 3 }, |
|||
{ color: '#c45656', percentage: 10 }, |
|||
{ color: '#F56C6C', percentage: 20 }, |
|||
{ color: '#f89898', percentage: 30 }, |
|||
{ color: '#fab6b6', percentage: 40 }, |
|||
{ color: '#fde2e2', percentage: 50 }, |
|||
{ color: '#f3d19e', percentage: 60 }, |
|||
{ color: '#eebe77', percentage: 70 }, |
|||
{ color: '#95d475', percentage: 80 }, |
|||
{ color: '#67C23A', percentage: 90 }, |
|||
{ color: '#529b2e', percentage: 100 } |
|||
], |
|||
type: ['danger', 'warning', 'info', 'primary', 'success'], |
|||
isVip: true, |
|||
configStore: useConfigStore(), |
|||
dialogInfo: { |
|||
show: false, |
|||
title: '比赛结果', |
|||
winIndex: -1 |
|||
}, |
|||
diolag: true, |
|||
clickCount: 0, |
|||
avaList: [] |
|||
} |
|||
}, |
|||
methods: { |
|||
init(isc = false) { |
|||
this.dealData() |
|||
this.setTime('timer0', 'time0', isc) |
|||
this.setTime('timer1', 'time1', isc) |
|||
}, |
|||
setTime(name, time, isGo = true) { |
|||
this.timeObj[time] = 100 |
|||
if (this.timeObj[name]) { |
|||
clearInterval(this.timeObj[name]) |
|||
} |
|||
if (isGo) { |
|||
this.timeObj[name] = setInterval(() => { |
|||
this.timeObj[time] -= 1 |
|||
this.timeObj[time] = _.max([this.timeObj[time], 0]) |
|||
}, 1000) |
|||
} |
|||
}, |
|||
getAva() { |
|||
this.clickCount++ |
|||
console.log(777, this.clickCount, this.avaList) |
|||
if (this.clickCount % 2) { |
|||
let arr = _.values(config) |
|||
let random = _.shuffle(arr) |
|||
this.avaList = [random[0], random[1]] |
|||
} |
|||
}, |
|||
dealData() { |
|||
this.getAva() |
|||
this.personList = [] |
|||
for (let i = 0; i < 2; i++) { |
|||
let item = { |
|||
ava: this.avaList[i], |
|||
questionList: [ |
|||
{ |
|||
title: '衣服可以保暖,体现了产品层次模型中的哪一层次产品?', |
|||
options: [ |
|||
{ |
|||
text: 'A 核心产品', |
|||
checked: false, |
|||
type: 'info', |
|||
disabled: false |
|||
}, |
|||
{ |
|||
text: 'B 形式产品', |
|||
checked: false, |
|||
type: 'info', |
|||
disabled: false |
|||
}, |
|||
{ |
|||
text: 'C 期望产品', |
|||
checked: false, |
|||
type: 'info', |
|||
disabled: false |
|||
}, |
|||
{ |
|||
text: 'D 附加产品', |
|||
checked: false, |
|||
type: 'info', |
|||
disabled: false |
|||
} |
|||
], |
|||
answer: -1, |
|||
trueAnswer: 0, |
|||
startTime: parseInt(dayjs().valueOf() / 10), |
|||
endTime: 0 |
|||
}, |
|||
{ |
|||
title: '产品的五层次中,____是指产品的品质、样式、包装和商标等。', |
|||
options: [ |
|||
{ |
|||
text: 'A 核心产品', |
|||
checked: false, |
|||
type: 'info', |
|||
disabled: false |
|||
}, |
|||
{ |
|||
text: 'B 形式产品', |
|||
checked: false, |
|||
type: 'info', |
|||
disabled: false |
|||
}, |
|||
{ |
|||
text: 'C 延伸产品', |
|||
checked: false, |
|||
type: 'info', |
|||
disabled: false |
|||
}, |
|||
{ |
|||
text: 'D 潜在产品', |
|||
checked: false, |
|||
type: 'info', |
|||
disabled: false |
|||
} |
|||
], |
|||
answer: -1, |
|||
trueAnswer: 1, |
|||
startTime: 0, |
|||
endTime: 0 |
|||
}, |
|||
{ |
|||
title: |
|||
'顾客希望旅游景区能够呈现丰富的旅游资源、干净整洁的游园环境、完善的基础设施设备,体现了产品层次模型中的哪一层次产品?', |
|||
options: [ |
|||
{ |
|||
text: 'A 核心产品', |
|||
checked: false, |
|||
type: 'info', |
|||
disabled: false |
|||
}, |
|||
{ |
|||
text: 'B 期望产品', |
|||
checked: false, |
|||
type: 'info', |
|||
disabled: false |
|||
}, |
|||
{ |
|||
text: 'C 形式产品', |
|||
checked: false, |
|||
type: 'info', |
|||
disabled: false |
|||
}, |
|||
{ |
|||
text: 'D 潜在产品', |
|||
checked: false, |
|||
type: 'info', |
|||
disabled: false |
|||
} |
|||
], |
|||
answer: -1, |
|||
trueAnswer: 1, |
|||
startTime: 0, |
|||
endTime: 0 |
|||
}, |
|||
{ |
|||
title: |
|||
'在传统村落白虎村旅游地可以购买纪念品、旅游保险、拍摄个人照片等,增强了游客的旅游体验,这属于哪一层次产品?', |
|||
options: [ |
|||
{ |
|||
text: 'A 核心产品', |
|||
checked: false, |
|||
type: 'info', |
|||
disabled: false |
|||
}, |
|||
{ |
|||
text: 'B 形式产品', |
|||
checked: false, |
|||
type: 'info', |
|||
disabled: false |
|||
}, |
|||
{ |
|||
text: 'C 延伸产品', |
|||
checked: false, |
|||
type: 'info', |
|||
disabled: false |
|||
}, |
|||
{ |
|||
text: 'D 潜在产品', |
|||
checked: false, |
|||
type: 'info', |
|||
disabled: false |
|||
} |
|||
], |
|||
answer: -1, |
|||
trueAnswer: 2, |
|||
startTime: 0, |
|||
endTime: 0 |
|||
}, |
|||
{ |
|||
title: '传统皮影面临困境,正在向数字皮影转型,体现了产品五层次模型中的哪一层次产品?', |
|||
options: [ |
|||
{ |
|||
text: 'A 核心产品', |
|||
checked: false, |
|||
type: 'info', |
|||
disabled: false |
|||
}, |
|||
{ |
|||
text: 'B 形式产品', |
|||
checked: false, |
|||
type: 'info', |
|||
disabled: false |
|||
}, |
|||
{ |
|||
text: 'C 期望产品', |
|||
checked: false, |
|||
type: 'info', |
|||
disabled: false |
|||
}, |
|||
{ |
|||
text: 'D 潜在产品', |
|||
checked: false, |
|||
type: 'info', |
|||
disabled: false |
|||
} |
|||
], |
|||
answer: -1, |
|||
trueAnswer: 3, |
|||
startTime: 0, |
|||
endTime: 0 |
|||
} |
|||
], |
|||
currentTi: 0, |
|||
clickDisable: false, // 是否点击 |
|||
time: 0, |
|||
sure: [] |
|||
} |
|||
this.personList.push(_.cloneDeep(item)) |
|||
} |
|||
}, |
|||
onChange1(optionItem, optionIndex, item, perItem, perIndex) { |
|||
optionItem.checked = true |
|||
item.answer = optionIndex |
|||
for (let i = 0; i < item.options.length; i++) { |
|||
if (optionIndex !== i) { |
|||
item.options[i].checked = false |
|||
} |
|||
item.options[i].type = 'info' |
|||
} |
|||
optionItem.type = 'success' |
|||
}, |
|||
nextTi(perItem, perIndex) { |
|||
let duration = 1500 |
|||
perItem.clickDisable = true |
|||
let item = perItem.questionList[perItem.currentTi] |
|||
if (item.answer !== item.trueAnswer) { |
|||
item.options[item.answer].type = 'danger' |
|||
item.options[item.trueAnswer].type = 'success' |
|||
} else { |
|||
item.options[item.trueAnswer].type = 'success' |
|||
} |
|||
perItem.questionList[perItem.currentTi].endTime = parseInt(dayjs().valueOf() / 10) |
|||
for (let i = 0; i < perItem.questionList[perItem.currentTi].options.length; i++) { |
|||
let ele = perItem.questionList[perItem.currentTi].options[i] |
|||
ele.disabled = true |
|||
} |
|||
let _msg = -1 |
|||
if ( |
|||
perItem.questionList[perItem.currentTi].answer === |
|||
perItem.questionList[perItem.currentTi].trueAnswer |
|||
) { |
|||
_msg = ElMessage({ |
|||
type: 'info', |
|||
duration: duration - 500, |
|||
customClass: 'yanmo', |
|||
icon: 'check', |
|||
message: '恭喜你,答对了!', |
|||
appendTo: document.getElementById(`yanmo${perIndex}`) |
|||
}) |
|||
let rightAudio = document.getElementById('right') |
|||
rightAudio.play() |
|||
} else { |
|||
_msg = ElMessage({ |
|||
type: 'info', |
|||
duration: duration - 500, |
|||
customClass: 'yanmo', |
|||
icon: 'close', |
|||
message: '很遗憾,打错了!', |
|||
appendTo: document.getElementById(`yanmo${perIndex}`) |
|||
}) |
|||
let errorAudio = document.getElementById('error') |
|||
errorAudio.play() |
|||
} |
|||
setTimeout(() => { |
|||
if (_msg !== -1) { |
|||
_msg.close() |
|||
} |
|||
//加一防止出错循环取余 |
|||
if (perItem.currentTi == perItem.questionList.length - 1) { |
|||
this.submit(perItem, perIndex) |
|||
} |
|||
let count = perItem.questionList.length |
|||
perItem.currentTi += 1 |
|||
perItem.currentTi %= count |
|||
// 将下一题的初始时间定死 |
|||
perItem.questionList[perItem.currentTi].startTime = parseInt(dayjs().valueOf() / 10) |
|||
this.setTime(`timer${perIndex}`, `time${perIndex}`) |
|||
perItem.clickDisable = false |
|||
}, duration) |
|||
}, |
|||
//提交 |
|||
submit(perItem, perIndex) { |
|||
perItem.time = 0 |
|||
perItem.sure = [] |
|||
for (let i = 0; i < perItem.questionList.length; i++) { |
|||
let element = perItem.questionList[i] |
|||
perItem.time += element.endTime - element.startTime |
|||
perItem.sure.push(element.trueAnswer === element.answer) |
|||
} |
|||
let pass = true |
|||
let sure = [] |
|||
let time = [] |
|||
for (let i = 0; i < JSON.parse(JSON.stringify(this.personList)).length; i++) { |
|||
let ele = this.personList[i] |
|||
sure.push(_.compact(ele.sure)) |
|||
time.push(ele.time) |
|||
if (!ele.time) { |
|||
pass = false |
|||
break |
|||
} |
|||
} |
|||
if (_.compact(sure[0]).length > _.compact(sure[1]).length) { |
|||
this.dialogInfo.winIndex = 0 |
|||
} else if (_.compact(sure[0]).length === _.compact(sure[1]).length) { |
|||
if (time[0] > time[1]) { |
|||
this.dialogInfo.winIndex = 1 |
|||
} else { |
|||
this.dialogInfo.winIndex = 0 |
|||
} |
|||
} else { |
|||
this.dialogInfo.winIndex = 1 |
|||
} |
|||
if (pass) { |
|||
this.dialogInfo.show = true |
|||
} |
|||
this.setTime(`timer${perIndex}`, `time${perIndex}`, false) |
|||
}, |
|||
handleClose(done) { |
|||
done() |
|||
this.continuePk() |
|||
}, |
|||
continuePk() { |
|||
this.dialogInfo.show = false |
|||
this.diolag = true |
|||
this.init() |
|||
}, |
|||
handleCloseDialog() { |
|||
this.diolag = false |
|||
this.init(true) |
|||
} |
|||
}, |
|||
async mounted() { |
|||
let audio = document.getElementById('myAudio1') |
|||
audio.addEventListener('canplay', function () { |
|||
audio.volume = 0.1 |
|||
}) |
|||
let fiveDay = dayjs('2024-05-21T00:00:00').valueOf() |
|||
if (!this.isVip) { |
|||
if (dayjs().valueOf() > fiveDay) { |
|||
this.isVip = false |
|||
return |
|||
} else { |
|||
this.isVip = true |
|||
} |
|||
} |
|||
this.dealData() |
|||
}, |
|||
watch: {}, |
|||
computed: {} |
|||
} |
|||
</script> |
|||
<style scoped> |
|||
.appClass { |
|||
width: 100vw; |
|||
height: 100vh; |
|||
color: #000; |
|||
background-color: #d9ecff; |
|||
} |
|||
|
|||
.parent0 { |
|||
border-right: 20vw solid #fff; |
|||
display: inline-block; |
|||
width: 40vw; |
|||
height: 100vh; |
|||
} |
|||
|
|||
.parent1 { |
|||
display: inline-block; |
|||
width: 40vw; |
|||
height: 100vh; |
|||
} |
|||
|
|||
.avatar0 { |
|||
text-align: left; |
|||
margin: 6px 0 0 6px; |
|||
min-height: 10vh; |
|||
width: 100%; |
|||
} |
|||
|
|||
.avatar1 { |
|||
text-align: right; |
|||
margin: 6px 16px 0 0; |
|||
min-height: 10vh; |
|||
width: 99%; |
|||
} |
|||
|
|||
.usetime0 { |
|||
text-align: center; |
|||
height: 0; |
|||
position: relative; |
|||
top: -10vh; |
|||
width: 100%; |
|||
} |
|||
|
|||
.usetime1 { |
|||
text-align: center; |
|||
height: 0; |
|||
position: relative; |
|||
top: -10vh; |
|||
width: 100%; |
|||
} |
|||
|
|||
.result0 { |
|||
text-align: center; |
|||
position: relative; |
|||
top: -10vh; |
|||
min-height: 8vh; |
|||
width: 100%; |
|||
font-size: 2em; |
|||
} |
|||
|
|||
.result1 { |
|||
text-align: center; |
|||
position: relative; |
|||
top: -10vh; |
|||
min-height: 8vh; |
|||
width: 100%; |
|||
font-size: 2em; |
|||
} |
|||
|
|||
.question0 { |
|||
height: 20vh; |
|||
text-align: center; |
|||
position: relative; |
|||
top: -10vh; |
|||
} |
|||
|
|||
.question1 { |
|||
height: 20vh; |
|||
text-align: center; |
|||
position: relative; |
|||
top: -10vh; |
|||
} |
|||
|
|||
.title { |
|||
text-indent: 2em; |
|||
width: 76%; |
|||
margin-left: 10%; |
|||
height: 31vh; |
|||
color: #000; |
|||
padding: 1% 2% 0 2%; |
|||
font-size: 2.3em; |
|||
border-radius: 10px; |
|||
text-align: left; |
|||
align-content: center; |
|||
background-color: #4bc1ed; |
|||
} |
|||
|
|||
.options { |
|||
width: 80%; |
|||
border-radius: 30px; |
|||
margin-left: 10%; |
|||
height: 34vh; |
|||
color: #fff; |
|||
text-align: center; |
|||
padding-top: 1vh; |
|||
margin-top: 3vh; |
|||
background-color: #4bc1ed; |
|||
} |
|||
|
|||
.option0 { |
|||
height: calc(9vh - 12px); |
|||
margin-top: 6px; |
|||
} |
|||
|
|||
.option1 { |
|||
height: calc(9vh - 12px); |
|||
margin-top: 6px; |
|||
} |
|||
|
|||
.next0 { |
|||
padding-top: 4vh; |
|||
min-height: 5vh; |
|||
width: 100%; |
|||
text-align: center; |
|||
} |
|||
|
|||
.next1 { |
|||
padding-top: 4vh; |
|||
min-height: 5vh; |
|||
width: 100%; |
|||
text-align: center; |
|||
} |
|||
|
|||
.mt-10 { |
|||
margin-top: 20px; |
|||
} |
|||
|
|||
.mt-20 { |
|||
margin: 40px 0; |
|||
} |
|||
|
|||
.noVip { |
|||
text-align: center; |
|||
margin-top: 40vh; |
|||
} |
|||
|
|||
.noVipTag { |
|||
font-size: 3em; |
|||
line-height: 1.6em; |
|||
height: 1.6em; |
|||
} |
|||
</style> |
Binary file not shown.
Loading…
Reference in new issue