246 lines
5.3 KiB
Vue
246 lines
5.3 KiB
Vue
<template>
|
||
<view class="sixdim-section">
|
||
<!-- 顶部图标 + 标题 -->
|
||
<!-- <view class="sixdim-bar">
|
||
<view class="sixdim-icon-grid">
|
||
<view v-for="n in 9" :key="n" class="sixdim-icon-dot"></view>
|
||
</view>
|
||
<text class="sixdim-bar-title">六维格局</text>
|
||
</view> -->
|
||
|
||
<!-- 卡片主体 -->
|
||
<view class="sixdim-card">
|
||
<view class="sixdim-info">
|
||
<view class="sixdim-info-icon">i</view>
|
||
</view>
|
||
|
||
<view class="sixdim-radar">
|
||
<!-- SVG 绘制六边形网格线 -->
|
||
<svg class="sixdim-radar-svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet">
|
||
|
||
|
||
<!-- 中圈六边形 -->
|
||
<polygon
|
||
points="50,22 78,36 78,64 50,78 22,64 22,36"
|
||
fill="none"
|
||
stroke="rgba(255, 255, 255, 0.4)"
|
||
stroke-width="0.8"
|
||
/>
|
||
|
||
</svg>
|
||
|
||
<view
|
||
v-for="(label, idx) in labels"
|
||
:key="idx"
|
||
class="sixdim-label"
|
||
:class="'sixdim-label-' + idx"
|
||
>
|
||
<text>{{ label }}</text>
|
||
</view>
|
||
|
||
<view class="sixdim-radar-fill" :style="fillStyle"></view>
|
||
</view>
|
||
|
||
<view class="sixdim-remark sixdim-remark-center">
|
||
<text class="sixdim-remark-label">大师的批注:</text>
|
||
<text class="sixdim-remark-text">{{ remark }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { computed } from 'vue';
|
||
|
||
interface Props {
|
||
labels: string[]; // 六维文字数组,如 ['事业', '财运', '健康', '家庭', '社交', '智慧']
|
||
values: number[]; // 六维数据数组,范围 0-100
|
||
remark: string; // 大师批注
|
||
}
|
||
|
||
const props = withDefaults(defineProps<Props>(), {
|
||
labels: () => ['事业', '财运', '健康', '家庭', '社交', '智慧'],
|
||
values: () => [100, 92, 86, 80, 75, 90],
|
||
remark: '此名天格人格地格配置上佳,主事业运亨通。水木相生,智慧超群,唯需注意社交圆融。'
|
||
});
|
||
|
||
// 根据 values 计算填充区域的 clip-path
|
||
// 六边形顶点位置(从顶部开始,顺时针):0°(上), 60°(右上), 120°(右下), 180°(下), 240°(左下), 300°(左上)
|
||
const fillStyle = computed(() => {
|
||
const maxValue = 100;
|
||
const centerX = 50; // 中心点 x 百分比
|
||
const centerY = 50; // 中心点 y 百分比
|
||
const baseRadius = 44; // 基础半径(从中心到外圈的百分比,约 44%)
|
||
|
||
// 计算每个维度的实际半径(0-100 映射到 0-baseRadius)
|
||
const points = props.values.map((value: number, idx: number) => {
|
||
const angle = (idx * 60 - 90) * (Math.PI / 180); // 转换为弧度,-90° 使顶部为起点
|
||
const radius = (value / maxValue) * baseRadius;
|
||
const x = centerX + radius * Math.cos(angle);
|
||
const y = centerY + radius * Math.sin(angle);
|
||
return { x, y };
|
||
});
|
||
|
||
// 生成 clip-path polygon 字符串
|
||
const path = points.map((p: { x: any; y: any; }) => `${p.x}% ${p.y}%`).join(', ');
|
||
return {
|
||
clipPath: `polygon(${path})`
|
||
};
|
||
});
|
||
</script>
|
||
|
||
<style scoped>
|
||
.sixdim-section {
|
||
margin-bottom: 64rpx;
|
||
}
|
||
|
||
.sixdim-bar {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12rpx;
|
||
margin-bottom: 24rpx;
|
||
padding: 0 8rpx;
|
||
}
|
||
|
||
.sixdim-icon-grid {
|
||
width: 28rpx;
|
||
height: 28rpx;
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
grid-template-rows: repeat(3, 1fr);
|
||
gap: 2rpx;
|
||
}
|
||
|
||
.sixdim-icon-dot {
|
||
width: 6rpx;
|
||
height: 6rpx;
|
||
border-radius: 2rpx;
|
||
background: #d4af37;
|
||
opacity: 0.85;
|
||
}
|
||
|
||
.sixdim-bar-title {
|
||
font-size: 24rpx;
|
||
font-weight: bold;
|
||
color: #e2e2e2;
|
||
letter-spacing: 0.24em;
|
||
}
|
||
|
||
.sixdim-card {
|
||
position: relative;
|
||
background: rgba(255, 255, 255, 0.05);
|
||
border-radius: 20rpx;
|
||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||
padding: 28rpx 24rpx 32rpx;
|
||
backdrop-filter: blur(12px);
|
||
overflow: hidden;
|
||
}
|
||
|
||
.sixdim-info {
|
||
position: absolute;
|
||
top: 16rpx;
|
||
right: 16rpx;
|
||
}
|
||
|
||
.sixdim-info-icon {
|
||
width: 28px;
|
||
height: 28px;
|
||
border-radius: 999rpx;
|
||
border: 1px solid rgba(255, 255, 255, 0.16);
|
||
color: rgba(255, 255, 255, 0.45);
|
||
font-size: 18px;
|
||
text-align: center;
|
||
line-height: 28rpx;
|
||
}
|
||
|
||
.sixdim-radar {
|
||
position: relative;
|
||
width: 100%;
|
||
max-width: 380rpx;
|
||
margin: 0 auto;
|
||
padding-top: 65%;
|
||
background: radial-gradient(circle at 50% 50%, rgba(255, 193, 7, 0.04), transparent 70%);
|
||
border-radius: 24rpx;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.sixdim-radar-svg {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
z-index: 3;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.sixdim-radar-fill {
|
||
position: absolute;
|
||
inset: 24%;
|
||
margin: auto;
|
||
background: linear-gradient(to bottom, rgba(255, 193, 7, 0.75), rgba(255, 87, 34, 0.55));
|
||
opacity: 0.85;
|
||
transition: clip-path 0.5s ease-out;
|
||
z-index: 2;
|
||
}
|
||
|
||
.sixdim-label {
|
||
position: absolute;
|
||
font-size: 20rpx;
|
||
color: #cfd2dc;
|
||
}
|
||
|
||
.sixdim-label-0 {
|
||
top: 6%;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
}
|
||
|
||
.sixdim-label-1 {
|
||
top: 26%;
|
||
right: 6%;
|
||
}
|
||
|
||
.sixdim-label-2 {
|
||
bottom: 28%;
|
||
right: 4%;
|
||
}
|
||
|
||
.sixdim-label-3 {
|
||
bottom: 4%;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
}
|
||
|
||
.sixdim-label-4 {
|
||
bottom: 28%;
|
||
left: 4%;
|
||
}
|
||
|
||
.sixdim-label-5 {
|
||
top: 26%;
|
||
left: 6%;
|
||
}
|
||
|
||
.sixdim-remark {
|
||
font-size: 20rpx;
|
||
line-height: 1.8;
|
||
color: #a0a4b8;
|
||
}
|
||
|
||
.sixdim-remark-center {
|
||
margin-top: 24rpx;
|
||
text-align: center;
|
||
padding: 0 24rpx;
|
||
}
|
||
|
||
.sixdim-remark-label {
|
||
color: #fdd835;
|
||
}
|
||
|
||
.sixdim-remark-text {
|
||
color: #c0c3d0;
|
||
}
|
||
</style>
|
||
|