feat: 🎸 接口对接调整

This commit is contained in:
2025-08-26 10:54:12 +08:00
parent 44a94b861a
commit 428b880970
21 changed files with 223 additions and 292 deletions

View File

@@ -1,4 +1,4 @@
import { useEffect, useRef, useState } from "react";
import { useEffect, useRef, useState, useCallback } from "react";
import { Empty, Spin } from "@arco-design/web-react";
import "./index.css";
@@ -13,18 +13,27 @@ const InfiniteScroll = ({
const containerRef = useRef(null);
const sentinelRef = useRef(null);
const observerRef = useRef(null);
const throttleRef = useRef(null); // 节流控制
const [loading, setLoading] = useState(false);
const [hasInitialized, setHasInitialized] = useState(false); // 首次挂载
// 加载更多数据的处理函数
const handleLoadMore = () => {
// 加载更多数据的处理函数(带节流)
const handleLoadMore = useCallback(() => {
if (loading || !hasMore) return;
setLoading(true);
loadMore().finally(() => {
setLoading(false);
});
};
// 节流处理500ms内只能触发一次
if (throttleRef.current) {
clearTimeout(throttleRef.current);
}
throttleRef.current = setTimeout(() => {
setLoading(true);
loadMore().finally(() => {
setLoading(false);
throttleRef.current = null;
});
}, 10);
}, [hasMore, loadMore, loading]);
// 设置IntersectionObserver
useEffect(() => {
@@ -59,8 +68,13 @@ const InfiniteScroll = ({
if (observerRef.current) {
observerRef.current.disconnect();
}
// 清理节流定时器
if (throttleRef.current) {
clearTimeout(throttleRef.current);
throttleRef.current = null;
}
};
}, [loadMore, hasMore, threshold, loading]);
}, [loadMore, hasMore, threshold, loading, hasInitialized, handleLoadMore]);
return (
<div

View File

@@ -1,4 +1,4 @@
import { useState, useEffect } from "react";
import { useState, useEffect, useCallback } from "react";
import { Spin } from "@arco-design/web-react";
import { useSelector, useDispatch } from "react-redux";
import { getLoginStudentInfo } from "@/services";
@@ -14,19 +14,19 @@ const Layout = ({ children }) => {
);
const studentInfo = useSelector((state) => state.student.studentInfo);
const queryLoginStudentInfo = async () => {
const queryLoginStudentInfo = useCallback(async () => {
const res = await getLoginStudentInfo();
if (res.success) {
dispatch(setStudentInfo(res.data));
}
};
}, [dispatch]);
// 初始化项目统一获取登录用户信息
useEffect(() => {
if (!studentInfo) {
queryLoginStudentInfo();
}
}, [studentInfo]);
}, [queryLoginStudentInfo, studentInfo]);
return (
<div className="app-layout">

View File

View File

@@ -1,6 +1,9 @@
import { Avatar, Skeleton } 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 (
@@ -11,7 +14,7 @@ const Rank = ({ className, data = null, loading = false }) => {
);
}
if (!data || !data.rankings || data.rankings.length === 0) {
if (!data || !data?.rankings || data?.rankings?.length === 0) {
return (
<div className={`module-class-rank ${className}`}>
<p className="module-class-rank-title">班级排名</p>
@@ -20,15 +23,15 @@ const Rank = ({ className, data = null, loading = false }) => {
);
}
const rankings = data.rankings.slice(0, 6);
const rankings = data?.rankings?.slice(0, 6);
// 安全处理领奖台学生确保至少有3个位置
const podiumStudents = [
rankings[1] || null, // 第2名
rankings[0] || null, // 第1名
rankings[2] || null // 第3名
rankings[0] || null, // 第1名
rankings[2] || null, // 第3名
];
const listStudents = rankings.slice(3);
return (
@@ -37,21 +40,11 @@ const Rank = ({ className, data = null, loading = false }) => {
<ul className="module-class-rank-podium">
{podiumStudents.map((student, index) => {
const positions = ["item2", "item1", "item3"];
const icons = ["icon2", "icon1", "icon3"];
if (!student) {
return (
<li key={`empty-${index}`} className={`module-class-rank-podium-${positions[index]} empty`}>
<div className="module-class-rank-podium-placeholder">
<span>-</span>
</div>
</li>
);
}
return (
<li key={student.studentId} className={`module-class-rank-podium-${positions[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} />
@@ -64,6 +57,15 @@ const Rank = ({ className, data = null, loading = false }) => {
</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>

View File

@@ -1,5 +1,6 @@
import { useNavigate, useLocation } from "react-router-dom";
import { Statistic } from "@arco-design/web-react";
import { useSelector } from "react-redux";
import IconFont from "@/components/IconFont";
import Logo from "@/assets/images/Sidebar/logo.png";
import BTNICON from "@/assets/images/Sidebar/btn_icon.png";
@@ -9,6 +10,7 @@ import "./index.css";
const Sidebar = ({ isCollapsed, setIsCollapsed }) => {
const navigate = useNavigate();
const location = useLocation();
const studentInfo = useSelector((state) => state.student.studentInfo);
const handleNavClick = (path) => {
navigate(path);