Files
cz-web/src/components/QrCodePanel.vue
2026-09-24 09:09:47 +08:00

115 lines
2.5 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.
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import { useCountDown } from '@/composables/useCountDown'
interface Props {
/** 二维码有效期(秒),默认 4:32 */
expiresIn?: number
size?: number
}
const props = withDefaults(defineProps<Props>(), {
expiresIn: 272,
size: 200,
})
const emit = defineEmits<{ refresh: [] }>()
const { seconds, start } = useCountDown(props.expiresIn)
const started = ref(false)
const expired = computed(() => started.value && seconds.value <= 0)
const countdownText = computed(() => {
const m = Math.floor(seconds.value / 60)
const s = seconds.value % 60
return `${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`
})
function refresh(): void {
start(props.expiresIn)
emit('refresh')
}
onMounted(() => {
start(props.expiresIn)
started.value = true
})
</script>
<template>
<div class="qr-panel">
<div
class="qr-panel__box"
:class="{ 'is-expired': expired }"
:style="{ width: `${size}px`, height: `${size}px` }"
@click="refresh"
>
<!-- TODO(api): 二维码内容由支付/签署接口返回后渲染 -->
<template v-if="!expired">
<span class="qr-panel__icon">▦</span>
<span class="qr-panel__tip">扫码支付/签署</span>
</template>
<template v-else>
<span class="qr-panel__icon">⟳</span>
<span class="qr-panel__tip">二维码已过期<br>点击刷新</span>
</template>
</div>
<p class="qr-panel__status text-secondary">
<template v-if="!expired">
二维码将在 <strong class="qr-panel__count">{{ countdownText }}</strong> 后失效(过期可点击二维码刷新)
</template>
<template v-else>
二维码已过期,请点击刷新
</template>
</p>
</div>
</template>
<style lang="less" scoped>
.qr-panel {
.flex(column, center);
gap: @spacing-sm;
&__box {
.flex(column, center);
gap: @spacing-xs;
border: 1px solid @border-color;
border-radius: @radius-base;
background: @white;
cursor: pointer;
transition: border-color 0.2s;
&:hover {
border-color: @primary-color;
}
&.is-expired {
background: @bg-color;
color: @text-color-secondary;
}
}
&__icon {
font-size: 56px;
color: @heading-color;
line-height: 1;
}
&__tip {
font-size: @font-size-sm;
color: @text-color-secondary;
text-align: center;
}
&__status {
font-size: @font-size-sm;
}
&__count {
color: @danger-color;
font-weight: 600;
}
}
</style>