feat: 动作卡组件 ActionCard(选项图标/拼音/听读/按压动画/四色边框)
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<view class="action-cards">
|
||||
<view
|
||||
v-for="(o, idx) in node.options"
|
||||
:key="o.option_id"
|
||||
class="action-card"
|
||||
:class="['c' + (idx + 1), { disabled: disabled }]"
|
||||
@click="pick(o)"
|
||||
>
|
||||
<view class="ac-mark">{{ ['A', 'B', 'C', 'D'][idx] }}</view>
|
||||
<view v-if="o.prop" class="ac-icon">
|
||||
<image v-if="o.prop.image" class="ac-icon-img" :src="o.prop.image" mode="aspectFit" />
|
||||
<text v-else class="ac-icon-emoji">{{ propEmoji(o.prop.name) }}</text>
|
||||
</view>
|
||||
<view class="ac-text">
|
||||
<RubyText :text="o.text" :pinyin="o.text_pinyin" :show="showPinyin" />
|
||||
</view>
|
||||
<view class="ac-listen" @click.stop="listen(o)">🔊</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import RubyText from '../RubyText.vue'
|
||||
import { propVisual } from '../utils/visual.js'
|
||||
import { speak } from '../utils/speech.js'
|
||||
|
||||
export default {
|
||||
name: 'ActionCard',
|
||||
components: { RubyText },
|
||||
props: {
|
||||
node: { type: Object, required: true }, // 决策节点(options 数组)
|
||||
showPinyin: { type: Boolean, default: true },
|
||||
disabled: { type: Boolean, default: false }
|
||||
},
|
||||
emits: ['choose'],
|
||||
methods: {
|
||||
pick(o) {
|
||||
if (this.disabled) return
|
||||
this.$emit('choose', o)
|
||||
},
|
||||
listen(o) {
|
||||
speak(o.text, o.audio)
|
||||
},
|
||||
propEmoji(name) {
|
||||
return propVisual(name).emoji
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.action-cards { display: flex; flex-direction: column; gap: 20rpx; }
|
||||
.action-card { display: flex; align-items: center; background: #f8f2e8; border: 6rpx solid transparent; border-radius: 24rpx; padding: 26rpx 28rpx; transition: transform 0.15s; }
|
||||
.action-card.disabled { opacity: 0.6; }
|
||||
.action-card:active { transform: scale(0.96); }
|
||||
.action-card.c1 { border-color: #ff9a3d; }
|
||||
.action-card.c2 { border-color: #4ecdc4; }
|
||||
.action-card.c3 { border-color: #6c8cff; }
|
||||
.action-card.c4 { border-color: #a58cff; }
|
||||
.ac-mark { width: 56rpx; height: 56rpx; border-radius: 50%; background: #ff9a3d; color: #fff; font-weight: 800; display: flex; align-items: center; justify-content: center; margin-right: 24rpx; flex-shrink: 0; }
|
||||
.ac-icon { width: 88rpx; height: 88rpx; background: #fff7ec; border-radius: 20rpx; display: flex; align-items: center; justify-content: center; margin-right: 20rpx; flex-shrink: 0; }
|
||||
.ac-icon-img { width: 64rpx; height: 64rpx; }
|
||||
.ac-icon-emoji { font-size: 48rpx; }
|
||||
.ac-text { flex: 1; font-size: 30rpx; font-weight: 600; color: #5b4636; }
|
||||
.ac-listen { font-size: 36rpx; width: 64rpx; height: 64rpx; display: flex; align-items: center; justify-content: center; background: #fff0e5; border-radius: 50%; margin-left: 16rpx; flex-shrink: 0; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user