upload project source code

This commit is contained in:
2026-04-30 18:49:43 +08:00
commit 9b394ba682
2277 changed files with 660945 additions and 0 deletions

View File

@@ -0,0 +1,255 @@
<template>
<view class="sixdim-section">
<view class="sixdim-card">
<view class="sixdim-info">
<view class="sixdim-info-icon">i</view>
</view>
<!-- 电脑端雷达图ECharts 渲染 -->
<view class="sixdim-radar">
<view ref="chartRef" class="sixdim-echart-inner" />
</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 { onMounted, onUnmounted, ref, watch } from "vue";
import * as echarts from "echarts";
interface Props {
labels: string[];
values: number[];
remark: string;
}
const props = defineProps<Props>();
const chartRef = ref<HTMLElement | null>(null);
let chart: echarts.ECharts | null = null;
const getSafeValues = (vals: number[]) => (Array.isArray(vals) ? vals.map((v) => (Number.isFinite(v as any) ? Number(v) : 0)) : []);
const getSafeLabels = (labs: string[]) => (Array.isArray(labs) ? labs.map((s) => String(s ?? "")) : []);
/** 雷达图 indicator 与 value 必须等长且非空,否则 ECharts radarLayout 会报 push undefined */
function alignRadarData(rawLabels: string[], rawValues: number[]): { labels: string[]; values: number[] } {
let labels = getSafeLabels(rawLabels).map((s) => s.trim());
let values = getSafeValues(rawValues);
let n = Math.max(labels.length, values.length);
// 个人测名默认六维:事业、财运、健康、家庭、社交、智慧
const defaultSix = ["事业", "财运", "健康", "家庭", "社交", "智慧"];
if (n === 0) {
labels = defaultSix;
values = [0, 0, 0, 0, 0, 0];
n = 6;
} else if (n <= 6) {
// 不足 6 维时,补足到 6 维并强制使用默认中文维度,确保「家庭」等字段一定出现
n = 6;
while (values.length < n) values.push(0);
labels = defaultSix;
} else {
while (labels.length < n) labels.push(`维度${labels.length + 1}`);
while (values.length < n) values.push(0);
labels = labels.slice(0, n);
values = values.slice(0, n);
}
// 再次截断到 n防御性处理
labels = labels.slice(0, n).map((s) => s || "—");
values = values.slice(0, n);
return { labels, values };
}
const buildOption = () => {
const { labels, values } = alignRadarData(props.labels, props.values);
const radarIndicator = labels.map((name) => ({ name: name || "—", max: 100 }));
return {
animationDuration: 700,
animationEasing: "cubicOut" as any,
tooltip: {
trigger: "item",
formatter: (params: any) => {
const valueArr: number[] = params?.value ?? [];
const parts = labels.map((lab, idx) => `${lab}${valueArr[idx] ?? 0}`);
return parts.join("<br/>");
},
},
radar: {
indicator: radarIndicator,
splitNumber: 4,
shape: "polygon",
center: ["50%", "48%"],
// 轴文字可能在较小容器内被裁切:适当缩小半径,让 label 落在视窗内
radius: "62%",
axisName: {
color: "rgba(207, 210, 220, 0.88)",
fontSize: 9,
padding: 6,
},
axisLine: {
lineStyle: {
color: "rgba(212, 220, 236, 0.32)",
width: 1,
},
},
splitLine: {
lineStyle: {
color: "rgba(255, 255, 255, 0.12)",
width: 1,
},
},
splitArea: {
areaStyle: {
color: ["rgba(255, 255, 255, 0.02)", "rgba(255, 193, 7, 0.015)"],
},
},
},
series: [
{
type: "radar",
data: [
{
value: [...values],
},
],
lineStyle: {
color: "rgba(255, 193, 7, 0.92)",
width: 2,
},
itemStyle: {
color: "rgba(255, 193, 7, 0.95)",
},
symbol: "circle",
symbolSize: 3,
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: "rgba(255, 193, 7, 0.78)" },
{ offset: 1, color: "rgba(243, 138, 43, 0.52)" },
]),
opacity: 0.95,
},
},
],
// 包含所有轴文字(避免 label 在容器内被裁切)
grid: { containLabel: true },
};
};
const render = () => {
if (!chartRef.value) return;
if (!chart) {
// 使用 svg 渲染器,避免 canvas getContext 在某些环境出错
chart = echarts.init(chartRef.value, undefined, { renderer: "svg" });
}
chart.setOption(buildOption(), { notMerge: true, lazyUpdate: true });
};
onMounted(() => {
render();
// 适配父容器缩放(桌面布局下尤其必要)
const onResize = () => chart?.resize();
window.addEventListener("resize", onResize);
onUnmounted(() => window.removeEventListener("resize", onResize));
});
watch(
() => [props.labels, props.values],
() => {
render();
},
{ deep: true }
);
onUnmounted(() => {
if (chart) {
chart.dispose();
chart = null;
}
});
</script>
<style scoped>
.sixdim-section {
margin-bottom: 64rpx;
}
.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: 16px;
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;
}
.sixdim-radar {
position: relative;
width: 100%;
max-width: 380rpx;
margin: 0 auto;
padding-top: 0;
background: radial-gradient(circle at 50% 50%, rgba(255, 193, 7, 0.04), transparent 70%);
border-radius: 24rpx;
height: 280px;
display: flex;
align-items: center;
justify-content: center;
}
.sixdim-echart-inner {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
top: 0;
}
.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>