feat: 🎸 新增了几处加载

This commit is contained in:
2025-08-26 11:27:09 +08:00
parent f4aac0e51e
commit 4d92976911
7 changed files with 181 additions and 192 deletions

View File

@@ -23,6 +23,11 @@
color: #262626;
}
.module-class-rank-spin,
.empty-data {
margin: auto;
}
.module-class-rank-podium {
width: 288px;
height: 120px;

View File

@@ -1,29 +1,11 @@
import { Avatar, Skeleton } from "@arco-design/web-react";
import { Avatar, Spin, Empty } from "@arco-design/web-react";
import "./index.css";
const positions = ["item2", "item1", "item3"];
const icons = ["icon2", "icon1", "icon3"];
const Rank = ({ className, data = null, loading = false }) => {
if (loading) {
return (
<div className={`module-class-rank ${className}`}>
<p className="module-class-rank-title">班级排名</p>
<Skeleton loading={true} />
</div>
);
}
if (!data || !data?.rankings || data?.rankings?.length === 0) {
return (
<div className={`module-class-rank ${className}`}>
<p className="module-class-rank-title">班级排名</p>
<div className="no-data">暂无排名数据</div>
</div>
);
}
const rankings = data?.rankings?.slice(0, 6);
const Rank = ({ className, data, loading }) => {
const rankings = data?.rankings?.slice(0, 6) || [];
// 安全处理领奖台学生确保至少有3个位置
const podiumStudents = [
@@ -37,47 +19,57 @@ const Rank = ({ className, data = null, loading = false }) => {
return (
<div className={`module-class-rank ${className}`}>
<p className="module-class-rank-title">班级排名</p>
<ul className="module-class-rank-podium">
{podiumStudents.map((student, index) => {
return student ? (
<li
key={student.studentId}
className={`module-class-rank-podium-${positions[index]}`}
>
<Avatar className="module-class-rank-podium-avatar">
{student.avatar ? (
<img alt="avatar" src={student.avatar} />
) : (
student.studentName?.charAt(0) || "?"
)}
</Avatar>
<span className="module-class-rank-podium-name">
{student.studentName || "未知"}
</span>
<i className={`module-class-rank-podium-${icons[index]}`}></i>
</li>
) : (
<li
key={`empty-${index}`}
className={`module-class-rank-podium-${positions[index]} empty`}
>
<div className="module-class-rank-podium-placeholder">
<span>-</span>
</div>
</li>
);
})}
</ul>
<ul className="module-class-rank-list">
{listStudents.map((student, index) => (
<li key={student.studentId} className="module-class-rank-list-item">
<i className={`module-class-rank-list-item-icon${index + 4}`} />
<p>{student.studentName || "未知"}</p>
<span>{student.score}</span>
</li>
))}
</ul>
{loading ? (
<Spin size={40} className="module-class-rank-spin" />
) : !data || !data?.rankings || data?.rankings?.length === 0 ? (
<Empty description="暂无排名数据" className="empty-data" />
) : (
<>
<ul className="module-class-rank-podium">
{podiumStudents.map((student, index) => {
return student ? (
<li
key={student.studentId}
className={`module-class-rank-podium-${positions[index]}`}
>
<Avatar className="module-class-rank-podium-avatar">
{student.avatar ? (
<img alt="avatar" src={student.avatar} />
) : (
student.studentName?.charAt(0) || "?"
)}
</Avatar>
<span className="module-class-rank-podium-name">
{student.studentName || "未知"}
</span>
<i className={`module-class-rank-podium-${icons[index]}`}></i>
</li>
) : (
<li
key={`empty-${index}`}
className={`module-class-rank-podium-${positions[index]} empty`}
>
<div className="module-class-rank-podium-placeholder">
<span>-</span>
</div>
</li>
);
})}
</ul>
<ul className="module-class-rank-list">
{listStudents.map((student, index) => (
<li
key={student.studentId}
className="module-class-rank-list-item"
>
<i className={`module-class-rank-list-item-icon${index + 4}`} />
<p>{student.studentName || "未知"}</p>
<span>{student.score}</span>
</li>
))}
</ul>
</>
)}
</div>
);
};

View File

@@ -19,6 +19,9 @@
color: #262626;
margin-bottom: 20px;
}
.study-studes-card-spin {
margin: auto;
}
.study-studes-card-list {
width: 100%;

View File

@@ -1,27 +1,14 @@
import * as echarts from "echarts";
import { useSelector } from "react-redux";
import { Spin } from "@arco-design/web-react";
import StudyProgress from "../StudyProgress";
import ScoreRingChart from "../ScoreRingChart";
import AttendanceRingChart from "../AttendanceRingChart";
import "./index.css";
const StudyStudes = ({
studyStatistics,
learningProgress,
loading = false,
}) => {
const StudyStudes = ({ studyStatistics, learningProgress, loading }) => {
const studentInfo = useSelector((state) => state.student.studentInfo);
// 如果数据还在加载中,显示加载状态
if (loading) {
return (
<div className="study-studes-card-wrapper">
<p className="study-studes-card-title">学习情况</p>
<div>加载中...</div>
</div>
);
}
// 使用传入的数据只在undefined时使用默认值0也是有效值
const personalStudyHours = studyStatistics?.studyTime?.personal ?? 0;
const classAverageStudyHours = studyStatistics?.studyTime?.classAverage ?? 0;
@@ -113,114 +100,118 @@ const StudyStudes = ({
return (
<div className="study-studes-card-wrapper">
<p className="study-studes-card-title">学习情况</p>
<ul className="study-studes-card-list">
{/* 时长 */}
<li className="study-studes-card-study-info">
<div className="study-studes-card-time-wrapper">
<div className="study-studes-card-study-time-wrapper">
<p className="study-studes-card-study-info-title">
个人学习时长h
</p>
<p className="study-studes-card-study-time-line">
<i
style={{
width: `${Math.min(
(personalStudyHours / classAverageStudyHours) * 70,
100
)}%`,
}}
>
<span>{personalStudyHours}</span>
</i>
</p>
</div>
<div className="study-studes-card-study-time-wrapper">
<p className="study-studes-card-study-info-title">
班级平均学习时长h
</p>
<p className="study-studes-card-study-time-line study-studes-card-study-time-line-class">
<i style={{ width: "80%" }}>
<span>{classAverageStudyHours}</span>
</i>
</p>
</div>
</div>
</li>
{/* 进度 */}
<li className="study-studes-card-study-progress">
<StudyProgress
value={overallProgress}
className="study-studes-card-study-progress-chart"
/>
<p className="study-studes-card-study-progress-title">
整体课程完成进度
</p>
</li>
{/* 课程整体完成情况 */}
<li className="study-studes-card-curriculum">
<ScoreRingChart
title={`整体课程\n完成情况`}
ringData={courseRingData}
className="study-studes-card-curriculum-chart"
/>
<div className="study-studes-card-curriculum-info">
<p>班级平均进度</p>
<span className="study-studes-card-curriculum-info-span1">
{classAverageCourseProgress}%
</span>
</div>
<div className="study-studes-card-curriculum-info">
<p>我的进度</p>
<span className="study-studes-card-curriculum-info-span2">
{personalCourseProgress}%
</span>
</div>
</li>
{/* 课后作业完成情况 */}
<li className="study-studes-card-curriculum-homework study-studes-card-curriculum">
<ScoreRingChart
title={`课后作业\n完成情况`}
ringData={homeworkRingData}
className="study-studes-card-curriculum-chart"
/>
<div className="study-studes-card-curriculum-info">
<p>班级平均进度</p>
<span className="study-studes-card-curriculum-info-span1">
{classAverageHomeworkProgress}%
</span>
</div>
<div className="study-studes-card-curriculum-info">
<p>我的进度</p>
<span className="study-studes-card-curriculum-info-span2">
{personalHomeworkProgress}%
</span>
</div>
</li>
{/* 考勤情况 */}
<li className="study-studes-card-curriculum">
<AttendanceRingChart
data={attendanceData}
centerContent={
<div className="study-studes-card-curriculum-chart-center-content">
考勤情况
{loading ? (
<Spin size={40} className="study-studes-card-spin" />
) : (
<ul className="study-studes-card-list">
{/* 时长 */}
<li className="study-studes-card-study-info">
<div className="study-studes-card-time-wrapper">
<div className="study-studes-card-study-time-wrapper">
<p className="study-studes-card-study-info-title">
个人学习时长h
</p>
<p className="study-studes-card-study-time-line">
<i
style={{
width: `${Math.min(
(personalStudyHours / classAverageStudyHours) * 70,
100
)}%`,
}}
>
<span>{personalStudyHours}</span>
</i>
</p>
</div>
}
/>
<div className="study-studes-card-study-time-wrapper">
<p className="study-studes-card-study-info-title">
班级平均学习时长h
</p>
<p className="study-studes-card-study-time-line study-studes-card-study-time-line-class">
<i style={{ width: "80%" }}>
<span>{classAverageStudyHours}</span>
</i>
</p>
</div>
</div>
</li>
{/* 进度 */}
<li className="study-studes-card-study-progress">
<StudyProgress
value={overallProgress}
className="study-studes-card-study-progress-chart"
/>
<p className="study-studes-card-study-progress-title">
整体课程完成进度
</p>
</li>
{/* 课程整体完成情况 */}
<li className="study-studes-card-curriculum">
<ScoreRingChart
title={`整体课程\n完成情况`}
ringData={courseRingData}
className="study-studes-card-curriculum-chart"
/>
<div className="study-studes-card-curriculum-info">
<p>班级平均进度</p>
<span className="study-studes-card-curriculum-info-span1">
{classAverageCourseProgress}%
</span>
</div>
<div className="study-studes-card-curriculum-info">
<p>我的进度</p>
<span className="study-studes-card-curriculum-info-span2">
{personalCourseProgress}%
</span>
</div>
</li>
{/* 课后作业完成情况 */}
<li className="study-studes-card-curriculum-homework study-studes-card-curriculum">
<ScoreRingChart
title={`课后作业\n完成情况`}
ringData={homeworkRingData}
className="study-studes-card-curriculum-chart"
/>
<div className="study-studes-card-curriculum-info">
<p>班级平均进度</p>
<span className="study-studes-card-curriculum-info-span1">
{classAverageHomeworkProgress}%
</span>
</div>
<div className="study-studes-card-curriculum-info">
<p>我的进度</p>
<span className="study-studes-card-curriculum-info-span2">
{personalHomeworkProgress}%
</span>
</div>
</li>
{/* 考勤情况 */}
<li className="study-studes-card-curriculum">
<AttendanceRingChart
data={attendanceData}
centerContent={
<div className="study-studes-card-curriculum-chart-center-content">
考勤情况
</div>
}
/>
<div className="study-studes-card-curriculum-info">
<p>出勤率</p>
<span className="study-studes-card-curriculum-info-span1">
{attendanceRate}%
</span>
</div>
<div className="study-studes-card-curriculum-info">
<p>缺勤率</p>
<span className="study-studes-card-curriculum-info-span3">
{absenceRate}%
</span>
</div>
</li>
</ul>
<div className="study-studes-card-curriculum-info">
<p>出勤率</p>
<span className="study-studes-card-curriculum-info-span1">
{attendanceRate}%
</span>
</div>
<div className="study-studes-card-curriculum-info">
<p>缺勤率</p>
<span className="study-studes-card-curriculum-info-span3">
{absenceRate}%
</span>
</div>
</li>
</ul>
)}
</div>
);
};

View File

@@ -1,4 +1,4 @@
import { useState, useEffect, useCallback } from "react";
import { useState, useEffect } from "react";
import { useDispatch } from "react-redux";
import ProfileCard from "./components/ProfileCard";
import Rank from "@/components/Rank";
@@ -11,13 +11,15 @@ import "./index.css";
const PersonalProfile = () => {
const dispatch = useDispatch();
const [profileData, setProfileData] = useState(null); // 个人档案完整数据
const [loading, setLoading] = useState(true);
const [loading, setLoading] = useState(false);
// 获取个人档案完整数据
const queryProfileOverview = useCallback(async () => {
const queryProfileOverview = async () => {
try {
if (loading) return;
setLoading(true);
const res = await getProfileOverview();
setLoading(false);
if (res.success) {
const data = res.data;
@@ -36,11 +38,11 @@ const PersonalProfile = () => {
} finally {
setLoading(false);
}
}, [dispatch]);
};
useEffect(() => {
queryProfileOverview();
}, [queryProfileOverview]);
}, []);
return (
<div className="personal-profile">

View File

@@ -5,7 +5,6 @@ export async function getStudyRecordsProgress() {
return request({
url: `/api/study-records/progress`,
method: "GET",
namespace: "dashboardLoading",
});
}
@@ -15,7 +14,6 @@ export async function getMyTasks(params = {}) {
url: `/api/tasks/my-tasks`,
method: "GET",
params: params,
namespace: "dashboardLoading",
});
}
@@ -25,6 +23,5 @@ export async function getClassRanking(params = { limit: 6 }) {
url: `/api/rankings/class`,
method: "GET",
params: params,
namespace: "dashboardLoading",
});
}

View File

@@ -5,6 +5,5 @@ export async function getLoginStudentInfo() {
return request({
url: `/api/students/me`,
method: "GET",
namespace: "globalLoading",
});
}