From 512b2420e32a51e718adf87e0c92ec5ebc0cfc82 Mon Sep 17 00:00:00 2001 From: Rao <1227431568@qq.com> Date: Tue, 25 Feb 2025 12:56:53 +0800 Subject: [PATCH 1/2] rht02251256 --- .../main/courses/components/FilterSection.tsx | 2 +- apps/web/src/app/main/courses/page.tsx | 61 +++++++++++++------ .../main/home/components/CategorySection.tsx | 3 +- .../main/home/components/CoursesSection.tsx | 2 +- .../app/main/home/components/HeroSection.tsx | 13 ++-- apps/web/src/app/main/layout/MainHeader.tsx | 9 ++- 6 files changed, 59 insertions(+), 31 deletions(-) diff --git a/apps/web/src/app/main/courses/components/FilterSection.tsx b/apps/web/src/app/main/courses/components/FilterSection.tsx index 6fe06c4..a5d9113 100755 --- a/apps/web/src/app/main/courses/components/FilterSection.tsx +++ b/apps/web/src/app/main/courses/components/FilterSection.tsx @@ -29,7 +29,7 @@ function useGetTaxonomy({type}) : GetTaxonomyProps { include:{ children :true }, - take:10, // 只取前10个 + take:20, // 只取前10个 orderBy: { createdAt: 'desc', // 按创建时间降序排列 }, diff --git a/apps/web/src/app/main/courses/page.tsx b/apps/web/src/app/main/courses/page.tsx index a411d60..2deace0 100755 --- a/apps/web/src/app/main/courses/page.tsx +++ b/apps/web/src/app/main/courses/page.tsx @@ -7,19 +7,24 @@ import { courseDetailSelect, CourseDto, LectureType, PostType } from "@nice/comm import { useSearchParams } from "react-router-dom"; import { set } from "idb-keyval"; - +interface paginationData { + items:CourseDto[], + totalPages:number +} export default function CoursesPage() { const [currentPage, setCurrentPage] = useState(1); const [selectedCategory, setSelectedCategory] = useState(""); const [selectedLevel, setSelectedLevel] = useState(""); - const pageSize = 9; - const [isAll,setIsAll] = useState(true) + const pageSize = 12; + const [isAll,setIsAll] = useState(true) const [searchParams, setSearchParams] = useSearchParams(); - let coursesData = [] - let isCourseLoading = false - if(!searchParams.get('searchValue')){ - console.log('no category') - const {data,isLoading} = api.post.findManyWithPagination.useQuery({ + + const [coursesData, setCoursesData] = useState([]); + const [isCourseLoading, setIsCourseLoading] = useState(false); + const [totalPagesNum, setTotalPagesNum] = useState(0); + + if(!searchParams.get('searchValue') && !searchParams.get('searchValue')){ + const {data,isLoading} :{ data:paginationData,isLoading:boolean} = api.post.findManyWithPagination.useQuery({ where: { type: PostType.COURSE, terms:isAll?{}:{ @@ -32,14 +37,21 @@ export default function CoursesPage() { }, }, - select:courseDetailSelect + pageSize, + page:currentPage, + select:courseDetailSelect, }); - coursesData = data?.items - isCourseLoading = isLoading + console.log(data) + useEffect(()=>{ + console.log(currentPage); + setIsCourseLoading(isLoading) + setCoursesData(data?.items) + setTotalPagesNum(data?.totalPages) + },[currentPage,data]) }else{ console.log('searchValue:'+searchParams.get('searchValue')) const searchValue = searchParams.get('searchValue') - const {data,isLoading} = api.post.findManyWithPagination.useQuery({ + const {data,isLoading} :{ data:paginationData,isLoading:boolean}= api.post.findManyWithPagination.useQuery({ where: { type: PostType.COURSE, OR:[ @@ -49,10 +61,15 @@ export default function CoursesPage() { { terms: { some: { name: { contains: searchValue, mode: 'insensitive' } } } } ] }, - select:courseDetailSelect + select:courseDetailSelect, + pageSize, + page:currentPage, }) - coursesData = data?.items - isCourseLoading = isLoading + useEffect(()=>{ + setIsCourseLoading(isLoading) + setCoursesData(data?.items) + setTotalPagesNum(data?.totalPages) + },[currentPage]) } useEffect(() => { if(searchParams.get('searchValue')==''){ @@ -93,13 +110,19 @@ export default function CoursesPage() { setSelectedCategory(category); setCurrentPage(1); setIsAll(!category) - setSearchParams({ searchValue: ''}); + setSearchParams(prev => { + prev.delete('searchValue'); + return prev; + }); }} onLevelChange={(level) => { setSelectedLevel(level); setCurrentPage(1); setIsAll(!level) - setSearchParams({ searchValue: ''}); + setSearchParams(prev => { + prev.delete('searchValue'); + return prev; + }); }} /> @@ -110,12 +133,12 @@ export default function CoursesPage() {
- 共找到 {filteredCourses.length} 门课程 + 共找到 {totalPagesNum * pageSize || 0} 门课程
{ onClick={()=>{ console.log(category.name) navigate(`/courses?category=${category.name}`) + window.scrollTo({ top: 0, behavior: 'smooth' }) }} >
diff --git a/apps/web/src/app/main/home/components/CoursesSection.tsx b/apps/web/src/app/main/home/components/CoursesSection.tsx index 0c04870..b965815 100755 --- a/apps/web/src/app/main/home/components/CoursesSection.tsx +++ b/apps/web/src/app/main/home/components/CoursesSection.tsx @@ -56,7 +56,7 @@ function useFetchCoursesByCategory(category: string) { terms:true } }); - + console.log("ss",data) return { data, isLoading}; } diff --git a/apps/web/src/app/main/home/components/HeroSection.tsx b/apps/web/src/app/main/home/components/HeroSection.tsx index f73357d..10ecbfe 100755 --- a/apps/web/src/app/main/home/components/HeroSection.tsx +++ b/apps/web/src/app/main/home/components/HeroSection.tsx @@ -48,12 +48,11 @@ const carouselItems: CarouselItem[] = [ const HeroSection = () => { const carouselRef = useRef(null); const { statistics, baseSetting } = useAppConfig(); - const platformStats: PlatformStat[] = [ - { icon: , value: "50,000+", label: "注册学员" }, - { icon: , value: "1,000+", label: "精品课程" }, - // { icon: , value: '98%', label: '好评度' }, - { icon: , value: "4552", label: "观看次数" }, + { icon: , value: statistics.staffs.toString(), label: "注册学员" }, + { icon: , value: statistics.courses.toString(), label: "精品课程" }, + { icon: , value: statistics.lectures.toString(), label: '课程章节' }, + { icon: , value: statistics.reads.toString(), label: "观看次数" }, ]; const handlePrev = useCallback(() => { carouselRef.current?.prev(); @@ -119,8 +118,8 @@ const HeroSection = () => {
{/* Stats Container */} -
-
+
+
{platformStats.map((stat, index) => (
@@ -37,7 +38,11 @@ export function MainHeader() { onChange={(e) => setSearchValue(e.target.value)} onPressEnter={(e) => { //console.log(e) - setSearchValue(""); + //setSearchValue(""); + setSearchParams((prev)=>{ + if(searchParams.get("category")) prev.delete("category") + return prev + }) navigate( `/courses/?searchValue=${searchValue}` ); From 6484ac80ad63e549ab5f52173c1303bdd7ae8055 Mon Sep 17 00:00:00 2001 From: Li1304553726 <1304553726@qq.com> Date: Tue, 25 Feb 2025 13:30:59 +0800 Subject: [PATCH 2/2] li --- .../main/courses/components/CourseCard.tsx | 115 ++++++++++++------ .../main/home/components/CoursesSection.tsx | 48 +++++--- packages/common/src/models/post.ts | 1 + 3 files changed, 111 insertions(+), 53 deletions(-) diff --git a/apps/web/src/app/main/courses/components/CourseCard.tsx b/apps/web/src/app/main/courses/components/CourseCard.tsx index 5d7c3cd..84688f3 100755 --- a/apps/web/src/app/main/courses/components/CourseCard.tsx +++ b/apps/web/src/app/main/courses/components/CourseCard.tsx @@ -1,49 +1,90 @@ -import { Card, Rate, Tag } from 'antd'; +import { Card, Rate, Tag ,Typography,Button} from 'antd'; import { Course } from '../mockData'; -import { UserOutlined, ClockCircleOutlined } from '@ant-design/icons'; +import { UserOutlined, ClockCircleOutlined, PlayCircleOutlined, TeamOutlined } from '@ant-design/icons'; import { CourseDto } from '@nice/common'; +import { useNavigate } from 'react-router-dom'; + interface CourseCardProps { course: CourseDto; } - +const { Title, Text } = Typography; export default function CourseCard({ course }: CourseCardProps) { + const navigate = useNavigate(); + const handleClick = (course: CourseDto) => { + navigate(`/course/${course.id}/detail`); + } return ( - handleClick(course)} + key={course.id} + hoverable + className="group overflow-hidden rounded-2xl border border-gray-200 bg-white + shadow-xl hover:shadow-2xl transition-all duration-300 transform hover:-translate-y-2" + cover={ +
+
- } - > -
-

- {course.title} -

-

{course.subTitle}

-
- - {course.rating} -
-
-
- - {course.enrollments?.length} 人在学 -
-
- - {course.duration} -
-
-
- {course.terms[0].name} - {course.terms[1].name} -
+
+
- + } + > +
+
+ + {course.terms[0].name} + + + {course.terms[1].name} + +
+ + <button > {course.title}</button> + + +
+ +
+ + {course?.depts[0]?.name} + +
+ + 观看次数{course?.meta?.views}次 + +
+ + +
+ +
+ +
+ ); } diff --git a/apps/web/src/app/main/home/components/CoursesSection.tsx b/apps/web/src/app/main/home/components/CoursesSection.tsx index b4938b0..ec2e759 100755 --- a/apps/web/src/app/main/home/components/CoursesSection.tsx +++ b/apps/web/src/app/main/home/components/CoursesSection.tsx @@ -1,6 +1,6 @@ import React, { useState, useMemo, useEffect } from 'react'; -import { useNavigate, useParams, useSearchParams } from 'react-router-dom'; -import { Button, Card, Typography, Tag, Progress, Spin, Empty } from 'antd'; +import { useNavigate } from 'react-router-dom'; +import { Button, Card, Typography, Tag, Spin, Empty } from 'antd'; import { PlayCircleOutlined, UserOutlined, @@ -12,7 +12,6 @@ import { } from '@ant-design/icons'; import { CourseDto, TaxonomySlug, TermDto } from '@nice/common'; import { api } from '@nice/client'; -// const {courseId} = useParams(); interface GetTaxonomyProps { categories: string[]; isLoading: boolean; @@ -39,6 +38,7 @@ function useGetTaxonomy({ type }): GetTaxonomyProps { }, [data]); return { categories, isLoading } } + // 不同分类跳转 function useFetchCoursesByCategory(category: string) { const isAll = category === '全部'; @@ -52,7 +52,8 @@ function useFetchCoursesByCategory(category: string) { }, take: 8, include: { - terms: true + terms: true, + depts:true } }); @@ -83,12 +84,9 @@ interface CoursesSectionProps { initialVisibleCoursesCount?: number; } - const CoursesSection: React.FC = ({ title, description, - courses, - isLoading, initialVisibleCoursesCount = 8, }) => { const navigate = useNavigate(); @@ -97,10 +95,11 @@ const CoursesSection: React.FC = ({ const gateGory: GetTaxonomyProps = useGetTaxonomy({ type: TaxonomySlug.CATEGORY, }) + const { data, isLoading: isDataLoading } = useFetchCoursesByCategory(selectedCategory); - useEffect(() => { - console.log('data:', data) - }) + // useEffect(() => { + // console.log('data:', data) + // }) const handleClick = (course: CourseDto) => { navigate(`/course/${course.id}/detail`); } @@ -108,6 +107,20 @@ const CoursesSection: React.FC = ({ useEffect(() => { console.log('data:', data) }) + + // const { data: depts, isLoading: isDeptLoading }: { data: CourseDto[], isLoading: boolean } = api.post.findMany.useQuery({ + // where: {}, + // include: { + // depts: true, + // }, + // orderBy: { + // createdAt: 'desc' // 按创建时间降序排列 + // }, + // take: 8 // 只获取前8个课程 + // }); + + + const filteredCourses = useMemo(() => { return selectedCategory === '全部' ? data @@ -115,6 +128,7 @@ const CoursesSection: React.FC = ({ }, [selectedCategory, data]); const displayedCourses = isDataLoading ? [] : filteredCourses?.slice(0, visibleCourses); + return (
@@ -170,8 +184,8 @@ const CoursesSection: React.FC = ({
- {displayedCourses.length=== 0 ? ( -
+ {displayedCourses.length === 0 ? ( +
) : displayedCourses?.map((course) => ( @@ -223,14 +237,16 @@ const CoursesSection: React.FC = ({
- + + {course?.depts[0]?.name}
- - - 观看次数{course?.meta?.views}次 + + 观看次数{course?.meta?.views}次
+ +