topfans/frontend/pages/dashboard/components/LevelDistribution.vue

220 lines
5.8 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.

<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-chart">
<qiun-data-charts
type="arcbar"
:opts="getOpts(item)"
:chartData="getChartData(item)"
:canvasId="`arcbar-${item.level}`"
:canvas2d="false"
:ontouch="false"
:in-scroll-view="true"
:tooltipShow="false"
/>
<!--
中心数字用 HTML 覆盖层而非 ucharts title
ucharts canvas 文本fillText不支持 text-shadow
覆盖层可以走 CSS text-shadow。
-->
<view class="ring-center" pointer-events="none">
<text class="ring-count">{{ item.count }}</text>
<text class="ring-count ring-text">{{ getPercent(item) }}%</text>
<image
class="ring-label-img"
:src="getGradeBadge(item.level)"
mode="aspectFit"
/>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import QiunDataCharts from "@/uni_modules/qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue";
const props = defineProps({
items: { type: Array, default: () => [] }, // AssetLevelItem[]
});
// 等级 → 渐变色(左→右),与原 conic-gradient 配色保持一致
const COLOR_MAP = {
UR: { start: "#FF9C84", end: "#88F4EB" },
SSR: { start: "#FF6640", end: "#B5F488" },
SR: { start: "#DFFF5E", end: "#F48896" },
R: { start: "#8FA9FF", end: "#4FFFF0" },
N: { start: "#C5C5C5", end: "#8C8C8C" },
};
// 等级徽章图片映射item.level 是字符串 ('UR'/'SSR'/'SR'/'R'/'N')
// 注意 UR 的文件名是 URengji.png没有 d与其他不同
const GRADE_BADGE_MAP = {
N: "/static/starbookcontent/grade/Ndengji.png",
R: "/static/starbookcontent/grade/Rdengji.png",
SR: "/static/starbookcontent/grade/SRdengji.png",
SSR: "/static/starbookcontent/grade/SSRdengji.png",
UR: "/static/starbookcontent/grade/URengji.png",
};
const getGradeBadge = (level) => GRADE_BADGE_MAP[level] || GRADE_BADGE_MAP.N;
function getPercent(item) {
if (!item.total) return 0;
return Math.round((item.count / item.total) * 100);
}
function getChartData(item) {
const pct = getPercent(item);
return {
series: [
{
name: item.level,
color: COLOR_MAP[item.level]?.start || "#999",
data: pct / 100,
},
],
};
}
function getOpts(item) {
const colors = COLOR_MAP[item.level] || { start: "#999", end: "#ccc" };
return {
color: [colors.start],
padding: [0, 0, 0, 0],
dataLabel: false,
legend: { show: false },
title: {
// 中心数字改由 .ring-center 覆盖层渲染(支持 text-shadow这里关掉
name: "",
fontSize: 0,
color: "transparent",
},
subtitle: {
name: "",
fontSize: 0,
color: "transparent",
},
extra: {
arcbar: {
// 'default' 走 u-charts.js 的 if 分支:背景只画 startAngle→endAngle 范围,
// 留下底部 90° 缺口(典型"圆弧进度条"造型)
type: "default",
width: 5,
// [PATCH] 背景改由 u-charts.js 内的 backgroundLinearType 接管,
// backgroundColor 留空字符串避免重复描边
backgroundColor: "",
// 背景渐变:对应 CSS linear-gradient(36.72deg, rgba(199,244,255,.45) 13.45%, rgba(233,193,255,.45) 79.47%)
backgroundLinearType: "custom",
backgroundLinearAngle: 36.72,
backgroundLinearColor: [
[0.1345, "rgba(199, 244, 255, 0.45)"],
[0.7947, "rgba(233, 193, 255, 0.45)"],
],
startAngle: 0.75, // 12 点钟
endAngle: 0.25, // 6 点钟(顺时针走 3/4 圈)
gap: 0,
// 进度条渐变fillColor = linear-gradient(left=color, right=customColor[0])
linearType: "custom",
customColor: [colors.end],
},
},
};
}
</script>
<style lang="scss" scoped>
.level-distribution {
background: rgba(121, 120, 215, 0.31);
border-radius: 17rpx;
padding: 20rpx;
margin-top: 16rpx;
box-shadow: 0px 4px 4px 0px rgba(96, 13, 13, 0.25);
}
.card-title {
display: block;
font-size: 24rpx;
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-chart {
width: 112rpx;
height: 112rpx;
position: relative;
display: flex;
align-items: center;
justify-content: center;
// 原 conic-gradient 版本的环外发光改由容器兜住canvas 透明区域也能看到
filter: drop-shadow(0 0 12rpx rgba(255, 255, 255, 0.15));
}
// 中心数字覆盖层HTML 文本支持 text-shadowcanvas 不支持)
.ring-center {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
z-index: 1;
flex-direction: column;
}
.ring-count {
font-size: 18rpx;
font-weight: 700;
font-family: "Baloo Bhai", sans-serif;
line-height: 1;
color: rgba(255, 241, 163, 1);
text-shadow: -1px 1px 4px rgba(206, 9, 9, 0.84);
}
.ring-text{
margin: 8rpx 0;
}
.ring-label-img {
width: 40rpx;
height: 40rpx;
margin-top: 4rpx;
position: absolute;
bottom: -8rpx;
}
.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>