Files
36Wisdom/ui-src/src/components/interactions/FindSpot.vue
T

76 lines
2.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="find-spot">
<view class="scene" :style="{ background: scene.color + '55' }">
<view
v-for="(it, i) in items"
:key="it.id"
class="spot"
:style="pos(i)"
:class="{ win: foundIdx === i }"
@click="tap(it, i)"
>
<view class="spot-icon">{{ propVisual(it.name).emoji }}</view>
</view>
<view class="scene-emoji">{{ scene.emoji }}</view>
</view>
<view class="hint">场景里藏着线索点一点找到它</view>
</view>
</template>
<script>
import { propVisual, sceneVisual } from '../../utils/visual.js'
import { playSound } from '../../utils/sound.js'
export default {
name: 'FindSpot',
props: { config: { type: String, default: '' } },
data() { return { retries: 0, found: false, done: false, foundIdx: -1 } },
computed: {
cfg() {
try { return JSON.parse(this.config) } catch (e) { return { kind: 'find_spot', items: [], answer: 0 } }
},
items() { return this.cfg.items || [] },
scene() { return sceneVisual('场景') }
},
methods: {
propVisual,
pos(i) {
// 5 个固定散布位置(左上/右上/中/左下/右下),按 index 轮转
const spots = [
{ left: '8%', top: '18%' }, { left: '58%', top: '12%' }, { left: '30%', top: '45%' },
{ left: '10%', top: '62%' }, { left: '55%', top: '60%' }
]
return spots[i % spots.length]
},
tap(it, i) {
if (this.found || this.done) return
if (it.id === this.cfg.answer) {
this.found = true
this.done = true
this.foundIdx = i
playSound('good')
this.$emit('done', { success: true })
} else {
this.retries++
playSound('bad')
if (this.retries >= 2) {
this.done = true
this.$emit('done', { success: false })
}
}
}
}
}
</script>
<style scoped>
.scene { position: relative; height: 420rpx; border-radius: 28rpx; margin-bottom: 24rpx; }
.scene-emoji { position: absolute; right: 20rpx; top: 10rpx; font-size: 120rpx; opacity: .35; }
.spot { position: absolute; width: 100rpx; height: 100rpx; border-radius: 24rpx; background: #fff; box-shadow: 0 4rpx 14rpx rgba(91,70,54,.18); display: flex; align-items: center; justify-content: center; transition: transform .12s ease; }
.spot:active { transform: scale(.92); }
.spot.win { transform: scale(1.08); border: 4rpx solid #ffb347; animation: win-pulse .5s ease; }
.spot-icon { font-size: 52rpx; }
.hint { text-align: center; color: #a08c74; }
@keyframes win-pulse { 0% { transform: scale(.9); } 50% { transform: scale(1.15); } 100% { transform: scale(1.08); } }
</style>