220 lines
5.8 KiB
Vue
220 lines
5.8 KiB
Vue
<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-shadow(canvas 不支持)
|
||
.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>
|