Files
sales_data_dashboard/vue-app/src/components/TopData.vue
T
2026-02-12 09:38:27 +08:00

167 lines
4.4 KiB
Vue

<template>
<div class="top-data">
<!-- 销售信息 -->
<div class="sales-info">
<div class="sales-info-top">
<div class="target-info">
<h3>年度目标</h3>
<div class="target-amount">{{ formatLargeNumber(yearData.target) }}</div>
</div>
<div class="total-info">
<h3>年度总销售额</h3>
<div class="total-amount">{{ formatLargeNumber(yearData.actual) }}</div>
</div>
</div>
<div class="sales-info-cont">
<div class="sales-info-bottom">
<div class="progress-container">
<div class="progress-bg">
<div class="progress-bar" :style="{ width: progressWidth }">
<div class="progress-info">
<div class="play-btn"></div>
</div>
</div>
<div class="progress-text">{{ progressRate }}%</div>
</div>
</div>
</div>
<div class="progress-label">完成率</div>
</div>
</div>
<!-- 年度进度 -->
<div class="countdown">
<h3>年度进度</h3>
<div class="quarters-container">
<div v-for="(quarter, index) in quarters" :key="quarter.id"
class="quarter-item"
:class="{ 'last-quarter': index === quarters.length - 1 }">
<div class="quarter-label">{{ quarter.label }}</div>
<div class="weeks-container">
<div
v-for="week in quarter.weeks"
:key="week"
class="week-circle"
:class="{ 'current': week === currentWeek, 'passed': week < currentWeek }"
:title="`第${week}周`"
>
{{ week }}
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
const emit = defineEmits(['progress-rate'])
// 年度销售数据
const yearData = ref({
target: 3500,
actual: 2750
})
// 进度条宽度
const progressWidth = ref('0%')
const progressRate = ref('0.00')
// 获取当前周数
const getCurrentWeek = () => {
const now = new Date()
const start = new Date(now.getFullYear(), 0, 1)
const diff = now - start
return Math.floor(diff / (7 * 24 * 60 * 60 * 1000)) + 1
}
const currentWeek = ref(getCurrentWeek())
// 季度数据
const quarters = ref([
{ id: 'q1', label: 'Q1', start: 1, end: 13, weeks: [] },
{ id: 'q2', label: 'Q2', start: 14, end: 26, weeks: [] },
{ id: 'q3', label: 'Q3', start: 27, end: 39, weeks: [] },
{ id: 'q4', label: 'Q4', start: 40, end: 52, weeks: [] }
])
// 初始化季度周数
quarters.value.forEach(quarter => {
for (let i = quarter.start; i <= quarter.end; i++) {
quarter.weeks.push(i)
}
})
// 获取年度数据(可替换为API调用)
const fetchYearData = async () => {
// TODO: 替换为实际的API调用
// try {
// const response = await fetch('/api/year-data')
// const data = await response.json()
// return data
// } catch (error) {
// console.error('获取数据失败:', error)
// return { target: 0, actual: 0 }
// }
// 当前使用模拟数据
console.log('正在获取年度数据...')
return {
target: 3500,
actual: 2750
}
}
// 格式化大数字(万元)
const formatLargeNumber = (num) => {
return num.toLocaleString('zh-CN') + ' 万元'
}
// 启动进度条动画
const startProgressAnimation = (targetRate) => {
const PROGRESS_STEP = 0.4
const PROGRESS_INTERVAL = 20
let value = 0
let lastTime = 0
const animateProgress = (currentTime) => {
if (!lastTime) lastTime = currentTime
const deltaTime = currentTime - lastTime
if (deltaTime >= PROGRESS_INTERVAL) {
value += PROGRESS_STEP
if (value >= targetRate) {
value = targetRate
progressWidth.value = value + '%'
return
}
progressWidth.value = value + '%'
lastTime = currentTime
}
requestAnimationFrame(animateProgress)
}
requestAnimationFrame(animateProgress)
}
// 初始化数据
onMounted(async () => {
// 获取数据
yearData.value = await fetchYearData()
// 计算完成率
const rate = ((yearData.value.actual / yearData.value.target) * 100).toFixed(2)
progressRate.value = rate
// 发射进度率事件
emit('progress-rate', parseFloat(rate))
// 延迟启动进度条动画
setTimeout(() => {
startProgressAnimation(parseFloat(rate))
}, 800)
})
</script>