feat(dashboard): LevelDistribution 5个conic-gradient环形图

This commit is contained in:
zheng020 2026-06-02 22:47:10 +08:00
parent e2555dc015
commit 1dbdcc5e20
2 changed files with 150 additions and 1 deletions

View File

@ -5,12 +5,16 @@
<!-- TOP 5 --> <!-- TOP 5 -->
<TopFiveAssets :items="topFive || []" /> <TopFiveAssets :items="topFive || []" />
<!-- 后续 Task 11/12 在此追加 LevelDistribution / UpcomingUpgrades / RecentUpgrades --> <!-- 等级分布 -->
<LevelDistribution :items="levels" />
<!-- 后续 Task 12 在此追加 UpcomingUpgrades / RecentUpgrades -->
</view> </view>
</template> </template>
<script setup> <script setup>
import TopFiveAssets from './TopFiveAssets.vue' import TopFiveAssets from './TopFiveAssets.vue'
import LevelDistribution from './LevelDistribution.vue'
defineProps({ defineProps({
topFive: { type: Array, default: () => [] }, topFive: { type: Array, default: () => [] },

View File

@ -0,0 +1,145 @@
<template>
<view class="level-distribution">
<text class="card-title">藏品等级分布</text>
<view v-if="!items || items.length === 0" class="empty-row">
<text class="empty-text">暂无数据</text>
</view>
<view v-else class="ring-row">
<view
v-for="item in items"
:key="item.level"
class="ring-cell"
>
<view
class="ring-outer"
:style="getRingStyle(item)"
>
<view class="ring-inner">
<text class="ring-count">{{ item.count }}</text>
</view>
</view>
<text class="ring-label">{{ item.level }}</text>
<text class="ring-pct">{{ getPercent(item) }}%</text>
</view>
</view>
</view>
</template>
<script setup>
const props = defineProps({
items: { type: Array, default: () => [] }, // AssetLevelItem[]
})
function getPercent(item) {
if (!item.total) return 0
return Math.round((item.count / item.total) * 100)
}
function getRingStyle(item) {
const pct = getPercent(item)
const colorMap = {
UR: '#FF8A65, #FFD740',
SSR: '#FF5E9C, #FFB199',
SR: '#B17BFF, #FF8FE6',
R: '#5EDFFF, #6FA9FF',
N: '#C5C5C5, #8C8C8C',
}
const colors = colorMap[item.level] || '#999, #ccc'
// 0
if (pct === 0) {
return {
background: 'conic-gradient(rgba(255,255,255,0.1) 0deg, rgba(255,255,255,0.1) 360deg)',
}
}
// pct%
return {
background: `conic-gradient(${colors} 0deg ${pct * 3.6}deg, rgba(255,255,255,0.1) ${pct * 3.6}deg 360deg)`,
}
}
</script>
<style lang="scss" scoped>
.level-distribution {
background: rgba(255, 255, 255, 0.1);
border-radius: 17rpx;
padding: 20rpx;
margin-top: 16rpx;
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.15);
}
.card-title {
display: block;
font-size: 28rpx;
font-weight: 600;
color: #ffffff;
margin-bottom: 16rpx;
}
.ring-row {
display: flex;
justify-content: space-around;
align-items: center;
padding: 16rpx 0;
}
.ring-cell {
display: flex;
flex-direction: column;
align-items: center;
flex: 1;
}
.ring-outer {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
position: relative;
box-shadow: 0 0 12px rgba(255, 255, 255, 0.15);
}
.ring-inner {
width: 60rpx;
height: 60rpx;
border-radius: 50%;
background: rgba(0, 0, 0, 0.3);
display: flex;
align-items: center;
justify-content: center;
backdrop-filter: blur(4px);
}
.ring-count {
font-size: 24rpx;
font-weight: 700;
color: #FFFABD;
font-family: 'Baloo Bhai', sans-serif;
}
.ring-label {
margin-top: 8rpx;
font-size: 20rpx;
font-weight: 600;
color: rgba(255, 255, 255, 0.9);
}
.ring-pct {
font-size: 18rpx;
color: rgba(255, 255, 255, 0.6);
margin-top: 2rpx;
}
.empty-row {
height: 120rpx;
display: flex;
align-items: center;
justify-content: center;
}
.empty-text {
color: rgba(255, 255, 255, 0.5);
font-size: 24rpx;
}
</style>