feat: 🎸 新增了几处加载
This commit is contained in:
@@ -23,6 +23,11 @@
|
|||||||
color: #262626;
|
color: #262626;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.module-class-rank-spin,
|
||||||
|
.empty-data {
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.module-class-rank-podium {
|
.module-class-rank-podium {
|
||||||
width: 288px;
|
width: 288px;
|
||||||
height: 120px;
|
height: 120px;
|
||||||
|
|||||||
@@ -1,29 +1,11 @@
|
|||||||
import { Avatar, Skeleton } from "@arco-design/web-react";
|
import { Avatar, Spin, Empty } from "@arco-design/web-react";
|
||||||
import "./index.css";
|
import "./index.css";
|
||||||
|
|
||||||
const positions = ["item2", "item1", "item3"];
|
const positions = ["item2", "item1", "item3"];
|
||||||
const icons = ["icon2", "icon1", "icon3"];
|
const icons = ["icon2", "icon1", "icon3"];
|
||||||
|
|
||||||
const Rank = ({ className, data = null, loading = false }) => {
|
const Rank = ({ className, data, loading }) => {
|
||||||
if (loading) {
|
const rankings = data?.rankings?.slice(0, 6) || [];
|
||||||
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);
|
|
||||||
|
|
||||||
// 安全处理领奖台学生,确保至少有3个位置
|
// 安全处理领奖台学生,确保至少有3个位置
|
||||||
const podiumStudents = [
|
const podiumStudents = [
|
||||||
@@ -37,47 +19,57 @@ const Rank = ({ className, data = null, loading = false }) => {
|
|||||||
return (
|
return (
|
||||||
<div className={`module-class-rank ${className}`}>
|
<div className={`module-class-rank ${className}`}>
|
||||||
<p className="module-class-rank-title">班级排名</p>
|
<p className="module-class-rank-title">班级排名</p>
|
||||||
|
{loading ? (
|
||||||
<ul className="module-class-rank-podium">
|
<Spin size={40} className="module-class-rank-spin" />
|
||||||
{podiumStudents.map((student, index) => {
|
) : !data || !data?.rankings || data?.rankings?.length === 0 ? (
|
||||||
return student ? (
|
<Empty description="暂无排名数据" className="empty-data" />
|
||||||
<li
|
) : (
|
||||||
key={student.studentId}
|
<>
|
||||||
className={`module-class-rank-podium-${positions[index]}`}
|
<ul className="module-class-rank-podium">
|
||||||
>
|
{podiumStudents.map((student, index) => {
|
||||||
<Avatar className="module-class-rank-podium-avatar">
|
return student ? (
|
||||||
{student.avatar ? (
|
<li
|
||||||
<img alt="avatar" src={student.avatar} />
|
key={student.studentId}
|
||||||
) : (
|
className={`module-class-rank-podium-${positions[index]}`}
|
||||||
student.studentName?.charAt(0) || "?"
|
>
|
||||||
)}
|
<Avatar className="module-class-rank-podium-avatar">
|
||||||
</Avatar>
|
{student.avatar ? (
|
||||||
<span className="module-class-rank-podium-name">
|
<img alt="avatar" src={student.avatar} />
|
||||||
{student.studentName || "未知"}
|
) : (
|
||||||
</span>
|
student.studentName?.charAt(0) || "?"
|
||||||
<i className={`module-class-rank-podium-${icons[index]}`}></i>
|
)}
|
||||||
</li>
|
</Avatar>
|
||||||
) : (
|
<span className="module-class-rank-podium-name">
|
||||||
<li
|
{student.studentName || "未知"}
|
||||||
key={`empty-${index}`}
|
</span>
|
||||||
className={`module-class-rank-podium-${positions[index]} empty`}
|
<i className={`module-class-rank-podium-${icons[index]}`}></i>
|
||||||
>
|
</li>
|
||||||
<div className="module-class-rank-podium-placeholder">
|
) : (
|
||||||
<span>-</span>
|
<li
|
||||||
</div>
|
key={`empty-${index}`}
|
||||||
</li>
|
className={`module-class-rank-podium-${positions[index]} empty`}
|
||||||
);
|
>
|
||||||
})}
|
<div className="module-class-rank-podium-placeholder">
|
||||||
</ul>
|
<span>-</span>
|
||||||
<ul className="module-class-rank-list">
|
</div>
|
||||||
{listStudents.map((student, index) => (
|
</li>
|
||||||
<li key={student.studentId} className="module-class-rank-list-item">
|
);
|
||||||
<i className={`module-class-rank-list-item-icon${index + 4}`} />
|
})}
|
||||||
<p>{student.studentName || "未知"}</p>
|
</ul>
|
||||||
<span>{student.score}分</span>
|
<ul className="module-class-rank-list">
|
||||||
</li>
|
{listStudents.map((student, index) => (
|
||||||
))}
|
<li
|
||||||
</ul>
|
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>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,6 +19,9 @@
|
|||||||
color: #262626;
|
color: #262626;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
.study-studes-card-spin {
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.study-studes-card-list {
|
.study-studes-card-list {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -1,27 +1,14 @@
|
|||||||
import * as echarts from "echarts";
|
import * as echarts from "echarts";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
|
import { Spin } from "@arco-design/web-react";
|
||||||
import StudyProgress from "../StudyProgress";
|
import StudyProgress from "../StudyProgress";
|
||||||
import ScoreRingChart from "../ScoreRingChart";
|
import ScoreRingChart from "../ScoreRingChart";
|
||||||
import AttendanceRingChart from "../AttendanceRingChart";
|
import AttendanceRingChart from "../AttendanceRingChart";
|
||||||
import "./index.css";
|
import "./index.css";
|
||||||
|
|
||||||
const StudyStudes = ({
|
const StudyStudes = ({ studyStatistics, learningProgress, loading }) => {
|
||||||
studyStatistics,
|
|
||||||
learningProgress,
|
|
||||||
loading = false,
|
|
||||||
}) => {
|
|
||||||
const studentInfo = useSelector((state) => state.student.studentInfo);
|
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也是有效值)
|
// 使用传入的数据,只在undefined时使用默认值(0也是有效值)
|
||||||
const personalStudyHours = studyStatistics?.studyTime?.personal ?? 0;
|
const personalStudyHours = studyStatistics?.studyTime?.personal ?? 0;
|
||||||
const classAverageStudyHours = studyStatistics?.studyTime?.classAverage ?? 0;
|
const classAverageStudyHours = studyStatistics?.studyTime?.classAverage ?? 0;
|
||||||
@@ -113,114 +100,118 @@ const StudyStudes = ({
|
|||||||
return (
|
return (
|
||||||
<div className="study-studes-card-wrapper">
|
<div className="study-studes-card-wrapper">
|
||||||
<p className="study-studes-card-title">学习情况</p>
|
<p className="study-studes-card-title">学习情况</p>
|
||||||
<ul className="study-studes-card-list">
|
{loading ? (
|
||||||
{/* 时长 */}
|
<Spin size={40} className="study-studes-card-spin" />
|
||||||
<li className="study-studes-card-study-info">
|
) : (
|
||||||
<div className="study-studes-card-time-wrapper">
|
<ul className="study-studes-card-list">
|
||||||
<div className="study-studes-card-study-time-wrapper">
|
{/* 时长 */}
|
||||||
<p className="study-studes-card-study-info-title">
|
<li className="study-studes-card-study-info">
|
||||||
个人学习时长(h)
|
<div className="study-studes-card-time-wrapper">
|
||||||
</p>
|
<div className="study-studes-card-study-time-wrapper">
|
||||||
<p className="study-studes-card-study-time-line">
|
<p className="study-studes-card-study-info-title">
|
||||||
<i
|
个人学习时长(h)
|
||||||
style={{
|
</p>
|
||||||
width: `${Math.min(
|
<p className="study-studes-card-study-time-line">
|
||||||
(personalStudyHours / classAverageStudyHours) * 70,
|
<i
|
||||||
100
|
style={{
|
||||||
)}%`,
|
width: `${Math.min(
|
||||||
}}
|
(personalStudyHours / classAverageStudyHours) * 70,
|
||||||
>
|
100
|
||||||
<span>{personalStudyHours}</span>
|
)}%`,
|
||||||
</i>
|
}}
|
||||||
</p>
|
>
|
||||||
</div>
|
<span>{personalStudyHours}</span>
|
||||||
<div className="study-studes-card-study-time-wrapper">
|
</i>
|
||||||
<p className="study-studes-card-study-info-title">
|
</p>
|
||||||
班级平均学习时长(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>
|
||||||
}
|
<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">
|
<div className="study-studes-card-curriculum-info">
|
||||||
<p>出勤率</p>
|
<p>出勤率</p>
|
||||||
<span className="study-studes-card-curriculum-info-span1">
|
<span className="study-studes-card-curriculum-info-span1">
|
||||||
{attendanceRate}%
|
{attendanceRate}%
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="study-studes-card-curriculum-info">
|
<div className="study-studes-card-curriculum-info">
|
||||||
<p>缺勤率</p>
|
<p>缺勤率</p>
|
||||||
<span className="study-studes-card-curriculum-info-span3">
|
<span className="study-studes-card-curriculum-info-span3">
|
||||||
{absenceRate}%
|
{absenceRate}%
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useEffect, useCallback } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { useDispatch } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
import ProfileCard from "./components/ProfileCard";
|
import ProfileCard from "./components/ProfileCard";
|
||||||
import Rank from "@/components/Rank";
|
import Rank from "@/components/Rank";
|
||||||
@@ -11,13 +11,15 @@ import "./index.css";
|
|||||||
const PersonalProfile = () => {
|
const PersonalProfile = () => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const [profileData, setProfileData] = useState(null); // 个人档案完整数据
|
const [profileData, setProfileData] = useState(null); // 个人档案完整数据
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
// 获取个人档案完整数据
|
// 获取个人档案完整数据
|
||||||
const queryProfileOverview = useCallback(async () => {
|
const queryProfileOverview = async () => {
|
||||||
try {
|
try {
|
||||||
|
if (loading) return;
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const res = await getProfileOverview();
|
const res = await getProfileOverview();
|
||||||
|
setLoading(false);
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
const data = res.data;
|
const data = res.data;
|
||||||
|
|
||||||
@@ -36,11 +38,11 @@ const PersonalProfile = () => {
|
|||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}, [dispatch]);
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
queryProfileOverview();
|
queryProfileOverview();
|
||||||
}, [queryProfileOverview]);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="personal-profile">
|
<div className="personal-profile">
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ export async function getStudyRecordsProgress() {
|
|||||||
return request({
|
return request({
|
||||||
url: `/api/study-records/progress`,
|
url: `/api/study-records/progress`,
|
||||||
method: "GET",
|
method: "GET",
|
||||||
namespace: "dashboardLoading",
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -15,7 +14,6 @@ export async function getMyTasks(params = {}) {
|
|||||||
url: `/api/tasks/my-tasks`,
|
url: `/api/tasks/my-tasks`,
|
||||||
method: "GET",
|
method: "GET",
|
||||||
params: params,
|
params: params,
|
||||||
namespace: "dashboardLoading",
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,6 +23,5 @@ export async function getClassRanking(params = { limit: 6 }) {
|
|||||||
url: `/api/rankings/class`,
|
url: `/api/rankings/class`,
|
||||||
method: "GET",
|
method: "GET",
|
||||||
params: params,
|
params: params,
|
||||||
namespace: "dashboardLoading",
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,5 @@ export async function getLoginStudentInfo() {
|
|||||||
return request({
|
return request({
|
||||||
url: `/api/students/me`,
|
url: `/api/students/me`,
|
||||||
method: "GET",
|
method: "GET",
|
||||||
namespace: "globalLoading",
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user