调整成绩分析

This commit is contained in:
ywyonui 2025-07-30 12:53:33 +08:00
parent 63eca2a0ea
commit 67ab505da5
4 changed files with 222 additions and 59 deletions

View File

@ -37,26 +37,13 @@
<CjBjTjGl :tjgl-data="tjglData" /> <CjBjTjGl :tjgl-data="tjglData" />
<!-- 6. 本班与年级平均分对比分析图表 --> <!-- 6. 本班与年级平均分对比分析图表 -->
<CjBjNjPjf <CjBjNjPjf v-model:selected-km-id="xzkmId" :bj-pj-list="bjPjList" />
:km-lb="
ksccKmLb.map((km) => ({
id: km.id,
name: km.kmmc,
kmmc: km.kmmc,
}))
"
v-model:selected-km-id="xzkmId"
:bj-pj-list="bjPjList"
:bj-pjf="tjglData.bjpjf"
:nj-pjf="tjglData.njpjzf"
@change="onKmChange"
/>
<!-- 7. 总分分数段图表 --> <!-- 7. 总分分数段图表 -->
<CjZfFs :fs-duan-lb="fsDuanLb" /> <CjZfFs :dj-rs-list="djRsList" />
<!-- 8. 总分等级段图表 --> <!-- 8. 总分等级段图表 -->
<CjZfDj :dj-duan-lb="djDuanLb" /> <CjZfDj :dj-rs-list="djRsList" />
</view> </view>
</view> </view>
</view> </view>
@ -116,22 +103,15 @@ interface BjPjInfo {
njmc: string; njmc: string;
fs: number; fs: number;
} }
interface DjRsInfo {
dj: string;
rs: number;
zgf: string;
zdf: string;
}
// --- Static Mock Data --- // --- Static Mock Data ---
const staticFsDuanLb: FsDuan[] = [ // 使 djRsList
{ name: "240-269", value: 5, color: "#1890ff" },
{ name: "210-239", value: 12, color: "#2fc25b" },
{ name: "180-210", value: 18, color: "#facc14" },
{ name: "180以下", value: 10, color: "#f04864" },
];
const staticDjDuanLb: DjDuan[] = [
{ name: "A", value: 5, color: "#1890ff" },
{ name: "B", value: 15, color: "#2fc25b" },
{ name: "C", value: 18, color: "#facc14" },
{ name: "D", value: 10, color: "#f04864" },
{ name: "E", value: 2, color: "#999999" },
];
// --- State --- // --- State ---
const xzbjId = ref<string | number | null>(null); const xzbjId = ref<string | number | null>(null);
@ -150,9 +130,8 @@ const tjglData = ref<TjglData>({
jgl: 0, jgl: 0,
jgrs: 0, jgrs: 0,
}); });
const fsDuanLb = ref<FsDuan[]>([...staticFsDuanLb]);
const djDuanLb = ref<DjDuan[]>([...staticDjDuanLb]);
const bjPjList = ref<BjPjInfo[]>([]); const bjPjList = ref<BjPjInfo[]>([]);
const djRsList = ref<DjRsInfo[]>([]);
// --- API Functions --- // --- API Functions ---
const getKsccKmLb = async (ksccId: string | number) => { const getKsccKmLb = async (ksccId: string | number) => {
@ -197,6 +176,7 @@ const getBjKscjKmData = async (
score: cj.ksfs || 0, score: cj.ksfs || 0,
bjpm: cj.bjpm || 0, // 使 bjpm: cj.bjpm || 0, // 使
})); }));
console.log("学生成绩列表:", xsCjLb.value);
// //
tjglData.value.bjrs = res.result.bjRs || 0; tjglData.value.bjrs = res.result.bjRs || 0;
@ -211,7 +191,12 @@ const getBjKscjKmData = async (
// CjBjNjPjf // CjBjNjPjf
bjPjList.value = res.result.bjPjList || []; bjPjList.value = res.result.bjPjList || [];
// CjZfFsCjZfDj
djRsList.value = res.result.djRsList || [];
console.log("获取班级科目成绩数据成功:", res.result); console.log("获取班级科目成绩数据成功:", res.result);
console.log("等级人数列表:", djRsList.value);
} }
} catch (error) { } catch (error) {
console.error("获取班级科目成绩数据失败:", error); console.error("获取班级科目成绩数据失败:", error);
@ -316,4 +301,24 @@ onMounted(async () => {
} }
} }
} }
.debug-info {
background-color: #f0f0f0;
padding: 20rpx;
margin-top: 20rpx;
border-radius: 10rpx;
.debug-title {
font-size: 32rpx;
font-weight: bold;
margin-bottom: 10rpx;
text-align: center;
}
.debug-item {
font-size: 28rpx;
color: #333;
margin-bottom: 5rpx;
}
}
</style> </style>

View File

@ -13,18 +13,26 @@
<view class="th">班级排名</view> <view class="th">班级排名</view>
</view> </view>
<view class="bg-body"> <view class="bg-body">
<view class="bg-row" v-for="xs in xsCjLb" :key="xs.id"> <view class="bg-row" v-for="xs in displayList" :key="xs.id">
<view class="td">{{ xs.name }}</view> <view class="td">{{ xs.name }}</view>
<view class="td">{{ xs.score }}</view> <view class="td">{{ xs.score }}</view>
<view class="td">{{ xs.bjpm }}</view> <view class="td">{{ xs.bjpm }}</view>
</view> </view>
<view v-if="!xsCjLb.length" class="bg-empty"> 暂无数据 </view> <view v-if="!xsCjLb.length" class="bg-empty"> 暂无数据 </view>
</view> </view>
<view
v-if="xsCjLb.length > 5"
class="expand-btn-wrap"
@click="toggleExpand"
>
{{ expanded ? "收拢" : "展开全部" }}
</view>
</view> </view>
</uni-section> </uni-section>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, ref } from "vue";
// --- Interfaces --- // --- Interfaces ---
interface XsCj { interface XsCj {
id: string | number; id: string | number;
@ -47,6 +55,22 @@ const props = withDefaults(defineProps<Props>(), {
{ id: "st-5", name: "孙七", score: 85, bjpm: 8 }, { id: "st-5", name: "孙七", score: 85, bjpm: 8 },
], ],
}); });
// /
const expanded = ref(false);
//
const displayList = computed(() => {
if (expanded.value) {
return props.xsCjLb;
}
return props.xsCjLb.slice(0, 5);
});
// /
function toggleExpand() {
expanded.value = !expanded.value;
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@ -100,5 +124,15 @@ const props = withDefaults(defineProps<Props>(), {
padding: 40rpx 0; padding: 40rpx 0;
} }
} }
.expand-btn-wrap {
display: flex;
justify-content: center;
padding: 16rpx 10rpx;
text-align: center;
background: #fff;
color: #1890ff;
border-top: 1rpx solid #f0f0f0;
}
} }
</style> </style>

View File

@ -12,8 +12,9 @@
id="GradeAnalysisAreaChart" id="GradeAnalysisAreaChart"
class="charts" class="charts"
/> />
<view v-if="isLoading" class="tb-placeholder"> <view v-if="isLoading" class="tb-placeholder"> 图表加载中... </view>
图表加载中或无数据... <view v-else-if="!hasValidData" class="tb-placeholder">
暂无等级段数据
</view> </view>
</view> </view>
</uni-section> </uni-section>
@ -21,7 +22,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import uCharts from "@/components/charts/u-charts.js"; import uCharts from "@/components/charts/u-charts.js";
import { nextTick, onMounted, ref } from "vue"; import { computed, nextTick, onMounted, ref, watch } from "vue";
import { areaOption } from "./cj.data"; import { areaOption } from "./cj.data";
// --- Interfaces --- // --- Interfaces ---
@ -31,26 +32,72 @@ interface DjDuan {
color: string; color: string;
} }
interface DjRsInfo {
dj: string;
rs: number;
zgf: string;
zdf: string;
}
// --- Props --- // --- Props ---
interface Props { interface Props {
djDuanLb?: DjDuan[]; djRsList?: DjRsInfo[];
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
djDuanLb: () => [ djRsList: () => [],
{ name: "A", value: 5, color: "#1890ff" },
{ name: "B", value: 15, color: "#2fc25b" },
{ name: "C", value: 18, color: "#facc14" },
{ name: "D", value: 10, color: "#f04864" },
{ name: "E", value: 2, color: "#999999" },
],
}); });
// --- State --- // --- State ---
const isLoading = ref(false); const isLoading = ref(false);
// --- Computed ---
const hasValidData = computed(() => {
return (
props.djRsList &&
props.djRsList.length > 0 &&
props.djRsList.some((item) => item.rs > 0)
);
});
const processedData = computed(() => {
if (!props.djRsList || props.djRsList.length === 0) {
return [];
}
//
const djColorMap: { [key: string]: string } = {
A: "#1890ff",
B: "#2fc25b",
C: "#facc14",
D: "#f04864",
E: "#999999",
};
// 0
return props.djRsList
.filter((item) => item.rs > 0)
.map((item) => ({
name: item.dj, // 使 dj
value: item.rs,
color: djColorMap[item.dj] || "#666666", //
}))
.sort((a, b) => {
// A > B > C > D > E
const levelOrder = { A: 5, B: 4, C: 3, D: 2, E: 1 };
const aLevel = levelOrder[a.name as keyof typeof levelOrder] || 0;
const bLevel = levelOrder[b.name as keyof typeof levelOrder] || 0;
return bLevel - aLevel; //
});
});
// --- --- // --- ---
const drawAreaChart = () => { const drawAreaChart = () => {
if (!hasValidData.value) {
console.log("没有有效的等级段数据");
return;
}
isLoading.value = true; isLoading.value = true;
setTimeout(() => { setTimeout(() => {
@ -73,11 +120,11 @@ const drawAreaChart = () => {
const ctx = uni.createCanvasContext("GradeAnalysisAreaChart"); const ctx = uni.createCanvasContext("GradeAnalysisAreaChart");
const areaData = { const areaData = {
categories: props.djDuanLb.map((item) => item.name), categories: processedData.value.map((item) => item.name),
series: [ series: [
{ {
name: "人数", name: "人数",
data: props.djDuanLb.map((item) => item.value), data: processedData.value.map((item) => item.value),
color: "#1890ff", color: "#1890ff",
}, },
], ],
@ -120,6 +167,7 @@ const drawAreaChart = () => {
} }
console.log("图表数据:", areaData); console.log("图表数据:", areaData);
console.log("处理后的等级段数据:", processedData.value);
try { try {
new uCharts(newOption); new uCharts(newOption);
@ -141,9 +189,23 @@ const drawAreaChart = () => {
}, 500); }, 500);
}; };
// --- Watchers ---
watch(
() => props.djRsList,
() => {
console.log("等级段数据变化:", props.djRsList);
if (hasValidData.value) {
drawAreaChart();
}
},
{ deep: true }
);
// --- Lifecycle --- // --- Lifecycle ---
onMounted(() => { onMounted(() => {
drawAreaChart(); if (hasValidData.value) {
drawAreaChart();
}
}); });
</script> </script>

View File

@ -12,8 +12,9 @@
id="GradeAnalysisDonutChart" id="GradeAnalysisDonutChart"
class="charts" class="charts"
/> />
<view v-if="isLoading" class="tb-placeholder"> <view v-if="isLoading" class="tb-placeholder"> 图表加载中... </view>
图表加载中或无数据... <view v-else-if="!hasValidData" class="tb-placeholder">
暂无分数段数据
</view> </view>
</view> </view>
</uni-section> </uni-section>
@ -21,7 +22,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import uCharts from "@/components/charts/u-charts.js"; import uCharts from "@/components/charts/u-charts.js";
import { nextTick, onMounted, ref } from "vue"; import { computed, nextTick, onMounted, ref, watch } from "vue";
import { ringOption } from "./cj.data"; import { ringOption } from "./cj.data";
// --- Interfaces --- // --- Interfaces ---
@ -31,25 +32,71 @@ interface FsDuan {
color: string; color: string;
} }
interface DjRsInfo {
dj: string;
rs: number;
zgf: string;
zdf: string;
}
// --- Props --- // --- Props ---
interface Props { interface Props {
fsDuanLb?: FsDuan[]; djRsList?: DjRsInfo[];
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
fsDuanLb: () => [ djRsList: () => [],
{ name: "240-269", value: 5, color: "#1890ff" },
{ name: "210-239", value: 12, color: "#2fc25b" },
{ name: "180-210", value: 18, color: "#facc14" },
{ name: "180以下", value: 10, color: "#f04864" },
],
}); });
// --- State --- // --- State ---
const isLoading = ref(false); const isLoading = ref(false);
// --- Computed ---
const hasValidData = computed(() => {
return (
props.djRsList &&
props.djRsList.length > 0 &&
props.djRsList.some((item) => item.rs > 0)
);
});
const processedData = computed(() => {
if (!props.djRsList || props.djRsList.length === 0) {
return [];
}
//
const djColorMap: { [key: string]: string } = {
A: "#1890ff",
B: "#2fc25b",
C: "#facc14",
D: "#f04864",
E: "#999999",
};
// 0
return props.djRsList
.filter((item) => item.rs > 0)
.map((item) => ({
name: `${item.zdf}-${item.zgf}`, // 使 zdf-zgf
value: item.rs,
color: djColorMap[item.dj] || "#666666", //
}))
.sort((a, b) => {
// "-"
const aNum = parseFloat(a.name.split("-")[0] || "0");
const bNum = parseFloat(b.name.split("-")[0] || "0");
return bNum - aNum; //
});
});
// --- --- // --- ---
const drawDonutChart = () => { const drawDonutChart = () => {
if (!hasValidData.value) {
console.log("没有有效的分数段数据");
return;
}
isLoading.value = true; isLoading.value = true;
setTimeout(() => { setTimeout(() => {
@ -75,7 +122,7 @@ const drawDonutChart = () => {
series: [ series: [
{ {
name: "总分分数段", name: "总分分数段",
data: props.fsDuanLb, data: processedData.value,
}, },
], ],
}; };
@ -110,6 +157,7 @@ const drawDonutChart = () => {
} }
console.log("图表数据:", donutData); console.log("图表数据:", donutData);
console.log("处理后的分数段数据:", processedData.value);
try { try {
new uCharts(newOption); new uCharts(newOption);
@ -131,9 +179,23 @@ const drawDonutChart = () => {
}, 500); }, 500);
}; };
// --- Watchers ---
watch(
() => props.djRsList,
() => {
console.log("分数段数据变化:", props.djRsList);
if (hasValidData.value) {
drawDonutChart();
}
},
{ deep: true }
);
// --- Lifecycle --- // --- Lifecycle ---
onMounted(() => { onMounted(() => {
drawDonutChart(); if (hasValidData.value) {
drawDonutChart();
}
}); });
</script> </script>