zhxy-jsd/src/pages/view/homeSchool/ChengJiFenXi.vue

320 lines
8.4 KiB
Vue
Raw Normal View History

2025-04-22 10:22:33 +08:00
<template>
<BasicLayout :show-nav-bar="true" :nav-bar-props="{ title: '成绩分析' }">
2025-07-30 01:02:14 +08:00
<view class="cjfx-page">
<!-- 1. 班级选择器 -->
<CjBjPicker v-model="xzbjId" @change="onBjChange" />
<!-- 2. 考试场次选择器 -->
<CjKsccPicker v-model="xzksccId" :bj-id="xzbjId" @change="onKsccChange" />
<view v-if="xzbjId && xzksccId">
<!-- 3. 科目选择Tabs (当选择了考试场次后显示) -->
<view class="km-xz-section" v-if="xzksccId && ksccKmLb.length > 0">
<view class="km-xz-tabs">
<scroll-view
scroll-x="true"
class="scroll-view-h"
:show-scrollbar="false"
2025-04-22 10:22:33 +08:00
>
2025-07-30 01:02:14 +08:00
<view
class="tab-item"
v-for="km in ksccKmLb"
:key="km.id"
:class="{ active: xzkmId === km.id }"
@click="selectKm(km.id)"
2025-04-22 10:22:33 +08:00
>
2025-07-30 01:02:14 +08:00
<text>{{ km.kmmc }}</text>
</view>
</scroll-view>
2025-04-22 10:22:33 +08:00
</view>
</view>
2025-07-30 01:02:14 +08:00
<view v-if="xzkmId">
<!-- 4. 本班学生成绩列表 -->
<CjBjXsList :xs-cj-lb="xsCjLb" />
<!-- 5. 班级统计概览 -->
<CjBjTjGl :tjgl-data="tjglData" />
<!-- 6. 本班与年级平均分对比分析图表 -->
<CjBjNjPjf
: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"
2025-04-22 10:22:33 +08:00
/>
2025-07-30 01:02:14 +08:00
<!-- 7. 总分分数段图表 -->
<CjZfFs :fs-duan-lb="fsDuanLb" />
<!-- 8. 总分等级段图表 -->
<CjZfDj :dj-duan-lb="djDuanLb" />
2025-04-22 10:22:33 +08:00
</view>
2025-07-30 01:02:14 +08:00
</view>
2025-04-22 10:22:33 +08:00
</view>
</BasicLayout>
</template>
<script lang="ts" setup>
2025-07-30 01:02:14 +08:00
import { jsdBjKscjKmApi, ksccKmFindByKsccIdApi } from "@/api/base/server";
import { onMounted, ref } from "vue";
import CjBjNjPjf from "./components/CjBjNjPjf.vue";
import CjBjPicker from "./components/CjBjPicker.vue";
import CjBjTjGl from "./components/CjBjTjGl.vue";
import CjBjXsList from "./components/CjBjXsList.vue";
import CjKsccPicker from "./components/CjKsccPicker.vue";
import CjZfDj from "./components/CjZfDj.vue";
import CjZfFs from "./components/CjZfFs.vue";
// --- Emits ---
const emit = defineEmits(["kmDataChange"]);
2025-04-22 10:22:33 +08:00
// --- Interfaces ---
2025-07-30 01:02:14 +08:00
interface KsccKm {
id: string | number;
kmmc: string;
kmfs: number;
}
interface XsCj {
id: string | number;
name: string;
score: number;
bjpm: number;
}
interface TjglData {
bjrs: number;
njpjzf: number;
bjpjf: number;
njzgf: number;
ysl: number;
bjzgf: number;
ysrs: number;
jgl: number;
jgrs: number;
}
interface FsDuan {
name: string;
value: number;
color: string;
}
interface DjDuan {
name: string;
value: number;
color: string;
}
interface BjPjInfo {
bjId: string;
bjmc: string;
njmc: string;
fs: number;
}
2025-04-22 10:22:33 +08:00
// --- Static Mock Data ---
2025-07-30 01:02:14 +08:00
const staticFsDuanLb: FsDuan[] = [
{ 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" },
2025-04-22 10:22:33 +08:00
];
2025-07-30 01:02:14 +08:00
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" },
2025-04-22 10:22:33 +08:00
];
// --- State ---
2025-07-30 01:02:14 +08:00
const xzbjId = ref<string | number | null>(null);
const xzksccId = ref<string | number | null>(null);
const xzkmId = ref<string | number | null>(null);
const ksccKmLb = ref<KsccKm[]>([]);
const xsCjLb = ref<XsCj[]>([]);
const tjglData = ref<TjglData>({
bjrs: 0,
njpjzf: 0,
bjpjf: 0,
njzgf: 0,
ysl: 0,
bjzgf: 0,
ysrs: 0,
jgl: 0,
jgrs: 0,
});
const fsDuanLb = ref<FsDuan[]>([...staticFsDuanLb]);
const djDuanLb = ref<DjDuan[]>([...staticDjDuanLb]);
const bjPjList = ref<BjPjInfo[]>([]);
// --- API Functions ---
const getKsccKmLb = async (ksccId: string | number) => {
try {
const res = await ksccKmFindByKsccIdApi({
ksccId,
});
if (res && res.resultCode === 1 && res.result) {
ksccKmLb.value = res.result.map((km: any) => ({
id: km.id,
kmmc: km.kmmc,
kmfs: 100, // 默认分数,实际应该从后端获取
}));
console.log("获取科目列表成功:", ksccKmLb.value);
// 默认选择第一个科目
if (ksccKmLb.value.length > 0) {
xzkmId.value = ksccKmLb.value[0].id;
// 获取该科目的成绩数据
await getBjKscjKmData(xzbjId.value!, ksccId, ksccKmLb.value[0].id);
}
}
} catch (error) {
console.error("获取科目列表失败:", error);
}
};
2025-04-22 10:22:33 +08:00
2025-07-30 01:02:14 +08:00
const getBjKscjKmData = async (
bjId: string | number,
ksccId: string | number,
kmId: string | number
) => {
try {
const res = await jsdBjKscjKmApi({ bjId, ksccId, kmId });
if (res && res.resultCode === 1 && res.result) {
// 处理学生成绩数据
const ksccKscjList = res.result.ksccKscjList || [];
xsCjLb.value = ksccKscjList.map((cj: any) => ({
id: cj.xsId,
name: cj.xsxm || cj.xm || "未知学生",
score: cj.ksfs || 0,
bjpm: cj.bjpm || 0, // 使用后端返回的班级排名
}));
// 处理统计数据
tjglData.value.bjrs = res.result.bjRs || 0;
tjglData.value.bjpjf = res.result.bjPjf || 0;
tjglData.value.njpjzf = res.result.njPjf || 0;
tjglData.value.bjzgf = res.result.bjZgf || 0;
tjglData.value.njzgf = res.result.njZgf || 0;
tjglData.value.ysrs = res.result.ysRs || 0;
tjglData.value.jgrs = res.result.jgRs || 0;
tjglData.value.ysl = res.result.ysl || 0;
tjglData.value.jgl = res.result.jgl || 0;
// 处理班级平均分列表数据传递给CjBjNjPjf组件
bjPjList.value = res.result.bjPjList || [];
console.log("获取班级科目成绩数据成功:", res.result);
}
} catch (error) {
console.error("获取班级科目成绩数据失败:", error);
}
};
2025-04-22 10:22:33 +08:00
// --- Event Handlers ---
2025-07-30 01:02:14 +08:00
const onBjChange = async (bjId: string | number | null, bjInfo: any | null) => {
xzbjId.value = bjId;
xzksccId.value = null; // 重置考试场次选择
xzkmId.value = null; // 重置科目选择
ksccKmLb.value = []; // 清空科目列表
2025-04-22 10:22:33 +08:00
2025-07-30 01:02:14 +08:00
console.log(`切换到班级: ${bjId}, 班级名称: ${bjInfo?.name}`);
2025-04-22 10:22:33 +08:00
};
2025-07-30 01:02:14 +08:00
const onKsccChange = async (
ksccId: string | number | null,
ksccInfo: any | null
2025-04-22 10:22:33 +08:00
) => {
2025-07-30 01:02:14 +08:00
xzksccId.value = ksccId;
xzkmId.value = null; // 重置科目选择
2025-04-22 10:22:33 +08:00
2025-07-30 01:02:14 +08:00
console.log(`切换到考试场次: ${ksccId}, 考试名称: ${ksccInfo?.name}`);
2025-04-22 10:22:33 +08:00
2025-07-30 01:02:14 +08:00
if (ksccId) {
// 获取该考试场次的科目列表
await getKsccKmLb(ksccId);
} else {
ksccKmLb.value = [];
2025-04-22 10:22:33 +08:00
}
};
2025-07-30 01:02:14 +08:00
const selectKm = async (kmId: string | number) => {
xzkmId.value = kmId;
console.log(`选中科目: ${kmId}`);
// 获取该科目的详细数据
if (xzbjId.value && xzksccId.value) {
await getBjKscjKmData(xzbjId.value, xzksccId.value, kmId);
2025-04-22 10:22:33 +08:00
}
};
2025-07-30 01:02:14 +08:00
const onKmChange = (kmId: string | number | null, km: any) => {
console.log(`科目变化: ${kmId}, 科目信息:`, km);
// 处理科目变化逻辑
2025-04-22 10:22:33 +08:00
};
2025-07-30 01:02:14 +08:00
// --- Lifecycle ---
onMounted(async () => {
console.log("成绩分析页面初始化完成");
2025-04-22 10:22:33 +08:00
});
</script>
<style scoped lang="scss">
2025-07-30 01:02:14 +08:00
.cjfx-page {
2025-04-22 10:22:33 +08:00
background-color: #f4f5f7;
min-height: calc(100vh - var(--window-top));
padding-bottom: 20rpx;
}
2025-07-30 01:02:14 +08:00
.km-xz-section {
2025-04-22 10:22:33 +08:00
background-color: #ffffff;
2025-07-30 01:02:14 +08:00
padding: 0;
2025-04-22 10:22:33 +08:00
2025-07-30 01:02:14 +08:00
.km-xz-tabs {
padding: 0;
2025-04-22 10:22:33 +08:00
2025-07-30 01:02:14 +08:00
.scroll-view-h {
white-space: nowrap;
width: 100%;
height: 80rpx;
line-height: 80rpx;
border-bottom: 1rpx solid #f0f0f0;
2025-04-22 10:22:33 +08:00
}
2025-07-30 01:02:14 +08:00
.tab-item {
display: inline-block;
padding: 0 30rpx;
font-size: 28rpx;
color: #666;
position: relative;
2025-04-22 10:22:33 +08:00
text-align: center;
2025-07-30 01:02:14 +08:00
height: 100%;
&.active {
color: #447ade;
font-weight: bold;
&::after {
content: "";
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 40%;
height: 6rpx;
background-color: #447ade;
border-radius: 3rpx;
2025-04-22 10:22:33 +08:00
}
}
}
}
}
</style>