From 237d5a44d81af987b0b7204eba76533f5bb81bad Mon Sep 17 00:00:00 2001 From: ditiqi Date: Tue, 25 Feb 2025 16:43:42 +0800 Subject: [PATCH 01/23] addd --- .../src/app/main/home/components/CoursesSection.tsx | 12 +++++++----- packages/common/src/models/post.ts | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/web/src/app/main/home/components/CoursesSection.tsx b/apps/web/src/app/main/home/components/CoursesSection.tsx index 2117baa..24bb307 100755 --- a/apps/web/src/app/main/home/components/CoursesSection.tsx +++ b/apps/web/src/app/main/home/components/CoursesSection.tsx @@ -6,7 +6,12 @@ import { TeamOutlined, ArrowRightOutlined, } from "@ant-design/icons"; -import { CourseDto, TaxonomySlug, TermDto } from "@nice/common"; +import { + courseDetailSelect, + CourseDto, + TaxonomySlug, + TermDto, +} from "@nice/common"; import { api } from "@nice/client"; import CourseCard from "../../courses/components/CourseCard"; interface GetTaxonomyProps { @@ -50,10 +55,7 @@ function useFetchCoursesByCategory(category: string) { }, }, take: 8, - include: { - terms: true, - depts: true, - }, + select: courseDetailSelect, }); return { data, isLoading }; diff --git a/packages/common/src/models/post.ts b/packages/common/src/models/post.ts index 6994d4b..0d2bf07 100755 --- a/packages/common/src/models/post.ts +++ b/packages/common/src/models/post.ts @@ -77,7 +77,7 @@ export type Course = Post & { export type CourseDto = Course & { enrollments?: Enrollment[]; sections?: SectionDto[]; - terms: Term[]; + terms: TermDto[]; lectureCount?: number; depts:Department[] }; From 9d7160ccd827eba6dcc5c26fad5effb547cf15b5 Mon Sep 17 00:00:00 2001 From: Li1304553726 <1304553726@qq.com> Date: Tue, 25 Feb 2025 17:44:33 +0800 Subject: [PATCH 02/23] add. Li --- .../main/courses/components/CourseCard.tsx | 25 ++++++++++++++++--- .../main/home/components/CoursesSection.tsx | 10 ++++---- packages/common/src/models/post.ts | 2 +- packages/common/src/models/term.ts | 4 ++- 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/apps/web/src/app/main/courses/components/CourseCard.tsx b/apps/web/src/app/main/courses/components/CourseCard.tsx index 9a9f37d..c860934 100755 --- a/apps/web/src/app/main/courses/components/CourseCard.tsx +++ b/apps/web/src/app/main/courses/components/CourseCard.tsx @@ -18,6 +18,8 @@ export default function CourseCard({ course }: CourseCardProps) { const handleClick = (course: CourseDto) => { navigate(`/course/${course.id}/detail`); }; + + return ( handleClick(course)} @@ -39,10 +41,26 @@ export default function CourseCard({ course }: CourseCardProps) { }>
- { + return ( + + {term.name} + + ); + })} + {/* {course.terms?.[0].name} + {course.terms?.[1].name} - + */}
<div className="ml-2 flex items-center flex-grow"> <Text className="font-medium text-blue-500 hover:text-blue-600 transition-colors duration-300 truncate max-w-[120px]"> - {course?.depts?.[0]?.name} + {(course.depts.map((depts)=>depts.name))} + {/* {course?.depts?.[0]?.name} */} </Text> </div> <span className="text-xs font-medium text-gray-500"> diff --git a/apps/web/src/app/main/home/components/CoursesSection.tsx b/apps/web/src/app/main/home/components/CoursesSection.tsx index 2117baa..d3fb760 100755 --- a/apps/web/src/app/main/home/components/CoursesSection.tsx +++ b/apps/web/src/app/main/home/components/CoursesSection.tsx @@ -6,7 +6,7 @@ import { TeamOutlined, ArrowRightOutlined, } from "@ant-design/icons"; -import { CourseDto, TaxonomySlug, TermDto } from "@nice/common"; +import { courseDetailSelect, CourseDto, TaxonomySlug, TermDto } from "@nice/common"; import { api } from "@nice/client"; import CourseCard from "../../courses/components/CourseCard"; interface GetTaxonomyProps { @@ -50,10 +50,7 @@ function useFetchCoursesByCategory(category: string) { }, }, take: 8, - include: { - terms: true, - depts: true, - }, + select: courseDetailSelect, }); return { data, isLoading }; @@ -83,6 +80,9 @@ const CoursesSection: React.FC<CoursesSectionProps> = ({ ); }, [selectedCategory, data]); const displayedCourses = isDataLoading ? [] : filteredCourses; + useEffect(()=>{ + console.log(data) + }) return ( <section className="relative py-20 overflow-hidden bg-gradient-to-b from-gray-50 to-white"> <div className="max-w-screen-2xl mx-auto px-6 relative"> diff --git a/packages/common/src/models/post.ts b/packages/common/src/models/post.ts index 6994d4b..0d2bf07 100755 --- a/packages/common/src/models/post.ts +++ b/packages/common/src/models/post.ts @@ -77,7 +77,7 @@ export type Course = Post & { export type CourseDto = Course & { enrollments?: Enrollment[]; sections?: SectionDto[]; - terms: Term[]; + terms: TermDto[]; lectureCount?: number; depts:Department[] }; diff --git a/packages/common/src/models/term.ts b/packages/common/src/models/term.ts index cef8b61..37c5d7f 100755 --- a/packages/common/src/models/term.ts +++ b/packages/common/src/models/term.ts @@ -1,8 +1,10 @@ -import { Term } from "@prisma/client"; +import { Taxonomy, Term } from "@prisma/client"; import { ResPerm } from "./rbac"; +import { TaxonomySlug } from "../enum"; export type TermDto = Term & { permissions: ResPerm; children: TermDto[]; hasChildren: boolean; + taxonomy: Taxonomy }; \ No newline at end of file From 19b6cbd0edad9a2c0a391181df3d03f65c564468 Mon Sep 17 00:00:00 2001 From: Rao <1227431568@qq.com> Date: Tue, 25 Feb 2025 17:45:00 +0800 Subject: [PATCH 03/23] rht02251745 --- .../main/home/components/CoursesSection.tsx | 44 +++---------------- .../home/components/CoursesSectionTag.tsx | 24 ++++++++++ 2 files changed, 29 insertions(+), 39 deletions(-) create mode 100644 apps/web/src/app/main/home/components/CoursesSectionTag.tsx diff --git a/apps/web/src/app/main/home/components/CoursesSection.tsx b/apps/web/src/app/main/home/components/CoursesSection.tsx index 2117baa..a5652e0 100755 --- a/apps/web/src/app/main/home/components/CoursesSection.tsx +++ b/apps/web/src/app/main/home/components/CoursesSection.tsx @@ -9,6 +9,7 @@ import { import { CourseDto, TaxonomySlug, TermDto } from "@nice/common"; import { api } from "@nice/client"; import CourseCard from "../../courses/components/CourseCard"; +import { CoursesSectionTag } from "./CoursesSectionTag"; interface GetTaxonomyProps { categories: string[]; isLoading: boolean; @@ -106,51 +107,16 @@ const CoursesSection: React.FC<CoursesSectionProps> = ({ <Spin className="m-3" /> ) : ( <> - <Tag - color={ - selectedCategory === "全部" - ? "blue" - : "default" - } - onClick={() => setSelectedCategory("全部")} - className={`px-6 py-2 text-base cursor-pointer rounded-full transition-all duration-300 ${ - selectedCategory === "全部" - ? "bg-blue-600 text-white shadow-lg" - : "bg-white text-gray-600 hover:bg-gray-100" - }`}> - 全部 - </Tag> - {gateGory.categories.map((category) => ( - <Tag - key={category} - color={ - selectedCategory === category - ? "blue" - : "default" - } - onClick={() => { - setSelectedCategory(category); - }} - className={`px-6 py-2 text-base cursor-pointer rounded-full transition-all duration-300 ${ - selectedCategory === category - ? "bg-blue-600 text-white shadow-lg" - : "bg-white text-gray-600 hover:bg-gray-100" - }`}> - {category} - </Tag> + {['全部',...gateGory.categories].map((category) => ( + <CoursesSectionTag category= {category} selectedCategory={selectedCategory} setSelectedCategory={setSelectedCategory}/> ))} </> )} </div> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8"> - {displayedCourses.length === 0 ? ( - <div className="col-span-full"> - <Empty - description="暂无课程" - image={Empty.PRESENTED_IMAGE_DEFAULT} - /> - </div> + {isDataLoading ? ( + <Spin className="m-3" /> ) : ( displayedCourses?.map((course) => ( <CourseCard course={course}></CourseCard> diff --git a/apps/web/src/app/main/home/components/CoursesSectionTag.tsx b/apps/web/src/app/main/home/components/CoursesSectionTag.tsx new file mode 100644 index 0000000..c03d718 --- /dev/null +++ b/apps/web/src/app/main/home/components/CoursesSectionTag.tsx @@ -0,0 +1,24 @@ +import { Tag } from "antd"; + +export function CoursesSectionTag({category, selectedCategory, setSelectedCategory}) { + return ( + <> + <Tag + key={category} + color={ + selectedCategory === category + ? "blue" + : "default" + } + onClick={() => { + setSelectedCategory(category); + }} + className={`px-6 py-2 text-base cursor-pointer rounded-full transition-all duration-300 ${selectedCategory === category + ? "bg-blue-600 text-white shadow-lg" + : "bg-white text-gray-600 hover:bg-gray-100" + }`}> + {category} + </Tag> + </> + ) +} From 6f560dc440416402dff4718a0f70eb29d176759f Mon Sep 17 00:00:00 2001 From: Rao <1227431568@qq.com> Date: Tue, 25 Feb 2025 17:47:09 +0800 Subject: [PATCH 04/23] add --- apps/web/src/app/main/home/components/CoursesSection.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/src/app/main/home/components/CoursesSection.tsx b/apps/web/src/app/main/home/components/CoursesSection.tsx index f34b1ac..2cda30d 100755 --- a/apps/web/src/app/main/home/components/CoursesSection.tsx +++ b/apps/web/src/app/main/home/components/CoursesSection.tsx @@ -109,8 +109,8 @@ const CoursesSection: React.FC<CoursesSectionProps> = ({ <Spin className="m-3" /> ) : ( <> - {['全部',...gateGory.categories].map((category) => ( - <CoursesSectionTag category= {category} selectedCategory={selectedCategory} setSelectedCategory={setSelectedCategory}/> + {['全部',...gateGory.categories].map((category,idx) => ( + <CoursesSectionTag key={idx} category= {category} selectedCategory={selectedCategory} setSelectedCategory={setSelectedCategory}/> ))} </> )} From 9a3d810421fc8b6909df551a1dc36b39d7114a6a Mon Sep 17 00:00:00 2001 From: Li1304553726 <1304553726@qq.com> Date: Tue, 25 Feb 2025 19:08:30 +0800 Subject: [PATCH 05/23] Li --- apps/web/src/app/main/courses/components/CourseCard.tsx | 4 ++-- apps/web/src/app/main/home/components/CoursesSection.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/web/src/app/main/courses/components/CourseCard.tsx b/apps/web/src/app/main/courses/components/CourseCard.tsx index c860934..16b7a2b 100755 --- a/apps/web/src/app/main/courses/components/CourseCard.tsx +++ b/apps/web/src/app/main/courses/components/CourseCard.tsx @@ -41,7 +41,7 @@ export default function CourseCard({ course }: CourseCardProps) { }> <div className="px-4"> <div className="flex gap-2 mb-4"> - {course.terms.map((term) => { + {course?.terms?.map((term) => { return ( <Tag key={term.id} @@ -85,7 +85,7 @@ export default function CourseCard({ course }: CourseCardProps) { <TeamOutlined className="text-blue-500 text-lg transform group-hover:scale-110 transition-transform duration-300" /> <div className="ml-2 flex items-center flex-grow"> <Text className="font-medium text-blue-500 hover:text-blue-600 transition-colors duration-300 truncate max-w-[120px]"> - {(course.depts.map((depts)=>depts.name))} + {(course?.depts?.map((depts)=>depts.name))} {/* {course?.depts?.[0]?.name} */} </Text> </div> diff --git a/apps/web/src/app/main/home/components/CoursesSection.tsx b/apps/web/src/app/main/home/components/CoursesSection.tsx index fc00aef..61948a1 100755 --- a/apps/web/src/app/main/home/components/CoursesSection.tsx +++ b/apps/web/src/app/main/home/components/CoursesSection.tsx @@ -123,8 +123,8 @@ const CoursesSection: React.FC<CoursesSectionProps> = ({ {isDataLoading ? ( <Spin className="m-3" /> ) : ( - displayedCourses?.map((course) => ( - <CourseCard course={course}></CourseCard> + displayedCourses?.map((course,index) => ( + <CourseCard course={course} key={index}></CourseCard> )) )} </div> From f01bfdf5dcdc79032fcd728125ce8296032d67bc Mon Sep 17 00:00:00 2001 From: Rao <1227431568@qq.com> Date: Tue, 25 Feb 2025 19:08:43 +0800 Subject: [PATCH 06/23] rht02251908 --- apps/web/src/app/main/home/components/CategorySection.tsx | 2 +- apps/web/src/components/common/editor/MindEditor.tsx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/web/src/app/main/home/components/CategorySection.tsx b/apps/web/src/app/main/home/components/CategorySection.tsx index d0735fa..e3decb4 100755 --- a/apps/web/src/app/main/home/components/CategorySection.tsx +++ b/apps/web/src/app/main/home/components/CategorySection.tsx @@ -188,7 +188,7 @@ const CategorySection = () => { } </div> - {!isLoading && courseCategoriesData.length > 8 && ( + {!isLoading && ( <div className="flex justify-center mt-12"> <Button type="default" diff --git a/apps/web/src/components/common/editor/MindEditor.tsx b/apps/web/src/components/common/editor/MindEditor.tsx index 732cfae..cd06b8e 100755 --- a/apps/web/src/components/common/editor/MindEditor.tsx +++ b/apps/web/src/components/common/editor/MindEditor.tsx @@ -13,6 +13,7 @@ export default function MindEditor() { toolBar: true, // default true nodeMenu: true, // default true keypress: true, // default true + locale: "zh_CN", }); // instance.install(NodeMenu); instance.init(MindElixir.new("新主题")); From a49b4af1a81fe73857c30c8e8aad87e82f7c0e99 Mon Sep 17 00:00:00 2001 From: ditiqi <ditiqi@163.com> Date: Tue, 25 Feb 2025 19:09:21 +0800 Subject: [PATCH 07/23] add --- .../main/courses/components/CourseCard.tsx | 40 +++++++++-------- .../main/courses/components/FilterSection.tsx | 2 +- apps/web/src/app/main/courses/mockData.ts | 44 ------------------- apps/web/src/app/main/courses/page.tsx | 3 +- 4 files changed, 23 insertions(+), 66 deletions(-) delete mode 100755 apps/web/src/app/main/courses/mockData.ts diff --git a/apps/web/src/app/main/courses/components/CourseCard.tsx b/apps/web/src/app/main/courses/components/CourseCard.tsx index c860934..f7e93be 100755 --- a/apps/web/src/app/main/courses/components/CourseCard.tsx +++ b/apps/web/src/app/main/courses/components/CourseCard.tsx @@ -1,5 +1,4 @@ import { Card, Rate, Tag, Typography, Button } from "antd"; -import { Course } from "../mockData"; import { UserOutlined, ClockCircleOutlined, @@ -19,7 +18,6 @@ export default function CourseCard({ course }: CourseCardProps) { navigate(`/course/${course.id}/detail`); }; - return ( <Card onClick={() => handleClick(course)} @@ -41,21 +39,25 @@ export default function CourseCard({ course }: CourseCardProps) { }> <div className="px-4"> <div className="flex gap-2 mb-4"> - {course.terms.map((term) => { - return ( - <Tag - key={term.id} - // color={term.taxonomy.slug===TaxonomySlug.CATEGORY? "blue" : "green"} - color={term?.taxonomy?.slug === TaxonomySlug.CATEGORY - ? "blue" - : term?.taxonomy?.slug === TaxonomySlug.LEVEL - ? "green" - : "blue"} - className="px-3 py-1 rounded-full bg-blue-100 text-blue-600 border-0"> - {term.name} - </Tag> - ); - })} + {course.terms.map((term) => { + return ( + <Tag + key={term.id} + // color={term.taxonomy.slug===TaxonomySlug.CATEGORY? "blue" : "green"} + color={ + term?.taxonomy?.slug === + TaxonomySlug.CATEGORY + ? "blue" + : term?.taxonomy?.slug === + TaxonomySlug.LEVEL + ? "green" + : "blue" + } + className="px-3 py-1 rounded-full bg-blue-100 text-blue-600 border-0"> + {term.name} + </Tag> + ); + })} {/* <Tag color="blue" className="px-3 py-1 rounded-full bg-blue-100 text-blue-600 border-0"> @@ -85,8 +87,8 @@ export default function CourseCard({ course }: CourseCardProps) { <TeamOutlined className="text-blue-500 text-lg transform group-hover:scale-110 transition-transform duration-300" /> <div className="ml-2 flex items-center flex-grow"> <Text className="font-medium text-blue-500 hover:text-blue-600 transition-colors duration-300 truncate max-w-[120px]"> - {(course.depts.map((depts)=>depts.name))} - {/* {course?.depts?.[0]?.name} */} + {course.depts.map((depts) => depts.name)} + {/* {course?.depts?.[0]?.name} */} </Text> </div> <span className="text-xs font-medium text-gray-500"> diff --git a/apps/web/src/app/main/courses/components/FilterSection.tsx b/apps/web/src/app/main/courses/components/FilterSection.tsx index 69fd828..2c754e4 100755 --- a/apps/web/src/app/main/courses/components/FilterSection.tsx +++ b/apps/web/src/app/main/courses/components/FilterSection.tsx @@ -1,5 +1,5 @@ import { Checkbox, Divider, Radio, Space, Spin } from "antd"; -import { categories, levels } from "../mockData"; + import { TaxonomySlug, TermDto } from "@nice/common"; import { useEffect, useMemo } from "react"; diff --git a/apps/web/src/app/main/courses/mockData.ts b/apps/web/src/app/main/courses/mockData.ts deleted file mode 100755 index 096d174..0000000 --- a/apps/web/src/app/main/courses/mockData.ts +++ /dev/null @@ -1,44 +0,0 @@ -export interface Course { - id: string; - title: string; - description: string; - instructor: string; - price: number; - originalPrice: number; - category: string; - level: string; - thumbnail: string; - rating: number; - enrollments: number; - duration: string; -} - -export const categories = [ - "计算机科学", - "数据科学", - "商业管理", - "人工智能", - "软件开发", - "网络安全", - "云计算", - "前端开发", - "后端开发", - "移动开发" -]; - -export const levels = ["入门", "初级", "中级", "高级"]; - -export const mockCourses: Course[] = Array.from({ length: 50 }, (_, i) => ({ - id: `course-${i + 1}`, - title: `${categories[i % categories.length]}课程 ${i + 1}`, - description: "本课程将带你深入了解该领域的核心概念和实践应用,通过实战项目提升你的专业技能。", - instructor: `讲师 ${i + 1}`, - price: Math.floor(Math.random() * 500 + 99), - originalPrice: Math.floor(Math.random() * 1000 + 299), - category: categories[i % categories.length], - level: levels[i % levels.length], - thumbnail: `/api/placeholder/280/160`, - rating: Number((Math.random() * 2 + 3).toFixed(1)), - enrollments: Math.floor(Math.random() * 10000), - duration: `${Math.floor(Math.random() * 20 + 10)}小时` -})); \ No newline at end of file diff --git a/apps/web/src/app/main/courses/page.tsx b/apps/web/src/app/main/courses/page.tsx index fa2fe9a..803b372 100755 --- a/apps/web/src/app/main/courses/page.tsx +++ b/apps/web/src/app/main/courses/page.tsx @@ -1,5 +1,4 @@ import { useState, useMemo, useEffect } from "react"; -import { mockCourses } from "./mockData"; import FilterSection from "./components/FilterSection"; import CourseList from "./components/CourseList"; import { api } from "@nice/client"; @@ -19,7 +18,7 @@ interface paginationData { } export default function CoursesPage() { const { searchValue, setSearchValue } = useMainContext(); - + return ( <> <div className="min-h-screen bg-gray-50"> From dc8bc7268783a1a2cc11576d7a68743e42f9dfc9 Mon Sep 17 00:00:00 2001 From: ditiqi <ditiqi@163.com> Date: Tue, 25 Feb 2025 19:30:56 +0800 Subject: [PATCH 08/23] aff --- .../main/courses/components/CourseList.tsx | 45 ++++++++++++------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/apps/web/src/app/main/courses/components/CourseList.tsx b/apps/web/src/app/main/courses/components/CourseList.tsx index 4550795..97001f0 100755 --- a/apps/web/src/app/main/courses/components/CourseList.tsx +++ b/apps/web/src/app/main/courses/components/CourseList.tsx @@ -1,6 +1,6 @@ -import { Pagination, Empty } from "antd"; +import { Pagination, Empty, Skeleton } from "antd"; import CourseCard from "./CourseCard"; -import { CourseDto, Prisma } from "@nice/common"; +import { courseDetailSelect, CourseDto, Prisma } from "@nice/common"; import { api } from "@nice/client"; import { DefaultArgs } from "@prisma/client/runtime/library"; import { useEffect, useMemo, useState } from "react"; @@ -11,6 +11,8 @@ interface CourseListProps { where?: Prisma.PostWhereInput; select?: Prisma.PostSelect<DefaultArgs>; }; + cols?: number; + showPagination?: boolean; } interface CoursesPagnationProps { data: { @@ -19,10 +21,15 @@ interface CoursesPagnationProps { }; isLoading: boolean; } -export default function CourseList({ params }: CourseListProps) { +export default function CourseList({ + params, + cols = 3, + showPagination = true, +}: CourseListProps) { const [currentPage, setCurrentPage] = useState<number>(params?.page || 1); const { data, isLoading }: CoursesPagnationProps = api.post.findManyWithPagination.useQuery({ + select: courseDetailSelect, ...params, page: currentPage, }); @@ -51,20 +58,26 @@ export default function CourseList({ params }: CourseListProps) { <div className="space-y-6"> {courses.length > 0 ? ( <> - <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> - {courses.map((course) => ( - <CourseCard key={course.id} course={course} /> - ))} - </div> - <div className="flex justify-center mt-8"> - <Pagination - current={currentPage} - total={totalPages} - pageSize={params?.pageSize} - onChange={onPageChange} - showSizeChanger={false} - /> + <div className={`grid grid-cols-${cols} gap-6`}> + {isLoading ? ( + <Skeleton paragraph={{ rows: 5 }}></Skeleton> + ) : ( + courses.map((course) => ( + <CourseCard key={course.id} course={course} /> + )) + )} </div> + {showPagination && ( + <div className="flex justify-center mt-8"> + <Pagination + current={currentPage} + total={totalPages} + pageSize={params?.pageSize} + onChange={onPageChange} + showSizeChanger={false} + /> + </div> + )} </> ) : ( <Empty description="暂无相关课程" /> From 9319f112b429b2d26c3d1a88b486f0f5b6c77d86 Mon Sep 17 00:00:00 2001 From: ditiqi <ditiqi@163.com> Date: Tue, 25 Feb 2025 19:30:59 +0800 Subject: [PATCH 09/23] add --- .../main/home/components/CategorySection.tsx | 358 ++++++++---------- 1 file changed, 168 insertions(+), 190 deletions(-) diff --git a/apps/web/src/app/main/home/components/CategorySection.tsx b/apps/web/src/app/main/home/components/CategorySection.tsx index e3decb4..ddfeab4 100755 --- a/apps/web/src/app/main/home/components/CategorySection.tsx +++ b/apps/web/src/app/main/home/components/CategorySection.tsx @@ -1,157 +1,141 @@ -import React, { useState, useCallback, useEffect, useMemo } from 'react'; -import { Typography, Button, Spin } from 'antd'; -import { stringToColor, TaxonomySlug, TermDto } from '@nice/common'; -import { api,} from '@nice/client'; -import { ControlOutlined } from '@ant-design/icons'; -import { useNavigate, useSearchParams } from 'react-router-dom'; +import React, { useState, useCallback, useEffect, useMemo } from "react"; +import { Typography, Button, Spin } from "antd"; +import { stringToColor, TaxonomySlug, TermDto } from "@nice/common"; +import { api } from "@nice/client"; +import { ControlOutlined } from "@ant-design/icons"; +import { useNavigate, useSearchParams } from "react-router-dom"; const { Title, Text } = Typography; interface CourseCategory { - name: string; - count: number; - description: string; + name: string; + count: number; + description: string; } -// const courseCategories: CourseCategory[] = [ -// { -// name: '计算机基础', -// count: 120, -// description: '计算机组成原理、操作系统、网络等基础知识' -// }, -// { -// name: '编程语言', -// count: 85, -// description: 'Python、Java、JavaScript等主流编程语言' -// }, -// { -// name: '人工智能', -// count: 65, -// description: '机器学习、深度学习、自然语言处理等前沿技术' -// }, -// { -// name: '数据科学', -// count: 45, -// description: '数据分析、数据可视化、商业智能等' -// }, -// { -// name: '云计算', -// count: 38, -// description: '云服务、容器化、微服务架构等' -// }, -// { -// name: '网络安全', -// count: 42, -// description: '网络安全基础、渗透测试、安全防护等' -// } -// ]; - - const CategorySection = () => { - const [hoveredIndex, setHoveredIndex] = useState<number | null>(null); - const [showAll, setShowAll] = useState(false); - //获得分类 - const {data:courseCategoriesData,isLoading} :{data:TermDto[],isLoading:boolean}= api.term.findMany.useQuery({ - where:{ - taxonomy: { - slug:TaxonomySlug.CATEGORY - } - }, - include:{ - children :true - }, - orderBy: { - createdAt: 'desc', // 按创建时间降序排列 - }, - take:8 - }) - // 分类展示 - const [displayedCategories,setDisplayedCategories] = useState<TermDto[]>([]) - useEffect(() => { - console.log(courseCategoriesData); - // 如果 showAll 为 true,则显示所有分类数据, -// 如果 showAll 为 false,则只显示前 8 个分类数据, - if(!isLoading){ - if(showAll){ - setDisplayedCategories(courseCategoriesData) - }else{ - setDisplayedCategories(courseCategoriesData.slice(0,8)) - } - } - }, [courseCategoriesData,showAll]); - // const courseCategories: CourseCategory[] = useMemo(() => { - // return data?.map((term) => ({ - // name: term.name, - // count: term.hasChildren ? term.children.length : 0, - // description: term.description - // })) || []; - // },[data]) - const handleMouseEnter = useCallback((index: number) => { - setHoveredIndex(index); - }, []); + const [hoveredIndex, setHoveredIndex] = useState<number | null>(null); + const [showAll, setShowAll] = useState(false); + //获得分类 + const { + data: courseCategoriesData, + isLoading, + }: { data: TermDto[]; isLoading: boolean } = api.term.findMany.useQuery({ + where: { + taxonomy: { + slug: TaxonomySlug.CATEGORY, + }, + }, + include: { + children: true, + }, + orderBy: { + createdAt: "desc", // 按创建时间降序排列 + }, + take: 8, + }); + // 分类展示 + const [displayedCategories, setDisplayedCategories] = useState<TermDto[]>( + [] + ); + useEffect(() => { + console.log(courseCategoriesData); + // 如果 showAll 为 true,则显示所有分类数据, + // 如果 showAll 为 false,则只显示前 8 个分类数据, + if (!isLoading) { + if (showAll) { + setDisplayedCategories(courseCategoriesData); + } else { + setDisplayedCategories(courseCategoriesData.slice(0, 8)); + } + } + }, [courseCategoriesData, showAll]); + // const courseCategories: CourseCategory[] = useMemo(() => { + // return data?.map((term) => ({ + // name: term.name, + // count: term.hasChildren ? term.children.length : 0, + // description: term.description + // })) || []; + // },[data]) + const handleMouseEnter = useCallback((index: number) => { + setHoveredIndex(index); + }, []); - const handleMouseLeave = useCallback(() => { - setHoveredIndex(null); - }, []); + const handleMouseLeave = useCallback(() => { + setHoveredIndex(null); + }, []); - const navigate = useNavigate() + const navigate = useNavigate(); - return ( - <section className="py-32 relative overflow-hidden"> - <div className="max-w-screen-2xl mx-auto px-4 relative"> - <div className="text-center mb-24"> - <Title level={2} className="font-bold text-5xl mb-6 bg-gradient-to-r from-gray-900 via-gray-700 to-gray-800 bg-clip-text text-transparent motion-safe:animate-gradient-x"> - 探索课程分类 - - - 选择你感兴趣的方向,开启学习之旅 - -
-
- { - isLoading ? : - (displayedCategories.map((category, index) => { - const categoryColor = stringToColor(category.name); - const isHovered = hoveredIndex === index; - - return ( -
handleMouseEnter(index)} - onMouseLeave={handleMouseLeave} - role="button" - tabIndex={0} - aria-label={`查看${category.name}课程类别`} - onClick={()=>{ - console.log(category.name) - navigate(`/courses?category=${category.name}`) - window.scrollTo({ top: 0, behavior: 'smooth' }) - }} - > -
-
-
-
-
-
- - {category.name} - - {/* +
+
+ + 探索课程分类 + + + 选择你感兴趣的方向,开启学习之旅 + +
+
+ {isLoading ? ( + + ) : ( + displayedCategories.map((category, index) => { + const categoryColor = stringToColor(category.name); + const isHovered = hoveredIndex === index; + + return ( +
handleMouseEnter(index)} + onMouseLeave={handleMouseLeave} + role="button" + tabIndex={0} + aria-label={`查看${category.name}课程类别`} + onClick={() => { + console.log(category.name); + navigate( + `/courses?category=${category.name}` + ); + window.scrollTo({ + top: 0, + behavior: "smooth", + }); + }}> +
+
+
+
+
+
+ + {category.name} + + {/* { > {category.children.length} 门课程 */} -
- - {category.description} - -
- 了解更多 - - → - -
-
-
- ); - })) - } - -
- {!isLoading && ( -
- -
- )} -
- - ); +
+ + {category.description} + +
+ 了解更多 + + → + +
+
+
+ ); + }) + )} +
+ {!isLoading && ( +
+ +
+ )} +
+ + ); }; -export default CategorySection; \ No newline at end of file +export default CategorySection; From 4eebb49c7f2574a66103b7fe57a938d7c751d859 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Tue, 25 Feb 2025 19:31:01 +0800 Subject: [PATCH 10/23] add --- .../main/home/components/CoursesSection.tsx | 101 ++++++------------ 1 file changed, 35 insertions(+), 66 deletions(-) diff --git a/apps/web/src/app/main/home/components/CoursesSection.tsx b/apps/web/src/app/main/home/components/CoursesSection.tsx index 61948a1..bbbbfde 100755 --- a/apps/web/src/app/main/home/components/CoursesSection.tsx +++ b/apps/web/src/app/main/home/components/CoursesSection.tsx @@ -1,20 +1,11 @@ -import React, { useState, useMemo, useEffect } from "react"; +import React, { useState, useMemo } from "react"; import { useNavigate } from "react-router-dom"; -import { Button, Card, Typography, Tag, Spin, Empty } from "antd"; -import { - PlayCircleOutlined, - TeamOutlined, - ArrowRightOutlined, -} from "@ant-design/icons"; -import { - courseDetailSelect, - CourseDto, - TaxonomySlug, - TermDto, -} from "@nice/common"; +import { Button, Typography, Skeleton } from "antd"; +import { ArrowRightOutlined } from "@ant-design/icons"; +import { TaxonomySlug, TermDto } from "@nice/common"; import { api } from "@nice/client"; -import CourseCard from "../../courses/components/CourseCard"; import { CoursesSectionTag } from "./CoursesSectionTag"; +import CourseList from "../../courses/components/CourseList"; interface GetTaxonomyProps { categories: string[]; isLoading: boolean; @@ -27,11 +18,7 @@ function useGetTaxonomy({ type }): GetTaxonomyProps { slug: type, }, }, - include: { - children: true, - }, take: 10, // 只取前10个 - orderBy: {}, }); const categories = useMemo(() => { const allCategories = isLoading @@ -41,26 +28,6 @@ function useGetTaxonomy({ type }): GetTaxonomyProps { }, [data]); return { categories, isLoading }; } -// 不同分类跳转 -function useFetchCoursesByCategory(category: string) { - const isAll = category === "全部"; - const { data, isLoading }: { data: CourseDto[]; isLoading: boolean } = - api.post.findMany.useQuery({ - where: isAll - ? {} - : { - terms: { - some: { - name: category, - }, - }, - }, - take: 8, - select: courseDetailSelect, - }); - - return { data, isLoading }; -} const { Title, Text } = Typography; interface CoursesSectionProps { title: string; @@ -70,25 +37,13 @@ interface CoursesSectionProps { const CoursesSection: React.FC = ({ title, description, + initialVisibleCoursesCount = 8, }) => { const navigate = useNavigate(); const [selectedCategory, setSelectedCategory] = useState("全部"); const gateGory: GetTaxonomyProps = useGetTaxonomy({ type: TaxonomySlug.CATEGORY, }); - const { data, isLoading: isDataLoading } = - useFetchCoursesByCategory(selectedCategory); - const filteredCourses = useMemo(() => { - return selectedCategory === "全部" - ? data - : data?.filter((c) => - c.terms.some((t) => t.name === selectedCategory) - ); - }, [selectedCategory, data]); - const displayedCourses = isDataLoading ? [] : filteredCourses; - useEffect(()=>{ - console.log(data) - }) return (
@@ -106,28 +61,42 @@ const CoursesSection: React.FC = ({
-
{gateGory.isLoading ? ( - + ) : ( <> - {['全部',...gateGory.categories].map((category,idx) => ( - - ))} + {["全部", ...gateGory.categories].map( + (category, idx) => ( + + ) + )} )}
- -
- {isDataLoading ? ( - - ) : ( - displayedCourses?.map((course,index) => ( - - )) - )} -
+ {
From 5686a337f304e23187bd69d6102272582dada70f Mon Sep 17 00:00:00 2001 From: ditiqi Date: Tue, 25 Feb 2025 19:50:36 +0800 Subject: [PATCH 11/23] add --- apps/server/src/models/term/term.router.ts | 2 +- .../main/courses/components/FilterSection.tsx | 84 +++---------------- .../main/courses/layout/AllCoursesLayout.tsx | 27 ++++++ apps/web/src/app/main/courses/page.tsx | 12 +-- .../components/models/term/term-select.tsx | 17 ---- 5 files changed, 42 insertions(+), 100 deletions(-) create mode 100644 apps/web/src/app/main/courses/layout/AllCoursesLayout.tsx diff --git a/apps/server/src/models/term/term.router.ts b/apps/server/src/models/term/term.router.ts index 43afff5..548526c 100755 --- a/apps/server/src/models/term/term.router.ts +++ b/apps/server/src/models/term/term.router.ts @@ -69,7 +69,7 @@ export class TermRouter { const { staff } = ctx; return await this.termService.getParentSimpleTree(staff, input); }), - getTreeData: this.trpc.protectProcedure + getTreeData: this.trpc.procedure .input(TermMethodSchema.getTreeData) .query(async ({ input }) => { return await this.termService.getTreeData(input); diff --git a/apps/web/src/app/main/courses/components/FilterSection.tsx b/apps/web/src/app/main/courses/components/FilterSection.tsx index 2c754e4..f7a6ced 100755 --- a/apps/web/src/app/main/courses/components/FilterSection.tsx +++ b/apps/web/src/app/main/courses/components/FilterSection.tsx @@ -5,86 +5,26 @@ import { TaxonomySlug, TermDto } from "@nice/common"; import { useEffect, useMemo } from "react"; import { api } from "@nice/client"; import { useSearchParams } from "react-router-dom"; -import TermTree from "@web/src/components/models/term/term-tree"; import TermSelect from "@web/src/components/models/term/term-select"; -interface FilterSectionProps { - selectedCategory: string; - selectedLevel: string; - onCategoryChange: (category: string) => void; - onLevelChange: (level: string) => void; -} - -interface GetTaxonomyProps { - categories: string[]; - isLoading: boolean; -} - -function useGetTaxonomy({ type }): GetTaxonomyProps { - const { data, isLoading }: { data: TermDto[]; isLoading: boolean } = - api.term.findMany.useQuery({ - where: { - taxonomy: { - //TaxonomySlug.CATEGORY - slug: type, - }, - }, - include: { - children: true, - }, - take: 10, // 只取前10个 - orderBy: { - createdAt: "desc", // 按创建时间降序排列 - }, - }); - const categories = useMemo(() => { - const allCategories = isLoading - ? [] - : data?.map((course) => course.name); - return [...Array.from(new Set(allCategories))]; - }, [data]); - return { categories, isLoading }; -} - -export default function FilterSection({ - selectedCategory, - selectedLevel, - onCategoryChange, - onLevelChange, -}: FilterSectionProps) { - const gateGory: GetTaxonomyProps = useGetTaxonomy({ - type: TaxonomySlug.CATEGORY, - }); - const levels: GetTaxonomyProps = useGetTaxonomy({ - type: TaxonomySlug.LEVEL, - }); - - const [searchParams, setSearchParams] = useSearchParams(); - useEffect(() => { - if (searchParams.get("category")) - onCategoryChange(searchParams.get("category")); - }, [searchParams.get("category")]); - +export default function FilterSection() { const { data: taxonomies } = api.taxonomy.getAll.useQuery({}); return ( -
- {taxonomies?.map((tax) => { +
+ {taxonomies?.map((tax, index) => { return ( - <> -
-

- {tax?.name} -

- -
- +
+

+ {tax?.name} +

+ + {index < taxonomies.length - 1 && ( + + )} +
); })} - -
); } diff --git a/apps/web/src/app/main/courses/layout/AllCoursesLayout.tsx b/apps/web/src/app/main/courses/layout/AllCoursesLayout.tsx new file mode 100644 index 0000000..b3089f1 --- /dev/null +++ b/apps/web/src/app/main/courses/layout/AllCoursesLayout.tsx @@ -0,0 +1,27 @@ +import { useMainContext } from "../../layout/MainProvider"; +import CourseList from "../components/CourseList"; +import FilterSection from "../components/FilterSection"; + +export function AllCoursesLayout() { + const { searchValue, setSearchValue } = useMainContext(); + return ( + <> +
+
+
+ +
+
+ +
+
+
+ + ); +} +export default AllCoursesLayout; diff --git a/apps/web/src/app/main/courses/page.tsx b/apps/web/src/app/main/courses/page.tsx index 803b372..0b0fb43 100755 --- a/apps/web/src/app/main/courses/page.tsx +++ b/apps/web/src/app/main/courses/page.tsx @@ -11,24 +11,16 @@ import { import { useSearchParams } from "react-router-dom"; import { set } from "idb-keyval"; import { useMainContext } from "../layout/MainProvider"; +import AllCoursesLayout from "./layout/AllCoursesLayout"; interface paginationData { items: CourseDto[]; totalPages: number; } export default function CoursesPage() { - const { searchValue, setSearchValue } = useMainContext(); - return ( <> -
-
{searchValue}
- -
+ ); } diff --git a/apps/web/src/components/models/term/term-select.tsx b/apps/web/src/components/models/term/term-select.tsx index ce5d9be..07b4741 100755 --- a/apps/web/src/components/models/term/term-select.tsx +++ b/apps/web/src/components/models/term/term-select.tsx @@ -10,8 +10,6 @@ interface TermSelectProps { onChange?: (value: string | string[]) => void; placeholder?: string; multiple?: boolean; - // rootId?: string; - // domain?: boolean; taxonomyId?: string; disabled?: boolean; className?: string; @@ -27,9 +25,7 @@ export default function TermSelect({ multiple = false, taxonomyId, domainId, - // rootId = null, disabled = false, - // domain = undefined, }: TermSelectProps) { const utils = api.useUtils(); const [listTreeData, setListTreeData] = useState< @@ -125,20 +121,9 @@ export default function TermSelect({ }; const handleExpand = async (keys: React.Key[]) => { - // console.log(keys); try { const allKeyIds = keys.map((key) => key.toString()).filter(Boolean) || []; - // const expandedNodes = await Promise.all( - // keys.map(async (key) => { - // return await utils.department.getChildSimpleTree.fetch({ - // deptId: key.toString(), - // domain, - // }); - // }) - // ); - // - //上面那样一个个拉会拉爆,必须直接拉deptIds const expandedNodes = await utils.term.getChildSimpleTree.fetch({ termIds: allKeyIds, taxonomyId, @@ -154,7 +139,6 @@ export default function TermSelect({ console.error("Error expanding nodes with keys", keys, ":", error); } }; - const handleDropdownVisibleChange = async (open: boolean) => { if (open) { // This will attempt to expand all nodes and fetch their children when the dropdown opens @@ -162,7 +146,6 @@ export default function TermSelect({ await handleExpand(allKeys); } }; - return ( Date: Tue, 25 Feb 2025 20:15:48 +0800 Subject: [PATCH 12/23] rht02252015 --- .../main/courses/components/CourseList.tsx | 2 +- .../main/home/components/CategorySection.tsx | 122 ++---------------- .../home/components/CategorySectionCard.tsx | 64 +++++++++ .../main/home/components/CoursesSection.tsx | 16 +-- .../app/main/home/components/LookForMore.tsx | 24 ++++ 5 files changed, 105 insertions(+), 123 deletions(-) create mode 100644 apps/web/src/app/main/home/components/CategorySectionCard.tsx create mode 100644 apps/web/src/app/main/home/components/LookForMore.tsx diff --git a/apps/web/src/app/main/courses/components/CourseList.tsx b/apps/web/src/app/main/courses/components/CourseList.tsx index 97001f0..2c1ce08 100755 --- a/apps/web/src/app/main/courses/components/CourseList.tsx +++ b/apps/web/src/app/main/courses/components/CourseList.tsx @@ -58,7 +58,7 @@ export default function CourseList({
{courses.length > 0 ? ( <> -
+
{isLoading ? ( ) : ( diff --git a/apps/web/src/app/main/home/components/CategorySection.tsx b/apps/web/src/app/main/home/components/CategorySection.tsx index ddfeab4..9584193 100755 --- a/apps/web/src/app/main/home/components/CategorySection.tsx +++ b/apps/web/src/app/main/home/components/CategorySection.tsx @@ -1,18 +1,13 @@ import React, { useState, useCallback, useEffect, useMemo } from "react"; -import { Typography, Button, Spin } from "antd"; +import { Typography, Button, Spin, Skeleton } from "antd"; import { stringToColor, TaxonomySlug, TermDto } from "@nice/common"; import { api } from "@nice/client"; import { ControlOutlined } from "@ant-design/icons"; import { useNavigate, useSearchParams } from "react-router-dom"; +import LookForMore from "./LookForMore"; +import CategorySectionCard from "./CategorySectionCard"; const { Title, Text } = Typography; - -interface CourseCategory { - name: string; - count: number; - description: string; -} - const CategorySection = () => { const [hoveredIndex, setHoveredIndex] = useState(null); const [showAll, setShowAll] = useState(false); @@ -39,9 +34,6 @@ const CategorySection = () => { [] ); useEffect(() => { - console.log(courseCategoriesData); - // 如果 showAll 为 true,则显示所有分类数据, - // 如果 showAll 为 false,则只显示前 8 个分类数据, if (!isLoading) { if (showAll) { setDisplayedCategories(courseCategoriesData); @@ -50,13 +42,6 @@ const CategorySection = () => { } } }, [courseCategoriesData, showAll]); - // const courseCategories: CourseCategory[] = useMemo(() => { - // return data?.map((term) => ({ - // name: term.name, - // count: term.hasChildren ? term.children.length : 0, - // description: term.description - // })) || []; - // },[data]) const handleMouseEnter = useCallback((index: number) => { setHoveredIndex(index); }, []); @@ -82,106 +67,27 @@ const CategorySection = () => {
{isLoading ? ( - + ) : ( displayedCategories.map((category, index) => { const categoryColor = stringToColor(category.name); const isHovered = hoveredIndex === index; return ( -
handleMouseEnter(index)} - onMouseLeave={handleMouseLeave} - role="button" - tabIndex={0} - aria-label={`查看${category.name}课程类别`} - onClick={() => { - console.log(category.name); - navigate( - `/courses?category=${category.name}` - ); - window.scrollTo({ - top: 0, - behavior: "smooth", - }); - }}> -
-
-
-
-
-
- - {category.name} - - {/* - {category.children.length} 门课程 - */} -
- - {category.description} - -
- 了解更多 - - → - -
-
-
+ ); }) )}
- {!isLoading && ( -
- -
- )} +
); diff --git a/apps/web/src/app/main/home/components/CategorySectionCard.tsx b/apps/web/src/app/main/home/components/CategorySectionCard.tsx new file mode 100644 index 0000000..a91525c --- /dev/null +++ b/apps/web/src/app/main/home/components/CategorySectionCard.tsx @@ -0,0 +1,64 @@ +import { useNavigate } from "react-router-dom"; +import { Typography } from "antd"; +export default function CategorySectionCard({index,handleMouseEnter,handleMouseLeave,category,categoryColor,isHovered,}) { + const navigate = useNavigate() + const { Title, Text } = Typography; + return ( +
handleMouseEnter(index)} + onMouseLeave={handleMouseLeave} + role="button" + tabIndex={0} + aria-label={`查看${category.name}课程类别`} + onClick={() => { + console.log(category.name); + navigate( + `/courses?category=${category.name}` + ); + window.scrollTo({ + top: 0, + behavior: "smooth", + }); + }}> +
+
+
+
+
+
+ + {category.name} + +
+
+ 了解更多 + + → + +
+
+
+ ) +} \ No newline at end of file diff --git a/apps/web/src/app/main/home/components/CoursesSection.tsx b/apps/web/src/app/main/home/components/CoursesSection.tsx index bbbbfde..bc2e5a4 100755 --- a/apps/web/src/app/main/home/components/CoursesSection.tsx +++ b/apps/web/src/app/main/home/components/CoursesSection.tsx @@ -6,6 +6,7 @@ import { TaxonomySlug, TermDto } from "@nice/common"; import { api } from "@nice/client"; import { CoursesSectionTag } from "./CoursesSectionTag"; import CourseList from "../../courses/components/CourseList"; +import LookForMore from "./LookForMore"; interface GetTaxonomyProps { categories: string[]; isLoading: boolean; @@ -97,20 +98,7 @@ const CoursesSection: React.FC = ({ }} showPagination={false} cols={4}> - { -
-
-
- -
-
- } +
); diff --git a/apps/web/src/app/main/home/components/LookForMore.tsx b/apps/web/src/app/main/home/components/LookForMore.tsx new file mode 100644 index 0000000..88e1b41 --- /dev/null +++ b/apps/web/src/app/main/home/components/LookForMore.tsx @@ -0,0 +1,24 @@ +import { ArrowRightOutlined } from "@ant-design/icons"; +import { Button } from "antd"; +import { useNavigate } from "react-router-dom"; + +export default function LookForMore({to}:{to:string}) { + const navigate = useNavigate(); + return ( + <> +
+
+
+ +
+
+ + ) + +} From ead1d926c6170f1a7731105207c2451a783f7540 Mon Sep 17 00:00:00 2001 From: Li1304553726 <1304553726@qq.com> Date: Tue, 25 Feb 2025 20:34:51 +0800 Subject: [PATCH 13/23] Li_0225 --- apps/web/src/app/main/home/components/CategorySection.tsx | 6 +----- apps/web/src/app/main/home/components/CoursesSection.tsx | 5 +---- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/apps/web/src/app/main/home/components/CategorySection.tsx b/apps/web/src/app/main/home/components/CategorySection.tsx index 9584193..1c0b8a6 100755 --- a/apps/web/src/app/main/home/components/CategorySection.tsx +++ b/apps/web/src/app/main/home/components/CategorySection.tsx @@ -2,8 +2,6 @@ import React, { useState, useCallback, useEffect, useMemo } from "react"; import { Typography, Button, Spin, Skeleton } from "antd"; import { stringToColor, TaxonomySlug, TermDto } from "@nice/common"; import { api } from "@nice/client"; -import { ControlOutlined } from "@ant-design/icons"; -import { useNavigate, useSearchParams } from "react-router-dom"; import LookForMore from "./LookForMore"; import CategorySectionCard from "./CategorySectionCard"; @@ -50,8 +48,6 @@ const CategorySection = () => { setHoveredIndex(null); }, []); - const navigate = useNavigate(); - return (
@@ -67,7 +63,7 @@ const CategorySection = () => {
{isLoading ? ( - + ) : ( displayedCategories.map((category, index) => { const categoryColor = stringToColor(category.name); diff --git a/apps/web/src/app/main/home/components/CoursesSection.tsx b/apps/web/src/app/main/home/components/CoursesSection.tsx index bc2e5a4..6bd8858 100755 --- a/apps/web/src/app/main/home/components/CoursesSection.tsx +++ b/apps/web/src/app/main/home/components/CoursesSection.tsx @@ -1,7 +1,5 @@ import React, { useState, useMemo } from "react"; -import { useNavigate } from "react-router-dom"; -import { Button, Typography, Skeleton } from "antd"; -import { ArrowRightOutlined } from "@ant-design/icons"; +import { Typography, Skeleton } from "antd"; import { TaxonomySlug, TermDto } from "@nice/common"; import { api } from "@nice/client"; import { CoursesSectionTag } from "./CoursesSectionTag"; @@ -40,7 +38,6 @@ const CoursesSection: React.FC = ({ description, initialVisibleCoursesCount = 8, }) => { - const navigate = useNavigate(); const [selectedCategory, setSelectedCategory] = useState("全部"); const gateGory: GetTaxonomyProps = useGetTaxonomy({ type: TaxonomySlug.CATEGORY, From 13b8c10c62ac09be71cb60c59b659b9694a3ddf5 Mon Sep 17 00:00:00 2001 From: Rao <1227431568@qq.com> Date: Tue, 25 Feb 2025 20:40:04 +0800 Subject: [PATCH 14/23] rht0225 --- .../main/home/components/CategorySection.tsx | 30 ++----------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/apps/web/src/app/main/home/components/CategorySection.tsx b/apps/web/src/app/main/home/components/CategorySection.tsx index 9584193..f7b3340 100755 --- a/apps/web/src/app/main/home/components/CategorySection.tsx +++ b/apps/web/src/app/main/home/components/CategorySection.tsx @@ -1,17 +1,13 @@ import React, { useState, useCallback, useEffect, useMemo } from "react"; -import { Typography, Button, Spin, Skeleton } from "antd"; +import { Typography, Skeleton } from "antd"; import { stringToColor, TaxonomySlug, TermDto } from "@nice/common"; import { api } from "@nice/client"; -import { ControlOutlined } from "@ant-design/icons"; -import { useNavigate, useSearchParams } from "react-router-dom"; import LookForMore from "./LookForMore"; import CategorySectionCard from "./CategorySectionCard"; const { Title, Text } = Typography; const CategorySection = () => { const [hoveredIndex, setHoveredIndex] = useState(null); - const [showAll, setShowAll] = useState(false); - //获得分类 const { data: courseCategoriesData, isLoading, @@ -21,27 +17,8 @@ const CategorySection = () => { slug: TaxonomySlug.CATEGORY, }, }, - include: { - children: true, - }, - orderBy: { - createdAt: "desc", // 按创建时间降序排列 - }, take: 8, }); - // 分类展示 - const [displayedCategories, setDisplayedCategories] = useState( - [] - ); - useEffect(() => { - if (!isLoading) { - if (showAll) { - setDisplayedCategories(courseCategoriesData); - } else { - setDisplayedCategories(courseCategoriesData.slice(0, 8)); - } - } - }, [courseCategoriesData, showAll]); const handleMouseEnter = useCallback((index: number) => { setHoveredIndex(index); }, []); @@ -49,9 +26,6 @@ const CategorySection = () => { const handleMouseLeave = useCallback(() => { setHoveredIndex(null); }, []); - - const navigate = useNavigate(); - return (
@@ -69,7 +43,7 @@ const CategorySection = () => { {isLoading ? ( ) : ( - displayedCategories.map((category, index) => { + courseCategoriesData.map((category, index) => { const categoryColor = stringToColor(category.name); const isHovered = hoveredIndex === index; From e769005b87d27f7eb9a80824a33d0c002c4d3248 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Tue, 25 Feb 2025 20:40:34 +0800 Subject: [PATCH 15/23] add --- apps/server/src/models/term/term.router.ts | 2 +- apps/server/src/models/term/term.service.ts | 4 +- .../courses/components/CoursesContainer.tsx | 52 ++++++++++++++++ .../main/courses/components/FilterSection.tsx | 19 +++++- .../main/courses/layout/AllCoursesLayout.tsx | 11 +--- apps/web/src/app/main/courses/page.tsx | 2 +- .../main/home/components/CategorySection.tsx | 21 +------ .../main/home/components/CoursesSection.tsx | 2 +- apps/web/src/app/main/layout/MainProvider.tsx | 9 ++- .../models/course/list}/CourseList.tsx | 6 +- .../models/course/list/course-list.tsx | 61 ------------------- packages/common/src/constants.ts | 8 +-- 12 files changed, 94 insertions(+), 103 deletions(-) create mode 100644 apps/web/src/app/main/courses/components/CoursesContainer.tsx rename apps/web/src/{app/main/courses/components => components/models/course/list}/CourseList.tsx (93%) delete mode 100755 apps/web/src/components/models/course/list/course-list.tsx diff --git a/apps/server/src/models/term/term.router.ts b/apps/server/src/models/term/term.router.ts index 548526c..1b15a3d 100755 --- a/apps/server/src/models/term/term.router.ts +++ b/apps/server/src/models/term/term.router.ts @@ -61,7 +61,7 @@ export class TermRouter { .input(TermMethodSchema.getSimpleTree) .query(async ({ input, ctx }) => { const { staff } = ctx; - return await this.termService.getChildSimpleTree(staff, input); + return await this.termService.getChildSimpleTree(input, staff); }), getParentSimpleTree: this.trpc.procedure .input(TermMethodSchema.getSimpleTree) diff --git a/apps/server/src/models/term/term.service.ts b/apps/server/src/models/term/term.service.ts index 7f21041..676d45e 100755 --- a/apps/server/src/models/term/term.service.ts +++ b/apps/server/src/models/term/term.service.ts @@ -269,10 +269,10 @@ export class TermService extends BaseTreeService { } async getChildSimpleTree( - staff: UserProfile, data: z.infer, + staff?: UserProfile, ) { - const { domainId = null, permissions } = staff; + const domainId = staff?.domainId || null; const hasAnyPerms = staff?.permissions?.includes(RolePerms.MANAGE_ANY_TERM) || staff?.permissions?.includes(RolePerms.READ_ANY_TERM); diff --git a/apps/web/src/app/main/courses/components/CoursesContainer.tsx b/apps/web/src/app/main/courses/components/CoursesContainer.tsx new file mode 100644 index 0000000..9e2d871 --- /dev/null +++ b/apps/web/src/app/main/courses/components/CoursesContainer.tsx @@ -0,0 +1,52 @@ +import CourseList from "@web/src/components/models/course/list/CourseList"; +import { useMainContext } from "../../layout/MainProvider"; +import { PostType, Prisma } from "@nice/common"; +import { useMemo } from "react"; + +export function CoursesContainer() { + const { searchValue, selectedTerms } = useMainContext(); + const termFilters = useMemo(() => { + return Object.entries(selectedTerms) + .filter(([, terms]) => terms.length > 0) + .map(([, terms]) => terms); + }, [selectedTerms]); + const searchCondition: Prisma.StringNullableFilter = { + contains: searchValue, + mode: "insensitive" as Prisma.QueryMode, // 使用类型断言 + }; + return ( + <> + ({ + terms: { + some: { + id: { + in: termFilter, // 确保至少有一个 term.id 在当前 termFilter 中 + }, + }, + }, + })), + OR: [ + { title: searchCondition }, + { subTitle: searchCondition }, + { content: searchCondition }, + { + terms: { + some: { + name: searchCondition, + }, + }, + }, + ], + }, + }} + cols={4}> + + ); +} + +export default CoursesContainer; diff --git a/apps/web/src/app/main/courses/components/FilterSection.tsx b/apps/web/src/app/main/courses/components/FilterSection.tsx index f7a6ced..e6f17eb 100755 --- a/apps/web/src/app/main/courses/components/FilterSection.tsx +++ b/apps/web/src/app/main/courses/components/FilterSection.tsx @@ -2,14 +2,21 @@ import { Checkbox, Divider, Radio, Space, Spin } from "antd"; import { TaxonomySlug, TermDto } from "@nice/common"; -import { useEffect, useMemo } from "react"; +import { useEffect, useMemo, useState } from "react"; import { api } from "@nice/client"; import { useSearchParams } from "react-router-dom"; import TermSelect from "@web/src/components/models/term/term-select"; +import { useMainContext } from "../../layout/MainProvider"; export default function FilterSection() { const { data: taxonomies } = api.taxonomy.getAll.useQuery({}); - + const { setSelectedTerms } = useMainContext(); + const handleTermChange = (slug, selected) => { + setSelectedTerms((prev) => ({ + ...prev, + [slug]: selected, // 更新对应 slug 的选择 + })); + }; return (
{taxonomies?.map((tax, index) => { @@ -18,7 +25,13 @@ export default function FilterSection() {

{tax?.name}

- + + handleTermChange(tax?.slug, selected) + }> {index < taxonomies.length - 1 && ( )} diff --git a/apps/web/src/app/main/courses/layout/AllCoursesLayout.tsx b/apps/web/src/app/main/courses/layout/AllCoursesLayout.tsx index b3089f1..1acc666 100644 --- a/apps/web/src/app/main/courses/layout/AllCoursesLayout.tsx +++ b/apps/web/src/app/main/courses/layout/AllCoursesLayout.tsx @@ -1,9 +1,9 @@ import { useMainContext } from "../../layout/MainProvider"; -import CourseList from "../components/CourseList"; +import CourseList from "../../../../components/models/course/list/CourseList"; import FilterSection from "../components/FilterSection"; +import CoursesContainer from "../components/CoursesContainer"; export function AllCoursesLayout() { - const { searchValue, setSearchValue } = useMainContext(); return ( <>
@@ -12,12 +12,7 @@ export function AllCoursesLayout() {
- +
diff --git a/apps/web/src/app/main/courses/page.tsx b/apps/web/src/app/main/courses/page.tsx index 0b0fb43..b389a4c 100755 --- a/apps/web/src/app/main/courses/page.tsx +++ b/apps/web/src/app/main/courses/page.tsx @@ -1,6 +1,6 @@ import { useState, useMemo, useEffect } from "react"; import FilterSection from "./components/FilterSection"; -import CourseList from "./components/CourseList"; +import CourseList from "../../../components/models/course/list/CourseList"; import { api } from "@nice/client"; import { courseDetailSelect, diff --git a/apps/web/src/app/main/home/components/CategorySection.tsx b/apps/web/src/app/main/home/components/CategorySection.tsx index ddfeab4..0866eb1 100755 --- a/apps/web/src/app/main/home/components/CategorySection.tsx +++ b/apps/web/src/app/main/home/components/CategorySection.tsx @@ -50,13 +50,7 @@ const CategorySection = () => { } } }, [courseCategoriesData, showAll]); - // const courseCategories: CourseCategory[] = useMemo(() => { - // return data?.map((term) => ({ - // name: term.name, - // count: term.hasChildren ? term.children.length : 0, - // description: term.description - // })) || []; - // },[data]) + const handleMouseEnter = useCallback((index: number) => { setHoveredIndex(index); }, []); @@ -102,6 +96,7 @@ const CategorySection = () => { navigate( `/courses?category=${category.name}` ); + window.scrollTo({ top: 0, behavior: "smooth", @@ -135,17 +130,7 @@ const CategorySection = () => { className="text-xl font-medium tracking-wide"> {category.name} - {/* - {category.children.length} 门课程 - */} +
>; + setSelectedTerms?: React.Dispatch>; } const MainContext = createContext(null); @@ -12,11 +16,14 @@ interface MainProviderProps { export function MainProvider({ children }: MainProviderProps) { const [searchValue, setSearchValue] = useState(""); + const [selectedTerms, setSelectedTerms] = useState({}); // 初始化状态 return ( {children} diff --git a/apps/web/src/app/main/courses/components/CourseList.tsx b/apps/web/src/components/models/course/list/CourseList.tsx similarity index 93% rename from apps/web/src/app/main/courses/components/CourseList.tsx rename to apps/web/src/components/models/course/list/CourseList.tsx index 97001f0..b637b17 100755 --- a/apps/web/src/app/main/courses/components/CourseList.tsx +++ b/apps/web/src/components/models/course/list/CourseList.tsx @@ -1,5 +1,5 @@ import { Pagination, Empty, Skeleton } from "antd"; -import CourseCard from "./CourseCard"; +import CourseCard from "../../../../app/main/courses/components/CourseCard"; import { courseDetailSelect, CourseDto, Prisma } from "@nice/common"; import { api } from "@nice/client"; import { DefaultArgs } from "@prisma/client/runtime/library"; @@ -49,7 +49,7 @@ export default function CourseList({ useEffect(() => { setCurrentPage(params?.page || 1); - }, [params?.page]); + }, [params?.page, params]); function onPageChange(page: number, pageSize: number) { setCurrentPage(page); window.scrollTo({ top: 0, behavior: "smooth" }); @@ -71,7 +71,7 @@ export default function CourseList({
React.ReactNode; - emptyComponent?: React.ReactNode; - // 新增分页相关属性 - currentPage: number; - totalPages: number; - onPageChange: (page: number) => void; -} - -const container = { - hidden: { opacity: 0 }, - show: { - opacity: 1, - transition: { - staggerChildren: 0.05, - duration: 0.3, - }, - }, -}; -export const CourseList = ({ - courses, - renderItem, - emptyComponent: EmptyComponent, - currentPage, - totalPages, - onPageChange, -}: CourseListProps) => { - if (!courses || courses.length === 0) { - return EmptyComponent || ; - } - - return ( -
- - {courses.map((course) => ( - - {renderItem(course)} - - ))} - - - -
- ); -}; diff --git a/packages/common/src/constants.ts b/packages/common/src/constants.ts index 9a36b03..34aca4f 100755 --- a/packages/common/src/constants.ts +++ b/packages/common/src/constants.ts @@ -69,10 +69,10 @@ export const InitTaxonomies: { // name: "研判单元", // slug: TaxonomySlug.UNIT, // }, - { - name: "标签", - slug: TaxonomySlug.TAG, - }, + // { + // name: "标签", + // slug: TaxonomySlug.TAG, + // }, ]; export const InitAppConfigs: Prisma.AppConfigCreateInput[] = [ { From 11e8ce708a152c331a602ea2fe29ebe2d637ad8e Mon Sep 17 00:00:00 2001 From: ditiqi Date: Tue, 25 Feb 2025 21:48:41 +0800 Subject: [PATCH 16/23] addd --- .../main/courses/components/FilterSection.tsx | 24 ++++++++++++----- .../main/courses/layout/AllCoursesLayout.tsx | 3 --- apps/web/src/app/main/courses/page.tsx | 18 ------------- apps/web/src/app/main/layout/MainProvider.tsx | 1 + .../components/models/term/term-select.tsx | 27 +++++++++++++++++-- 5 files changed, 44 insertions(+), 29 deletions(-) diff --git a/apps/web/src/app/main/courses/components/FilterSection.tsx b/apps/web/src/app/main/courses/components/FilterSection.tsx index e6f17eb..203e1d1 100755 --- a/apps/web/src/app/main/courses/components/FilterSection.tsx +++ b/apps/web/src/app/main/courses/components/FilterSection.tsx @@ -10,27 +10,39 @@ import { useMainContext } from "../../layout/MainProvider"; export default function FilterSection() { const { data: taxonomies } = api.taxonomy.getAll.useQuery({}); - const { setSelectedTerms } = useMainContext(); - const handleTermChange = (slug, selected) => { - setSelectedTerms((prev) => ({ - ...prev, + const { selectedTerms, setSelectedTerms } = useMainContext(); + const handleTermChange = (slug: string, selected: string[]) => { + setSelectedTerms({ + ...selectedTerms, [slug]: selected, // 更新对应 slug 的选择 - })); + }); }; return (
{taxonomies?.map((tax, index) => { + const items = Object.entries(selectedTerms).find( + ([key, items]) => key === tax.slug + )?.[1]; return (

{tax?.name}

( +
{menu}
+ )} + dropdownStyle={{ maxHeight: 400, overflow: "auto" }} multiple taxonomyId={tax?.id} onChange={(selected) => - handleTermChange(tax?.slug, selected) + handleTermChange( + tax?.slug, + selected as string[] + ) }>
{index < taxonomies.length - 1 && ( diff --git a/apps/web/src/app/main/courses/layout/AllCoursesLayout.tsx b/apps/web/src/app/main/courses/layout/AllCoursesLayout.tsx index 1acc666..5062731 100644 --- a/apps/web/src/app/main/courses/layout/AllCoursesLayout.tsx +++ b/apps/web/src/app/main/courses/layout/AllCoursesLayout.tsx @@ -1,8 +1,5 @@ -import { useMainContext } from "../../layout/MainProvider"; -import CourseList from "../../../../components/models/course/list/CourseList"; import FilterSection from "../components/FilterSection"; import CoursesContainer from "../components/CoursesContainer"; - export function AllCoursesLayout() { return ( <> diff --git a/apps/web/src/app/main/courses/page.tsx b/apps/web/src/app/main/courses/page.tsx index b389a4c..9c9225e 100755 --- a/apps/web/src/app/main/courses/page.tsx +++ b/apps/web/src/app/main/courses/page.tsx @@ -1,22 +1,4 @@ -import { useState, useMemo, useEffect } from "react"; -import FilterSection from "./components/FilterSection"; -import CourseList from "../../../components/models/course/list/CourseList"; -import { api } from "@nice/client"; -import { - courseDetailSelect, - CourseDto, - LectureType, - PostType, -} from "@nice/common"; -import { useSearchParams } from "react-router-dom"; -import { set } from "idb-keyval"; -import { useMainContext } from "../layout/MainProvider"; import AllCoursesLayout from "./layout/AllCoursesLayout"; - -interface paginationData { - items: CourseDto[]; - totalPages: number; -} export default function CoursesPage() { return ( <> diff --git a/apps/web/src/app/main/layout/MainProvider.tsx b/apps/web/src/app/main/layout/MainProvider.tsx index f75f62f..0952268 100644 --- a/apps/web/src/app/main/layout/MainProvider.tsx +++ b/apps/web/src/app/main/layout/MainProvider.tsx @@ -2,6 +2,7 @@ import React, { createContext, ReactNode, useContext, useState } from "react"; interface SelectedTerms { [key: string]: string[]; // 每个 slug 对应一个 string 数组 } + interface MainContextType { searchValue?: string; selectedTerms?: SelectedTerms; diff --git a/apps/web/src/components/models/term/term-select.tsx b/apps/web/src/components/models/term/term-select.tsx index 07b4741..c0fe5a0 100755 --- a/apps/web/src/components/models/term/term-select.tsx +++ b/apps/web/src/components/models/term/term-select.tsx @@ -1,5 +1,12 @@ import { TreeSelect, TreeSelectProps } from "antd"; -import React, { useEffect, useState, useCallback, useRef } from "react"; +import React, { + useEffect, + useState, + useCallback, + useRef, + ReactElement, + JSXElementConstructor, +} from "react"; import { getUniqueItems } from "@nice/common"; import { api } from "@nice/client"; import { DefaultOptionType } from "antd/es/select"; @@ -14,6 +21,13 @@ interface TermSelectProps { disabled?: boolean; className?: string; domainId?: string; + dropdownStyle?: React.CSSProperties; + style?: React.CSSProperties; + open?: boolean; + showSearch?: boolean; + dropdownRender?: ( + menu: ReactElement> + ) => ReactElement>; } export default function TermSelect({ @@ -24,8 +38,13 @@ export default function TermSelect({ placeholder = "选择分类", multiple = false, taxonomyId, + open = undefined, + showSearch = true, domainId, + dropdownStyle, + style, disabled = false, + dropdownRender, }: TermSelectProps) { const utils = api.useUtils(); const [listTreeData, setListTreeData] = useState< @@ -150,16 +169,20 @@ export default function TermSelect({ Date: Tue, 25 Feb 2025 22:04:14 +0800 Subject: [PATCH 17/23] add --- apps/server/src/models/app-config/app-config.router.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/server/src/models/app-config/app-config.router.ts b/apps/server/src/models/app-config/app-config.router.ts index 882fa16..350d047 100755 --- a/apps/server/src/models/app-config/app-config.router.ts +++ b/apps/server/src/models/app-config/app-config.router.ts @@ -36,7 +36,7 @@ export class AppConfigRouter { .mutation(async ({ input }) => { return await this.appConfigService.deleteMany(input); }), - findFirst: this.trpc.protectProcedure + findFirst: this.trpc.procedure .input(AppConfigFindFirstArgsSchema) .query(async ({ input }) => { return await this.appConfigService.findFirst(input); From 6b699a40926ad20f498186f4cf554b0b4563e375 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Tue, 25 Feb 2025 22:04:17 +0800 Subject: [PATCH 18/23] add --- .../src/app/main/layout/NavigationMenu.tsx | 58 ++++++++++--------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/apps/web/src/app/main/layout/NavigationMenu.tsx b/apps/web/src/app/main/layout/NavigationMenu.tsx index b1a4fb6..53efdb3 100755 --- a/apps/web/src/app/main/layout/NavigationMenu.tsx +++ b/apps/web/src/app/main/layout/NavigationMenu.tsx @@ -1,31 +1,37 @@ -import { Menu } from 'antd'; -import { useNavigate, useLocation } from 'react-router-dom'; +import { Menu } from "antd"; +import { useNavigate, useLocation } from "react-router-dom"; const menuItems = [ - { key: 'home', path: '/', label: '首页' }, - { key: 'courses', path: '/courses', label: '全部课程' }, - { key: 'paths', path: '/paths', label: '学习路径' } + { key: "home", path: "/", label: "首页" }, + { key: "courses", path: "/courses", label: "全部课程" }, + { key: "paths", path: "/paths", label: "学习路径" }, ]; export const NavigationMenu = () => { - const navigate = useNavigate(); - const { pathname } = useLocation(); - const selectedKey = menuItems.find(item => item.path === pathname)?.key || ''; - return ( - { - const selectedItem = menuItems.find(item => item.key === key); - if (selectedItem) navigate(selectedItem.path); - }} - > - {menuItems.map(({ key, label }) => ( - - {label} - - ))} - - ); -}; \ No newline at end of file + const navigate = useNavigate(); + const { pathname } = useLocation(); + const selectedKey = + menuItems.find((item) => item.path === pathname)?.key || ""; + return ( + { + const selectedItem = menuItems.find((item) => item.key === key); + if (selectedItem) navigate(selectedItem.path); + window.scrollTo({ + top: 0, + behavior: "smooth", + }); + }}> + {menuItems.map(({ key, label }) => ( + + {label} + + ))} + + ); +}; From 34992311192b3413eedaf5b0e7da9dbc6ab046b6 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Tue, 25 Feb 2025 22:04:19 +0800 Subject: [PATCH 19/23] add --- .../components/models/term/term-select.tsx | 50 +++++++++++-------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/apps/web/src/components/models/term/term-select.tsx b/apps/web/src/components/models/term/term-select.tsx index c0fe5a0..8f76f07 100755 --- a/apps/web/src/components/models/term/term-select.tsx +++ b/apps/web/src/components/models/term/term-select.tsx @@ -72,7 +72,7 @@ export default function TermSelect({ throw error; } }, - [utils] + [utils, value] ); const fetchTerms = useCallback(async () => { @@ -139,25 +139,35 @@ export default function TermSelect({ } }; - const handleExpand = async (keys: React.Key[]) => { - try { - const allKeyIds = - keys.map((key) => key.toString()).filter(Boolean) || []; - const expandedNodes = await utils.term.getChildSimpleTree.fetch({ - termIds: allKeyIds, - taxonomyId, - domainId, - }); - const flattenedNodes = expandedNodes.flat(); - const newItems = getUniqueItems( - [...listTreeData, ...flattenedNodes], - "id" - ); - setListTreeData(newItems); - } catch (error) { - console.error("Error expanding nodes with keys", keys, ":", error); - } - }; + const handleExpand = useCallback( + async (keys: React.Key[]) => { + try { + const allKeyIds = + keys.map((key) => key.toString()).filter(Boolean) || []; + const expandedNodes = await utils.term.getChildSimpleTree.fetch( + { + termIds: allKeyIds, + taxonomyId, + domainId, + } + ); + const flattenedNodes = expandedNodes.flat(); + const newItems = getUniqueItems( + [...listTreeData, ...flattenedNodes], + "id" + ); + setListTreeData(newItems); + } catch (error) { + console.error( + "Error expanding nodes with keys", + keys, + ":", + error + ); + } + }, + [value] + ); const handleDropdownVisibleChange = async (open: boolean) => { if (open) { // This will attempt to expand all nodes and fetch their children when the dropdown opens From 36b479bc202a8e06eddc15bffa6a1d085f942231 Mon Sep 17 00:00:00 2001 From: Rao <1227431568@qq.com> Date: Tue, 25 Feb 2025 22:19:38 +0800 Subject: [PATCH 20/23] rht02252219 --- .../app/main/home/components/CategorySection.tsx | 15 +++++++++++++++ .../main/home/components/CategorySectionCard.tsx | 16 +++++----------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/apps/web/src/app/main/home/components/CategorySection.tsx b/apps/web/src/app/main/home/components/CategorySection.tsx index bcbaa28..f3ed9ec 100755 --- a/apps/web/src/app/main/home/components/CategorySection.tsx +++ b/apps/web/src/app/main/home/components/CategorySection.tsx @@ -4,10 +4,13 @@ import { stringToColor, TaxonomySlug, TermDto } from "@nice/common"; import { api } from "@nice/client"; import LookForMore from "./LookForMore"; import CategorySectionCard from "./CategorySectionCard"; +import { useNavigate } from "react-router-dom"; +import { useMainContext } from "../../layout/MainProvider"; const { Title, Text } = Typography; const CategorySection = () => { const [hoveredIndex, setHoveredIndex] = useState(null); + const { selectedTerms, setSelectedTerms } = useMainContext(); const { data: courseCategoriesData, isLoading, @@ -16,9 +19,12 @@ const CategorySection = () => { taxonomy: { slug: TaxonomySlug.CATEGORY, }, + parentId : null }, take: 8, }); + const navigate = useNavigate() + const handleMouseEnter = useCallback((index: number) => { setHoveredIndex(index); }, []); @@ -26,6 +32,14 @@ const CategorySection = () => { const handleMouseLeave = useCallback(() => { setHoveredIndex(null); }, []); + + const handleMouseClick = useCallback((categoryId:string) => { + setSelectedTerms({ + [TaxonomySlug.CATEGORY] : [categoryId] + }) + navigate('/courses') + window.scrollTo({top: 0,behavior: "smooth",}) + },[]); return (
@@ -56,6 +70,7 @@ const CategorySection = () => { isHovered={isHovered} handleMouseEnter={handleMouseEnter} handleMouseLeave={handleMouseLeave} + handleMouseClick={handleMouseClick} /> ); }) diff --git a/apps/web/src/app/main/home/components/CategorySectionCard.tsx b/apps/web/src/app/main/home/components/CategorySectionCard.tsx index a91525c..e3e1273 100644 --- a/apps/web/src/app/main/home/components/CategorySectionCard.tsx +++ b/apps/web/src/app/main/home/components/CategorySectionCard.tsx @@ -1,6 +1,6 @@ import { useNavigate } from "react-router-dom"; import { Typography } from "antd"; -export default function CategorySectionCard({index,handleMouseEnter,handleMouseLeave,category,categoryColor,isHovered,}) { +export default function CategorySectionCard({handleMouseClick, index,handleMouseEnter,handleMouseLeave,category,categoryColor,isHovered,}) { const navigate = useNavigate() const { Title, Text } = Typography; return ( @@ -12,16 +12,10 @@ export default function CategorySectionCard({index,handleMouseEnter,handleMouseL role="button" tabIndex={0} aria-label={`查看${category.name}课程类别`} - onClick={() => { - console.log(category.name); - navigate( - `/courses?category=${category.name}` - ); - window.scrollTo({ - top: 0, - behavior: "smooth", - }); - }}> + onClick={()=>{ + handleMouseClick(category.id) + }} + >
Date: Tue, 25 Feb 2025 22:25:40 +0800 Subject: [PATCH 21/23] add --- apps/server/src/models/term/term.service.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/server/src/models/term/term.service.ts b/apps/server/src/models/term/term.service.ts index 676d45e..7cbcc5f 100755 --- a/apps/server/src/models/term/term.service.ts +++ b/apps/server/src/models/term/term.service.ts @@ -352,7 +352,9 @@ export class TermService extends BaseTreeService { staff: UserProfile, data: z.infer, ) { - const { domainId = null, permissions } = staff; + // const { domainId = null, permissions } = staff; + const permissions = staff?.permissions || []; + const domainId = staff?.domainId || null; const hasAnyPerms = permissions.includes(RolePerms.READ_ANY_TERM) || permissions.includes(RolePerms.MANAGE_ANY_TERM); From 76ef17163c9733cd6163ad8f828455b68dad11c2 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Tue, 25 Feb 2025 22:31:42 +0800 Subject: [PATCH 22/23] add --- apps/web/src/components/models/term/term-select.tsx | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/apps/web/src/components/models/term/term-select.tsx b/apps/web/src/components/models/term/term-select.tsx index 8f76f07..3896d8e 100755 --- a/apps/web/src/components/models/term/term-select.tsx +++ b/apps/web/src/components/models/term/term-select.tsx @@ -15,11 +15,9 @@ interface TermSelectProps { defaultValue?: string | string[]; value?: string | string[]; onChange?: (value: string | string[]) => void; - placeholder?: string; multiple?: boolean; taxonomyId?: string; disabled?: boolean; - className?: string; domainId?: string; dropdownStyle?: React.CSSProperties; style?: React.CSSProperties; @@ -34,7 +32,6 @@ export default function TermSelect({ defaultValue, value, onChange, - className, placeholder = "选择分类", multiple = false, taxonomyId, @@ -45,7 +42,8 @@ export default function TermSelect({ style, disabled = false, dropdownRender, -}: TermSelectProps) { + ...treeSelectProps +}: TermSelectProps & TreeSelectProps) { const utils = api.useUtils(); const [listTreeData, setListTreeData] = useState< Omit[] @@ -179,9 +177,6 @@ export default function TermSelect({ handleChange(multiple ? [] : undefined)} onTreeExpand={handleExpand} onDropdownVisibleChange={handleDropdownVisibleChange} + {...treeSelectProps} /> ); } From 1ed74e659011b2371d226ba8da291388315de7e0 Mon Sep 17 00:00:00 2001 From: Li1304553726 <1304553726@qq.com> Date: Tue, 25 Feb 2025 22:46:17 +0800 Subject: [PATCH 23/23] li . --- .../app/main/courses/components/CourseCard.tsx | 13 ++++++++----- .../src/app/main/layout/UserMenu/UserMenu.tsx | 16 +++++++--------- .../layout/element/usermenu/usermenu.tsx | 14 ++++++-------- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/apps/web/src/app/main/courses/components/CourseCard.tsx b/apps/web/src/app/main/courses/components/CourseCard.tsx index 45dc274..963c691 100755 --- a/apps/web/src/app/main/courses/components/CourseCard.tsx +++ b/apps/web/src/app/main/courses/components/CourseCard.tsx @@ -46,10 +46,10 @@ export default function CourseCard({ course }: CourseCardProps) { // color={term.taxonomy.slug===TaxonomySlug.CATEGORY? "blue" : "green"} color={ term?.taxonomy?.slug === - TaxonomySlug.CATEGORY + TaxonomySlug.CATEGORY ? "blue" : term?.taxonomy?.slug === - TaxonomySlug.LEVEL + TaxonomySlug.LEVEL ? "green" : "orange" } @@ -87,12 +87,15 @@ export default function CourseCard({ course }: CourseCardProps) {
- {course?.depts?.map((depts) => depts.name)} - {/* {course?.depts?.[0]?.name} */} + { + course?.depts.length > 1 ?`${course.depts[0].name}等`:course.depts[0].name + } + {/* {course?.depts?.map((dept) => {return dept.name.length > 1 ?`${dept.name.slice}等`: dept.name})} */} + {/* {course?.depts?.map((dept)=>{return dept.name})} */}
- 观看次数{course?.meta?.views}次 + {course?.meta?.views ? `观看次数 ${course?.meta?.views}` : null}
diff --git a/apps/web/src/app/main/layout/UserMenu/UserMenu.tsx b/apps/web/src/app/main/layout/UserMenu/UserMenu.tsx index 508fdaa..ea23902 100755 --- a/apps/web/src/app/main/layout/UserMenu/UserMenu.tsx +++ b/apps/web/src/app/main/layout/UserMenu/UserMenu.tsx @@ -221,21 +221,19 @@ export function UserMenu() { focus:outline-none focus:ring-2 focus:ring-[#00538E]/20 group relative overflow-hidden - active:scale-[0.99] - ${ - item.label === "注销" + active:scale-[0.99] + ${item.label === "注销" ? "text-[#B22234] hover:bg-red-50/80 hover:text-red-700" : "text-[#00538E] hover:bg-[#E6EEF5] hover:text-[#003F6A]" - }`}> + }`}> + group-hover:translate-x-0.5 ${item.label === "注销" + ? "group-hover:text-red-600" + : "group-hover:text-[#003F6A]" + }`}> {item.icon} {item.label} diff --git a/apps/web/src/components/layout/element/usermenu/usermenu.tsx b/apps/web/src/components/layout/element/usermenu/usermenu.tsx index d2611dd..31460cd 100755 --- a/apps/web/src/components/layout/element/usermenu/usermenu.tsx +++ b/apps/web/src/components/layout/element/usermenu/usermenu.tsx @@ -229,20 +229,18 @@ export function UserMenu() { focus:ring-2 focus:ring-[#00538E]/20 group relative overflow-hidden active:scale-[0.99] - ${ - item.label === "注销" + ${item.label === "注销" ? "text-[#B22234] hover:bg-red-50/80 hover:text-red-700" : "text-[#00538E] hover:bg-[#E6EEF5] hover:text-[#003F6A]" - }`}> + }`}> + group-hover:translate-x-0.5 ${item.label === "注销" + ? "group-hover:text-red-600" + : "group-hover:text-[#003F6A]" + }`}> {item.icon} {item.label}