Files
crawler-plugin/admin-frontend-vue/src/components/MaskReveal.vue
T

82 lines
1.9 KiB
Vue

<script setup lang="ts">
import { onBeforeUnmount, ref, watch } from 'vue'
import { secretPlaceholder } from '@/pages/shop/secret-mask'
/**
* MaskReveal 掩码揭示(module 13 task 247):默认以店铺 secret-mask 掩码占位展示,
* 点击切换时向父组件发 reveal 事件取明文(以 value prop 回填);短时后自动收回。
*/
const props = withDefaults(defineProps<{ value?: string; revealMs?: number }>(), {
value: '',
revealMs: 5000,
})
const emit = defineEmits<{ (e: 'reveal'): void }>()
const revealed = ref(false)
let timer: ReturnType<typeof setTimeout> | null = null
function clearTimer(): void {
if (timer) {
clearTimeout(timer)
timer = null
}
}
function show(): void {
revealed.value = true
emit('reveal')
clearTimer()
timer = setTimeout(() => {
revealed.value = false
}, props.revealMs)
}
function hide(): void {
clearTimer()
revealed.value = false
}
function toggle(): void {
if (revealed.value) hide()
else show()
}
watch(
() => props.value,
(v) => {
if (!v) revealed.value = false
},
)
onBeforeUnmount(clearTimer)
</script>
<template>
<span class="mask-reveal">
<span class="mask-reveal-text">{{ revealed && value ? value : secretPlaceholder() }}</span>
<button
type="button"
class="mask-reveal-toggle"
:aria-label="revealed ? '隐藏' : '显示'"
@click="toggle"
>
{{ revealed ? '隐藏' : '显示' }}
</button>
</span>
</template>
<style scoped>
.mask-reveal { display: inline-flex; align-items: center; gap: 6px; }
.mask-reveal-text { font-variant-numeric: tabular-nums; }
.mask-reveal-toggle {
border: 1px solid #cbd9e6;
border-radius: 6px;
background: #fff;
color: #5b6f83;
font-size: 12px;
padding: 1px 8px;
cursor: pointer;
}
.mask-reveal-toggle:hover { color: #2f5d8b; border-color: #95b1cb; background: #edf5fb; }
</style>