|
|
|
@ -1,52 +1,57 @@ |
|
|
|
<template> |
|
|
|
<template> |
|
|
|
<div class="statistic"> |
|
|
|
<div class="statistic"> |
|
|
|
<div class="statistic-number"> |
|
|
|
<div class="statistic-number"> |
|
|
|
{{ isDecimal ? parseFloat(outputValue.toFixed(2)) : parseInt(outputValue) }}{{ valueUnit }} |
|
|
|
<!-- 如果是字符串则直接显示,否则显示动画数字 + 单位 --> |
|
|
|
|
|
|
|
<template v-if="typeof props.value === 'string'"> |
|
|
|
|
|
|
|
{{ props.value }} |
|
|
|
|
|
|
|
</template> |
|
|
|
|
|
|
|
<template v-else> |
|
|
|
|
|
|
|
{{ formattedNumber }}{{ valueUnit }} |
|
|
|
|
|
|
|
</template> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="statistic-title" :title="tooltip">{{ title }}</div> |
|
|
|
<div class="statistic-title" :title="tooltip">{{ title }}</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
</template> |
|
|
|
|
|
|
|
|
|
|
|
<script setup> |
|
|
|
<script setup> |
|
|
|
import {useTransition} from "@vueuse/core"; |
|
|
|
import {useTransition} from "@vueuse/core"; |
|
|
|
|
|
|
|
import {computed, ref, watch} from 'vue'; |
|
|
|
|
|
|
|
|
|
|
|
const props = defineProps({ |
|
|
|
const props = defineProps({ |
|
|
|
tooltip: { |
|
|
|
tooltip: {type: String, default: ''}, |
|
|
|
type: String, |
|
|
|
title: {type: String}, |
|
|
|
default: '', |
|
|
|
// 支持 Number 和 String 类型 |
|
|
|
}, |
|
|
|
value: {type: [Number, String], default: 0}, |
|
|
|
title: { |
|
|
|
valueUnit: {type: String}, |
|
|
|
type: String |
|
|
|
isDecimal: {type: Boolean, default: false} |
|
|
|
}, |
|
|
|
|
|
|
|
value: { |
|
|
|
|
|
|
|
type: Number, |
|
|
|
|
|
|
|
default: 0, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
valueUnit: { |
|
|
|
|
|
|
|
type: String, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
// 是否是小数 |
|
|
|
|
|
|
|
isDecimal: { |
|
|
|
|
|
|
|
type: Boolean, |
|
|
|
|
|
|
|
default: false |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
const value = ref(props.value); |
|
|
|
// 用于动画的数字值(仅当 value 为数字时有效) |
|
|
|
console.log( |
|
|
|
const numericValue = ref(typeof props.value === 'number' ? props.value : 0); |
|
|
|
value |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
watch(() => props.value, (val) => { |
|
|
|
watch(() => props.value, (val) => { |
|
|
|
value.value = val || 0; |
|
|
|
if (typeof val === 'number') { |
|
|
|
|
|
|
|
numericValue.value = val || 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// 字符串变化时不处理 numericValue,保持原数字(但模板中不会使用它) |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 数字动画(始终存在,但字符串模式下不显示) |
|
|
|
|
|
|
|
const animatedValue = useTransition(numericValue, {duration: 1500}); |
|
|
|
|
|
|
|
|
|
|
|
}) |
|
|
|
// 格式化数字部分 |
|
|
|
const outputValue = useTransition(value, { |
|
|
|
const formattedNumber = computed(() => { |
|
|
|
duration: 1500, |
|
|
|
if (typeof props.value === 'string') return ''; |
|
|
|
|
|
|
|
const num = animatedValue.value; |
|
|
|
|
|
|
|
return props.isDecimal ? parseFloat(num.toFixed(2)) : parseInt(num); |
|
|
|
}); |
|
|
|
}); |
|
|
|
</script> |
|
|
|
</script> |
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped> |
|
|
|
<style lang="scss" scoped> |
|
|
|
.statistic { |
|
|
|
.statistic { |
|
|
|
text-align: center; |
|
|
|
text-align: center; |
|
|
|
cursor: pointer; |
|
|
|
cursor: pointer; |
|
|
|
|
|
|
|
|
|
|
|
.statistic-number { |
|
|
|
.statistic-number { |
|
|
|
font-size: 39px; |
|
|
|
font-size: 39px; |
|
|
|
font-weight: 700; |
|
|
|
font-weight: 700; |
|
|
|
@ -85,4 +90,4 @@ const outputValue = useTransition(value, { |
|
|
|
font-size: 27px; |
|
|
|
font-size: 27px; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
</style> |
|
|
|
</style> |