167 lines
4.4 KiB
Vue
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>
|