From 0081ccf3f2de55ef253f35dd4b689e6c826fbc87 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 09:32:55 +0800 Subject: [PATCH 01/30] add --- apps/server/src/queue/models/post/utils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/server/src/queue/models/post/utils.ts b/apps/server/src/queue/models/post/utils.ts index 8546c66..1a352ff 100644 --- a/apps/server/src/queue/models/post/utils.ts +++ b/apps/server/src/queue/models/post/utils.ts @@ -20,6 +20,7 @@ export async function updatePostViewCount(id: string, type: VisitType) { }, // Use 0 if no visits exist }, }); + console.log('readed'); } else if (type === VisitType.LIKE) { await db.post.update({ where: { From ab1bce816bf0e02a50c86454726798efc94484ab Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 09:32:59 +0800 Subject: [PATCH 02/30] ddadad --- apps/server/src/queue/worker/processor.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/server/src/queue/worker/processor.ts b/apps/server/src/queue/worker/processor.ts index 7273ecf..a968179 100755 --- a/apps/server/src/queue/worker/processor.ts +++ b/apps/server/src/queue/worker/processor.ts @@ -11,6 +11,7 @@ import { updateCourseReviewStats, updateParentLectureStats, } from '@server/models/post/utils'; +import { updatePostViewCount } from '../models/post/utils'; const logger = new Logger('QueueWorker'); export default async function processJob(job: Job) { try { @@ -44,6 +45,12 @@ export default async function processJob(job: Job) { `Updated course stats for courseId: ${courseId}, type: ${type}`, ); } + if (job.name === QueueJobType.UPDATE_POST_VISIT_COUNT) { + await updatePostViewCount(job.data.id, job.data.type); + } + if (job.name === QueueJobType.UPDATE_POST_STATE) { + await updatePostViewCount(job.data.id, job.data.type); + } } catch (error: any) { logger.error( `Error processing stats update job: ${error.message}`, From 3e7a6dbc6b2f8b5053aba516fb5d933d931b24d6 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 09:33:01 +0800 Subject: [PATCH 03/30] asdsa --- apps/web/src/components/layout/element/usermenu/usermenu.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/src/components/layout/element/usermenu/usermenu.tsx b/apps/web/src/components/layout/element/usermenu/usermenu.tsx index e00965b..d2611dd 100755 --- a/apps/web/src/components/layout/element/usermenu/usermenu.tsx +++ b/apps/web/src/components/layout/element/usermenu/usermenu.tsx @@ -185,13 +185,13 @@ export function UserMenu() { id="user-menu" aria-orientation="vertical" aria-labelledby="user-menu-button" - style={{ zIndex: 100 }} + style={{ zIndex: 1000 }} className="absolute right-0 mt-3 w-64 origin-top-right bg-white rounded-xl overflow-hidden shadow-lg border border-[#E5EDF5]"> {/* User Profile Section */}
Date: Mon, 24 Feb 2025 09:33:03 +0800 Subject: [PATCH 04/30] asdsa --- .../course/detail/CourseDetailDescription.tsx | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/apps/web/src/components/models/course/detail/CourseDetailDescription.tsx b/apps/web/src/components/models/course/detail/CourseDetailDescription.tsx index 75a5104..3b75ae9 100755 --- a/apps/web/src/components/models/course/detail/CourseDetailDescription.tsx +++ b/apps/web/src/components/models/course/detail/CourseDetailDescription.tsx @@ -2,6 +2,8 @@ import { Course } from "@nice/common"; import React, { useContext } from "react"; import { Typography, Skeleton } from "antd"; // 引入 antd 组件 import { CourseDetailContext } from "./CourseDetailContext"; +import { CalendarOutlined, EyeOutlined } from "@ant-design/icons"; +import dayjs from "dayjs"; interface CourseDetailProps { course: Course; @@ -18,8 +20,20 @@ export const CourseDetailDescription: React.FC = () => { ) : (
-
{"课程简介"}
+
{"课程简介:"}
+
+
{course?.subTitle}
+
+ +
{course?.meta?.views}
+
+
+ + {dayjs(course?.createdAt).format("YYYY年M月D日")} +
+
= () => { onExpand: () => console.log("展开"), // collapseText: "收起", }}> - {course.content} + {course?.content}
)} From 40d5d28cb69ca09681864ccc60dedaa3d740abe3 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 09:33:04 +0800 Subject: [PATCH 05/30] asdasd --- .../course/detail/CourseDetailDisplayArea.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/web/src/components/models/course/detail/CourseDetailDisplayArea.tsx b/apps/web/src/components/models/course/detail/CourseDetailDisplayArea.tsx index f6f4913..1a6a7b8 100755 --- a/apps/web/src/components/models/course/detail/CourseDetailDisplayArea.tsx +++ b/apps/web/src/components/models/course/detail/CourseDetailDisplayArea.tsx @@ -17,7 +17,7 @@ import { Skeleton } from "antd"; export const CourseDetailDisplayArea: React.FC = () => { // 创建滚动动画效果 - const { course, isLoading, lecture, lectureIsLoading } = + const { course, isLoading, lecture, lectureIsLoading, selectedLectureId } = useContext(CourseDetailContext); const { scrollY } = useScroll(); const videoOpacity = useTransform(scrollY, [0, 200], [1, 0.8]); @@ -27,6 +27,15 @@ export const CourseDetailDisplayArea: React.FC = () => { {lectureIsLoading && ( )} + {!selectedLectureId && ( + <> +
+
+ {"123"} +
+
+ + )} {!lectureIsLoading && lecture?.meta?.type === LectureType.VIDEO && (
{
-
{" "} +
)} {!lectureIsLoading && From d5070fa6479540b4437928ed09f2c7f27f84c208 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 09:33:06 +0800 Subject: [PATCH 06/30] asdsda --- .../course/detail/CourseDetailHeader/CourseDetailHeader.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/src/components/models/course/detail/CourseDetailHeader/CourseDetailHeader.tsx b/apps/web/src/components/models/course/detail/CourseDetailHeader/CourseDetailHeader.tsx index 88657a2..71ec0e0 100755 --- a/apps/web/src/components/models/course/detail/CourseDetailHeader/CourseDetailHeader.tsx +++ b/apps/web/src/components/models/course/detail/CourseDetailHeader/CourseDetailHeader.tsx @@ -8,7 +8,7 @@ import { } from "@ant-design/icons"; import { useAuth } from "@web/src/providers/auth-provider"; import { useNavigate } from "react-router-dom"; -import { UserMenu } from "@web/src/components/layout/element/usermenu/usermenu"; +import { UserMenu } from "@web/src/app/main/layout/UserMenu"; import { CourseDetailContext } from "../CourseDetailContext"; const { Header } = Layout; @@ -18,7 +18,7 @@ export function CourseDetailHeader() { const { isAuthenticated, user } = useAuth(); const navigate = useNavigate(); const { course } = useContext(CourseDetailContext); - + return (
From f8f508676a103b6061d25c230dc15518b39baefe Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 09:33:09 +0800 Subject: [PATCH 07/30] asddsa --- .../detail/CourseSyllabus/CourseSyllabus.tsx | 99 ++++++++----------- 1 file changed, 40 insertions(+), 59 deletions(-) diff --git a/apps/web/src/components/models/course/detail/CourseSyllabus/CourseSyllabus.tsx b/apps/web/src/components/models/course/detail/CourseSyllabus/CourseSyllabus.tsx index 3b04395..36eb086 100755 --- a/apps/web/src/components/models/course/detail/CourseSyllabus/CourseSyllabus.tsx +++ b/apps/web/src/components/models/course/detail/CourseSyllabus/CourseSyllabus.tsx @@ -6,7 +6,6 @@ import { } from "@heroicons/react/24/outline"; import { ChevronLeftIcon, ChevronRightIcon } from "@heroicons/react/24/outline"; import React, { useState, useRef, useContext } from "react"; -import { motion, AnimatePresence } from "framer-motion"; import { SectionDto, TaxonomySlug } from "@nice/common"; import { SyllabusHeader } from "./SyllabusHeader"; import { SectionItem } from "./SectionItem"; @@ -30,11 +29,7 @@ export const CourseSyllabus: React.FC = ({ const { isHeaderVisible } = useContext(CourseDetailContext); const [expandedSections, setExpandedSections] = useState([]); const sectionRefs = useRef<{ [key: string]: HTMLDivElement | null }>({}); - // api.term.findMany.useQuery({ - // where: { - // taxonomy: { slug: TaxonomySlug.CATEGORY }, - // }, - // }); + const toggleSection = (sectionId: string) => { setExpandedSections((prev) => prev.includes(sectionId) @@ -42,70 +37,56 @@ export const CourseSyllabus: React.FC = ({ : [...prev, sectionId] ); - setTimeout(() => { - sectionRefs.current[sectionId]?.scrollIntoView({ - behavior: "smooth", - block: "start", - }); - }, 100); + // 直接滚动,无需延迟 + sectionRefs.current[sectionId]?.scrollIntoView({ + behavior: "smooth", + block: "start", + }); }; return ( <> - - {/* 收起时的悬浮按钮 */} - {!isOpen && ( - - - - )} - - + +
+ )} + +
- - {isOpen && ( - - + {isOpen && ( +
+ -
-
- {sections.map((section, index) => ( - - (sectionRefs.current[ - section.id - ] = el) - } - index={index + 1} - section={section} - isExpanded={expandedSections.includes( - section.id - )} - onToggle={toggleSection} - onLectureClick={onLectureClick} - /> - ))} -
+
+
+ {sections.map((section, index) => ( + + (sectionRefs.current[section.id] = + el) + } + index={index + 1} + section={section} + isExpanded={expandedSections.includes( + section.id + )} + onToggle={toggleSection} + onLectureClick={onLectureClick} + /> + ))}
- - )} - - +
+
+ )} +
); }; From a4d56179ca7b5dc225c8c6f9451b6e09ee835102 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 09:33:11 +0800 Subject: [PATCH 08/30] asdsa --- .../course/detail/CourseSyllabus/SectionItem.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/web/src/components/models/course/detail/CourseSyllabus/SectionItem.tsx b/apps/web/src/components/models/course/detail/CourseSyllabus/SectionItem.tsx index d2a4fe6..6cd1627 100755 --- a/apps/web/src/components/models/course/detail/CourseSyllabus/SectionItem.tsx +++ b/apps/web/src/components/models/course/detail/CourseSyllabus/SectionItem.tsx @@ -16,11 +16,11 @@ interface SectionItemProps { export const SectionItem = React.forwardRef( ({ section, index, isExpanded, onToggle, onLectureClick }, ref) => ( -
) ); From f25b9843ae51965b39236eebec96af8999d1fd10 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 09:33:13 +0800 Subject: [PATCH 09/30] asddas --- packages/common/src/models/post.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/common/src/models/post.ts b/packages/common/src/models/post.ts index 0961cab..fa030b6 100755 --- a/packages/common/src/models/post.ts +++ b/packages/common/src/models/post.ts @@ -67,6 +67,9 @@ export type CourseMeta = { thumbnail?: string; objectives?: string[]; + views?: number; + likes?: number; + hates?: number; }; export type Course = Post & { meta?: CourseMeta; From eaec8b1829b401e0a91763e974561704e1577b92 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 09:41:45 +0800 Subject: [PATCH 10/30] add --- .../components/coursePreviewAllmsg.tsx | 122 +++++++++++------- 1 file changed, 72 insertions(+), 50 deletions(-) diff --git a/apps/web/src/app/main/course/preview/components/coursePreviewAllmsg.tsx b/apps/web/src/app/main/course/preview/components/coursePreviewAllmsg.tsx index f56466d..73ed1f9 100644 --- a/apps/web/src/app/main/course/preview/components/coursePreviewAllmsg.tsx +++ b/apps/web/src/app/main/course/preview/components/coursePreviewAllmsg.tsx @@ -1,51 +1,73 @@ -import { useEffect } from 'react'; -import { CoursePreviewMsg } from '@web/src/app/main/course/preview/type.ts'; -import { Button , Tabs , Image, Skeleton } from 'antd'; -import type { TabsProps } from 'antd'; +import { useEffect } from "react"; +import { CoursePreviewMsg } from "@web/src/app/main/course/preview/type.ts"; +import { Button, Tabs, Image, Skeleton } from "antd"; +import type { TabsProps } from "antd"; import { PlayCircleOutlined } from "@ant-design/icons"; -export function CoursePreviewAllmsg({previewMsg,items,isLoading}: {previewMsg?:CoursePreviewMsg,items:TabsProps['items'],isLoading:Boolean}){ - useEffect(() => { - console.log(previewMsg) - }) - const TapOnChange = (key: string) => { - console.log(key); - }; - return ( -
-
-
- example -
- -
- -
-
- { - isLoading ? - :( - <> - {previewMsg.Title} - {previewMsg.SubTitle} - {previewMsg.Description} - - ) - } - - -
-
-
- -
-
- ) -} \ No newline at end of file +export function CoursePreviewAllmsg({ + previewMsg, + items, + isLoading, +}: { + previewMsg?: CoursePreviewMsg; + items: TabsProps["items"]; + isLoading: boolean; +}) { + useEffect(() => { + console.log(previewMsg); + }); + const TapOnChange = (key: string) => { + console.log(key); + }; + return ( +
+
+
+ example +
+ +
+
+
+ {isLoading ? ( + + ) : ( + <> + + {previewMsg.Title} + + + {previewMsg.SubTitle} + + + {previewMsg.Description} + + + )} + + +
+
+
+ +
+
+ ); +} From 44c4d152b7583bf552000e09a465bd3ea292e05c Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 09:41:48 +0800 Subject: [PATCH 11/30] add --- .../course/detail/CourseDetailDisplayArea.tsx | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/apps/web/src/components/models/course/detail/CourseDetailDisplayArea.tsx b/apps/web/src/components/models/course/detail/CourseDetailDisplayArea.tsx index 1a6a7b8..b5aed44 100755 --- a/apps/web/src/components/models/course/detail/CourseDetailDisplayArea.tsx +++ b/apps/web/src/components/models/course/detail/CourseDetailDisplayArea.tsx @@ -27,7 +27,7 @@ export const CourseDetailDisplayArea: React.FC = () => { {lectureIsLoading && ( )} - {!selectedLectureId && ( + {!selectedLectureId && !lectureIsLoading && ( <>
@@ -36,20 +36,23 @@ export const CourseDetailDisplayArea: React.FC = () => {
)} - {!lectureIsLoading && lecture?.meta?.type === LectureType.VIDEO && ( -
- -
- -
-
-
- )} + {selectedLectureId && + !lectureIsLoading && + lecture?.meta?.type === LectureType.VIDEO && ( +
+ +
+ +
+
+
+ )} {!lectureIsLoading && + selectedLectureId && lecture?.meta?.type === LectureType.ARTICLE && (
From 2fdb6341954c8fca177eb706806eecf1cc408112 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 09:41:50 +0800 Subject: [PATCH 12/30] addad --- .../components/models/course/detail/CourseDetailLayout.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/web/src/components/models/course/detail/CourseDetailLayout.tsx b/apps/web/src/components/models/course/detail/CourseDetailLayout.tsx index 02316bb..d2cffe6 100755 --- a/apps/web/src/components/models/course/detail/CourseDetailLayout.tsx +++ b/apps/web/src/components/models/course/detail/CourseDetailLayout.tsx @@ -18,7 +18,7 @@ export default function CourseDetailLayout() { const handleLectureClick = (lectureId: string) => { setSelectedLectureId(lectureId); }; - const [isSyllabusOpen, setIsSyllabusOpen] = useState(false); + const [isSyllabusOpen, setIsSyllabusOpen] = useState(true); return (
@@ -30,6 +30,9 @@ export default function CourseDetailLayout() { {" "} {/* 添加这个包装 div */} Date: Mon, 24 Feb 2025 09:41:54 +0800 Subject: [PATCH 13/30] adda --- .../CoursePreview/couresPreviewTabmsg.tsx | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 apps/web/src/components/models/course/detail/CoursePreview/couresPreviewTabmsg.tsx diff --git a/apps/web/src/components/models/course/detail/CoursePreview/couresPreviewTabmsg.tsx b/apps/web/src/components/models/course/detail/CoursePreview/couresPreviewTabmsg.tsx new file mode 100644 index 0000000..8f32fce --- /dev/null +++ b/apps/web/src/components/models/course/detail/CoursePreview/couresPreviewTabmsg.tsx @@ -0,0 +1,25 @@ +import { Checkbox, List } from 'antd'; +import React from 'react'; + +export function CoursePreviewTabmsg({data}){ + + + const renderItem = (item) => ( + + + + ); + + return( +
+ +
+ ) +} \ No newline at end of file From 7649894f50cdac3af10edff3437ce9fa83b6c484 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 09:41:56 +0800 Subject: [PATCH 14/30] add --- .../course/detail/CoursePreview/courseCatalog.tsx | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 apps/web/src/components/models/course/detail/CoursePreview/courseCatalog.tsx diff --git a/apps/web/src/components/models/course/detail/CoursePreview/courseCatalog.tsx b/apps/web/src/components/models/course/detail/CoursePreview/courseCatalog.tsx new file mode 100644 index 0000000..b13e87d --- /dev/null +++ b/apps/web/src/components/models/course/detail/CoursePreview/courseCatalog.tsx @@ -0,0 +1,11 @@ +import type { MenuProps } from 'antd'; +import { Menu } from 'antd'; + +type MenuItem = Required['items'][number]; + +export function CourseCatalog(){ + return ( + <> + + ) +} \ No newline at end of file From c5bb5179ee2bfc2821f51a51fe4ac6b2289c6956 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 09:41:59 +0800 Subject: [PATCH 15/30] add --- .../CoursePreview/coursePreviewAllmsg.tsx | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 apps/web/src/components/models/course/detail/CoursePreview/coursePreviewAllmsg.tsx diff --git a/apps/web/src/components/models/course/detail/CoursePreview/coursePreviewAllmsg.tsx b/apps/web/src/components/models/course/detail/CoursePreview/coursePreviewAllmsg.tsx new file mode 100644 index 0000000..73ed1f9 --- /dev/null +++ b/apps/web/src/components/models/course/detail/CoursePreview/coursePreviewAllmsg.tsx @@ -0,0 +1,73 @@ +import { useEffect } from "react"; +import { CoursePreviewMsg } from "@web/src/app/main/course/preview/type.ts"; +import { Button, Tabs, Image, Skeleton } from "antd"; +import type { TabsProps } from "antd"; +import { PlayCircleOutlined } from "@ant-design/icons"; +export function CoursePreviewAllmsg({ + previewMsg, + items, + isLoading, +}: { + previewMsg?: CoursePreviewMsg; + items: TabsProps["items"]; + isLoading: boolean; +}) { + useEffect(() => { + console.log(previewMsg); + }); + const TapOnChange = (key: string) => { + console.log(key); + }; + return ( +
+
+
+ example +
+ +
+
+
+ {isLoading ? ( + + ) : ( + <> + + {previewMsg.Title} + + + {previewMsg.SubTitle} + + + {previewMsg.Description} + + + )} + + +
+
+
+ +
+
+ ); +} From b6fdb531317a49e2b52dd01cf445fa4f3ce839a7 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 09:42:01 +0800 Subject: [PATCH 16/30] add --- .../models/course/detail/CourseSyllabus/CourseSyllabus.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/web/src/components/models/course/detail/CourseSyllabus/CourseSyllabus.tsx b/apps/web/src/components/models/course/detail/CourseSyllabus/CourseSyllabus.tsx index 36eb086..9e6cf84 100755 --- a/apps/web/src/components/models/course/detail/CourseSyllabus/CourseSyllabus.tsx +++ b/apps/web/src/components/models/course/detail/CourseSyllabus/CourseSyllabus.tsx @@ -27,7 +27,9 @@ export const CourseSyllabus: React.FC = ({ onToggle, }) => { const { isHeaderVisible } = useContext(CourseDetailContext); - const [expandedSections, setExpandedSections] = useState([]); + const [expandedSections, setExpandedSections] = useState( + sections.map((section) => section.id) // 默认展开所有章节 + ); const sectionRefs = useRef<{ [key: string]: HTMLDivElement | null }>({}); const toggleSection = (sectionId: string) => { From 8d0a79646ce15f6155c264d688a2bbe5362d43e6 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 09:49:05 +0800 Subject: [PATCH 17/30] aff --- apps/web/src/app/main/course/preview/type.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/web/src/app/main/course/preview/type.ts b/apps/web/src/app/main/course/preview/type.ts index 3119ae7..fe3a2fd 100644 --- a/apps/web/src/app/main/course/preview/type.ts +++ b/apps/web/src/app/main/course/preview/type.ts @@ -1,8 +1,8 @@ -export interface CoursePreviewMsg{ - videoPreview: string; - Title: string; - SubTitle:string; - Description:string; - ToCourseUrl:string; - isLoading:Boolean +export interface CoursePreviewMsg { + videoPreview: string; + Title: string; + SubTitle: string; + Description: string; + ToCourseUrl: string; + isLoading: boolean; } From 82048a115e673d73630209c54a6ea9f97bc6302a Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 09:49:07 +0800 Subject: [PATCH 18/30] aff --- .../CoursePreview/coursePreviewAllmsg.tsx | 30 ++++++------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/apps/web/src/components/models/course/detail/CoursePreview/coursePreviewAllmsg.tsx b/apps/web/src/components/models/course/detail/CoursePreview/coursePreviewAllmsg.tsx index 73ed1f9..2a89d44 100644 --- a/apps/web/src/components/models/course/detail/CoursePreview/coursePreviewAllmsg.tsx +++ b/apps/web/src/components/models/course/detail/CoursePreview/coursePreviewAllmsg.tsx @@ -1,33 +1,21 @@ -import { useEffect } from "react"; +import { useContext, useEffect } from "react"; import { CoursePreviewMsg } from "@web/src/app/main/course/preview/type.ts"; import { Button, Tabs, Image, Skeleton } from "antd"; import type { TabsProps } from "antd"; import { PlayCircleOutlined } from "@ant-design/icons"; -export function CoursePreviewAllmsg({ - previewMsg, - items, - isLoading, -}: { - previewMsg?: CoursePreviewMsg; - items: TabsProps["items"]; - isLoading: boolean; -}) { - useEffect(() => { - console.log(previewMsg); - }); +import { CourseDetailContext } from "../CourseDetailContext"; +export function CoursePreview() { const TapOnChange = (key: string) => { console.log(key); }; + const { course, isLoading, lecture, lectureIsLoading, selectedLectureId } = + useContext(CourseDetailContext); return (
example - {previewMsg.Title} + {course.title} - {previewMsg.SubTitle} + {course.subTitle} - {previewMsg.Description} + {course.Description} )} From 8652488bad73e6e0c410e613d703a970e56620fa Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 09:49:10 +0800 Subject: [PATCH 19/30] add --- apps/web/src/utils/axios-client.ts | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/apps/web/src/utils/axios-client.ts b/apps/web/src/utils/axios-client.ts index 23877df..24f0abc 100755 --- a/apps/web/src/utils/axios-client.ts +++ b/apps/web/src/utils/axios-client.ts @@ -1,20 +1,20 @@ -import axios from 'axios'; -import { env } from '../env'; -const BASE_URL = `http://${env.SERVER_IP}:3000` +import axios from "axios"; +import { env } from "../env"; +const BASE_URL = `http://${env.SERVER_IP}:${env.SERVER_PORT}`; const apiClient = axios.create({ - baseURL: BASE_URL, - // withCredentials: true, + baseURL: BASE_URL, + // withCredentials: true, }); // Add a request interceptor to attach the access token apiClient.interceptors.request.use( - (config) => { - const accessToken = localStorage.getItem('access_token'); - if (accessToken) { - config.headers['Authorization'] = `Bearer ${accessToken}`; - } - return config; - }, - (error) => Promise.reject(error) + (config) => { + const accessToken = localStorage.getItem("access_token"); + if (accessToken) { + config.headers["Authorization"] = `Bearer ${accessToken}`; + } + return config; + }, + (error) => Promise.reject(error) ); export default apiClient; From 29f49846b7cf807b41ecf5fba04280e6b6848c25 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 10:16:33 +0800 Subject: [PATCH 20/30] add --- apps/server/src/queue/models/post/utils.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/server/src/queue/models/post/utils.ts b/apps/server/src/queue/models/post/utils.ts index 1a352ff..98eb43c 100644 --- a/apps/server/src/queue/models/post/utils.ts +++ b/apps/server/src/queue/models/post/utils.ts @@ -1,5 +1,9 @@ import { db, VisitType } from '@nice/common'; export async function updatePostViewCount(id: string, type: VisitType) { + const post = await db.post.findFirst({ + where: { id }, + select: { id: true, meta: true }, + }); const totalViews = await db.visit.aggregate({ _sum: { views: true, @@ -16,6 +20,7 @@ export async function updatePostViewCount(id: string, type: VisitType) { }, data: { meta: { + ...((post?.meta as any) || {}), views: totalViews._sum.views || 0, }, // Use 0 if no visits exist }, @@ -28,6 +33,7 @@ export async function updatePostViewCount(id: string, type: VisitType) { }, data: { meta: { + ...((post?.meta as any) || {}), likes: totalViews._sum.views || 0, // Use 0 if no visits exist }, }, @@ -39,6 +45,7 @@ export async function updatePostViewCount(id: string, type: VisitType) { }, data: { meta: { + ...((post?.meta as any) || {}), hates: totalViews._sum.views || 0, // Use 0 if no visits exist }, }, From 0666aa04b146815931144f4a28e60b4d1ae971e1 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 10:16:36 +0800 Subject: [PATCH 21/30] add --- apps/web/src/components/common/uploader/AvatarUploader.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/web/src/components/common/uploader/AvatarUploader.tsx b/apps/web/src/components/common/uploader/AvatarUploader.tsx index d4077f3..1ca2e20 100755 --- a/apps/web/src/components/common/uploader/AvatarUploader.tsx +++ b/apps/web/src/components/common/uploader/AvatarUploader.tsx @@ -44,7 +44,9 @@ const AvatarUploader: React.FC = ({ // 在组件中定义 key 状态 const [avatarKey, setAvatarKey] = useState(0); const { token } = theme.useToken(); - + useEffect(() => { + setPreviewUrl(value || ""); + }, [value]); const handleChange = async (event: React.ChangeEvent) => { const selectedFile = event.target.files?.[0]; if (!selectedFile) return; From 0fe62d93475958d3ecb8eeaf9b9cda19ecdaf049 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 10:16:39 +0800 Subject: [PATCH 22/30] add --- .../course/detail/CourseDetailDescription.tsx | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/apps/web/src/components/models/course/detail/CourseDetailDescription.tsx b/apps/web/src/components/models/course/detail/CourseDetailDescription.tsx index 3b75ae9..a7eea6c 100755 --- a/apps/web/src/components/models/course/detail/CourseDetailDescription.tsx +++ b/apps/web/src/components/models/course/detail/CourseDetailDescription.tsx @@ -1,17 +1,13 @@ import { Course } from "@nice/common"; import React, { useContext } from "react"; -import { Typography, Skeleton } from "antd"; // 引入 antd 组件 +import { Image, Typography, Skeleton } from "antd"; // 引入 antd 组件 import { CourseDetailContext } from "./CourseDetailContext"; import { CalendarOutlined, EyeOutlined } from "@ant-design/icons"; import dayjs from "dayjs"; -interface CourseDetailProps { - course: Course; - isLoading: boolean; -} - -export const CourseDetailDescription: React.FC = () => { - const { course, isLoading } = useContext(CourseDetailContext); +export const CourseDetailDescription: React.FC = () => { + const { course, isLoading, selectedLectureId } = + useContext(CourseDetailContext); const { Paragraph, Title } = Typography; return ( @@ -20,6 +16,17 @@ export const CourseDetailDescription: React.FC = () => { ) : (
+ {!selectedLectureId && ( + <> +
+ +
+ + )}
{"课程简介:"}
{course?.subTitle}
From 836c116a3dbde4b178f647a7581b269a47a867bc Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 10:16:42 +0800 Subject: [PATCH 23/30] add --- .../course/detail/CourseDetailDisplayArea.tsx | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/apps/web/src/components/models/course/detail/CourseDetailDisplayArea.tsx b/apps/web/src/components/models/course/detail/CourseDetailDisplayArea.tsx index b5aed44..142abde 100755 --- a/apps/web/src/components/models/course/detail/CourseDetailDisplayArea.tsx +++ b/apps/web/src/components/models/course/detail/CourseDetailDisplayArea.tsx @@ -7,6 +7,7 @@ import { Course, LectureType, PostType } from "@nice/common"; import { CourseDetailContext } from "./CourseDetailContext"; import CollapsibleContent from "@web/src/components/common/container/CollapsibleContent"; import { Skeleton } from "antd"; +import { CoursePreview } from "./CoursePreview/CoursePreview"; // interface CourseDetailDisplayAreaProps { // // course: Course; @@ -27,15 +28,7 @@ export const CourseDetailDisplayArea: React.FC = () => { {lectureIsLoading && ( )} - {!selectedLectureId && !lectureIsLoading && ( - <> -
-
- {"123"} -
-
- - )} + {selectedLectureId && !lectureIsLoading && lecture?.meta?.type === LectureType.VIDEO && ( @@ -64,10 +57,7 @@ export const CourseDetailDisplayArea: React.FC = () => {
)}
- +
{/* 课程内容区域 */}
From 1a1a866406d682659fd644f91209e530391f8bca Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 10:16:44 +0800 Subject: [PATCH 24/30] add --- .../{coursePreviewAllmsg.tsx => CoursePreview.tsx} | 13 +------------ .../course/editor/context/CourseEditorContext.tsx | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 14 deletions(-) rename apps/web/src/components/models/course/detail/CoursePreview/{coursePreviewAllmsg.tsx => CoursePreview.tsx} (94%) diff --git a/apps/web/src/components/models/course/detail/CoursePreview/coursePreviewAllmsg.tsx b/apps/web/src/components/models/course/detail/CoursePreview/CoursePreview.tsx similarity index 94% rename from apps/web/src/components/models/course/detail/CoursePreview/coursePreviewAllmsg.tsx rename to apps/web/src/components/models/course/detail/CoursePreview/CoursePreview.tsx index 2a89d44..7d6d4f4 100644 --- a/apps/web/src/components/models/course/detail/CoursePreview/coursePreviewAllmsg.tsx +++ b/apps/web/src/components/models/course/detail/CoursePreview/CoursePreview.tsx @@ -5,9 +5,6 @@ import type { TabsProps } from "antd"; import { PlayCircleOutlined } from "@ant-design/icons"; import { CourseDetailContext } from "../CourseDetailContext"; export function CoursePreview() { - const TapOnChange = (key: string) => { - console.log(key); - }; const { course, isLoading, lecture, lectureIsLoading, selectedLectureId } = useContext(CourseDetailContext); return ( @@ -37,7 +34,7 @@ export function CoursePreview() { {course.subTitle} - {course.Description} + {course.content} )} @@ -48,14 +45,6 @@ export function CoursePreview() {
-
- -
); } diff --git a/apps/web/src/components/models/course/editor/context/CourseEditorContext.tsx b/apps/web/src/components/models/course/editor/context/CourseEditorContext.tsx index 5ee54b3..913bf34 100755 --- a/apps/web/src/components/models/course/editor/context/CourseEditorContext.tsx +++ b/apps/web/src/components/models/course/editor/context/CourseEditorContext.tsx @@ -2,6 +2,7 @@ import { createContext, useContext, ReactNode, useEffect } from "react"; import { Form, FormInstance, message } from "antd"; import { CourseDto, + CourseMeta, CourseStatus, ObjectType, PostType, @@ -10,6 +11,7 @@ import { import { api, usePost } from "@nice/client"; import { useNavigate } from "react-router-dom"; import { z } from "zod"; +import { useAuth } from "@web/src/providers/auth-provider"; export type CourseFormData = { title: string; @@ -42,6 +44,7 @@ export function CourseFormProvider({ }: CourseFormProviderProps) { const [form] = Form.useForm(); const { create, update, createCourse } = usePost(); + const { user } = useAuth(); const { data: course }: { data: CourseDto } = api.post.findFirst.useQuery( { where: { id: editId }, @@ -77,7 +80,7 @@ export function CourseFormProvider({ } }, [course, form]); - const onSubmit = async (values: CourseFormData) => { + const onSubmit = async (values: any) => { console.log(values); const sections = values?.sections || []; const termIds = taxonomies @@ -87,7 +90,7 @@ export function CourseFormProvider({ const formattedValues = { ...values, meta: { - thumbnail: values.thumbnail, + thumbnail: values?.meta?.thumbnail, }, terms: { connect: termIds.map((id) => ({ id })), // 转换成 connect 格式 @@ -98,6 +101,12 @@ export function CourseFormProvider({ delete formattedValues[tax.id]; }); delete formattedValues.sections; + if (course) { + formattedValues.meta = { + ...(course?.meta as CourseMeta), + thumbnail: values?.meta?.thumbnail, + }; + } try { if (editId) { await update.mutateAsync({ @@ -110,6 +119,7 @@ export function CourseFormProvider({ courseDetail: { data: { title: formattedValues.title || "12345", + // state: CourseStatus.DRAFT, type: PostType.COURSE, ...formattedValues, From 617c7db9197af313bdbc9a157a3d8ae099f094a9 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 11:50:33 +0800 Subject: [PATCH 25/30] add --- .../course/detail/CourseDetailDescription.tsx | 25 ++++++++--- .../detail/CourseSyllabus/LectureItem.tsx | 42 +++++++++++-------- 2 files changed, 44 insertions(+), 23 deletions(-) diff --git a/apps/web/src/components/models/course/detail/CourseDetailDescription.tsx b/apps/web/src/components/models/course/detail/CourseDetailDescription.tsx index a7eea6c..e33e445 100755 --- a/apps/web/src/components/models/course/detail/CourseDetailDescription.tsx +++ b/apps/web/src/components/models/course/detail/CourseDetailDescription.tsx @@ -1,15 +1,23 @@ import { Course } from "@nice/common"; -import React, { useContext } from "react"; +import React, { useContext, useMemo } from "react"; import { Image, Typography, Skeleton } from "antd"; // 引入 antd 组件 import { CourseDetailContext } from "./CourseDetailContext"; -import { CalendarOutlined, EyeOutlined } from "@ant-design/icons"; +import { + CalendarOutlined, + EyeOutlined, + PlayCircleOutlined, +} from "@ant-design/icons"; import dayjs from "dayjs"; +import { useNavigate } from "react-router-dom"; export const CourseDetailDescription: React.FC = () => { - const { course, isLoading, selectedLectureId } = + const { course, isLoading, selectedLectureId, setSelectedLectureId } = useContext(CourseDetailContext); const { Paragraph, Title } = Typography; - + const firstLectureId = useMemo(() => { + return course?.sections?.[0]?.lectures?.[0]?.id; + }, [course]); + const navigate = useNavigate(); return (
{isLoading || !course ? ( @@ -18,12 +26,19 @@ export const CourseDetailDescription: React.FC = () => {
{!selectedLectureId && ( <> -
+
+
{ + setSelectedLectureId(firstLectureId); + }} + className="w-full h-full absolute top-0 z-10 bg-black opacity-30 transition-opacity duration-300 ease-in-out hover:opacity-70 cursor-pointer"> + +
)} diff --git a/apps/web/src/components/models/course/detail/CourseSyllabus/LectureItem.tsx b/apps/web/src/components/models/course/detail/CourseSyllabus/LectureItem.tsx index a79b16e..ed73745 100755 --- a/apps/web/src/components/models/course/detail/CourseSyllabus/LectureItem.tsx +++ b/apps/web/src/components/models/course/detail/CourseSyllabus/LectureItem.tsx @@ -7,6 +7,7 @@ import { FileTextOutlined, PlayCircleOutlined, } from "@ant-design/icons"; // 使用 Ant Design 图标 +import { useParams } from "react-router-dom"; interface LectureItemProps { lecture: Lecture; @@ -16,25 +17,30 @@ interface LectureItemProps { export const LectureItem: React.FC = ({ lecture, onClick, -}) => ( -
onClick(lecture.id)}> - {lecture.type === LectureType.VIDEO && ( - - )} - {lecture.type === LectureType.ARTICLE && ( - // 为文章类型添加图标 - )} -
-

{lecture.title}

- {lecture.subTitle && ( -

{lecture.subTitle}

+}) => { + const { lectureId } = useParams(); + return ( +
onClick(lecture.id)}> + {lecture.type === LectureType.VIDEO && ( + )} -
- {/*
+ {lecture.type === LectureType.ARTICLE && ( + // 为文章类型添加图标 + )} +
+

{lecture.title}

+ {lecture.subTitle && ( +

+ {lecture.subTitle} +

+ )} +
+ {/*
{lecture.duration}分钟
*/} -
-); +
+ ); +}; From 0a2dad865f1ab64649aed1d9edd80f12db3be092 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 11:50:36 +0800 Subject: [PATCH 26/30] add --- packages/common/src/constants.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/common/src/constants.ts b/packages/common/src/constants.ts index 0a41f6e..fbc63cd 100755 --- a/packages/common/src/constants.ts +++ b/packages/common/src/constants.ts @@ -58,6 +58,7 @@ export const InitTaxonomies: { { name: "分类", slug: TaxonomySlug.CATEGORY, + objectType: [ObjectType.COURSE], }, { name: "难度等级", From 074ca5ca22002636950ca2746498055c235ff12f Mon Sep 17 00:00:00 2001 From: Rao <1227431568@qq.com> Date: Mon, 24 Feb 2025 11:50:56 +0800 Subject: [PATCH 27/30] rhtwork --- apps/server/src/main.ts | 2 +- apps/server/src/models/post/post.service.ts | 11 +- .../main/courses/components/FilterSection.tsx | 9 +- apps/web/src/app/main/courses/page.tsx | 1 + .../main/home/components/CategorySection.tsx | 248 ++++++++++-------- .../app/main/home/components/HeroSection.tsx | 15 +- apps/web/src/app/main/home/page.tsx | 2 + apps/web/src/hooks/useLocalSetting.ts | 4 +- apps/web/src/utils/axios-client.ts | 2 +- 9 files changed, 170 insertions(+), 124 deletions(-) diff --git a/apps/server/src/main.ts b/apps/server/src/main.ts index 386668a..8b82ed1 100755 --- a/apps/server/src/main.ts +++ b/apps/server/src/main.ts @@ -15,7 +15,7 @@ async function bootstrap() { const trpc = app.get(TrpcRouter); trpc.applyMiddleware(app); - const port = process.env.SERVER_PORT || 3001; + const port = process.env.SERVER_PORT || 3000; await app.listen(port); } diff --git a/apps/server/src/models/post/post.service.ts b/apps/server/src/models/post/post.service.ts index df99714..eeb6e98 100755 --- a/apps/server/src/models/post/post.service.ts +++ b/apps/server/src/models/post/post.service.ts @@ -19,6 +19,7 @@ import { setCourseInfo, setPostRelation } from './utils'; import EventBus, { CrudOperation } from '@server/utils/event-bus'; import { BaseTreeService } from '../base/base.tree.service'; import { z } from 'zod'; +import { DefaultArgs } from '@prisma/client/runtime/library'; @Injectable() export class PostService extends BaseTreeService { @@ -215,7 +216,15 @@ export class PostService extends BaseTreeService { return { ...result, items }; }); } - + async findManyWithPagination(args: + { page?: number; + pageSize?: number; + where?: Prisma.PostWhereInput; + select?: Prisma.PostSelect; + }): Promise<{ items: { id: string; type: string | null; level: string | null; state: string | null; title: string | null; subTitle: string | null; content: string | null; important: boolean | null; domainId: string | null; order: number | null; duration: number | null; rating: number | null; createdAt: Date; publishedAt: Date | null; updatedAt: Date; deletedAt: Date | null; authorId: string | null; parentId: string | null; hasChildren: boolean | null; meta: Prisma.JsonValue | null; }[]; totalPages: number; }> + { + return super.findManyWithPagination(args); + } protected async setPerms(data: Post, staff?: UserProfile) { if (!staff) return; const perms: ResPerm = { diff --git a/apps/web/src/app/main/courses/components/FilterSection.tsx b/apps/web/src/app/main/courses/components/FilterSection.tsx index 32f41ba..6de4312 100755 --- a/apps/web/src/app/main/courses/components/FilterSection.tsx +++ b/apps/web/src/app/main/courses/components/FilterSection.tsx @@ -2,8 +2,9 @@ import { Checkbox, Divider, Radio, Space , Spin} from 'antd'; import { categories, levels } from '../mockData'; import { TaxonomySlug, TermDto } from '@nice/common'; -import { useMemo } from 'react'; +import { useEffect, useMemo } from 'react'; import { api } from '@nice/client'; +import { useSearchParams } from 'react-router-dom'; interface FilterSectionProps { selectedCategory: string; @@ -53,6 +54,12 @@ export default function FilterSection({ const levels : GetTaxonomyProps = useGetTaxonomy({ type: TaxonomySlug.LEVEL, }) + + const [searchParams,setSearchParams] = useSearchParams() + useEffect(() => { + if(searchParams.get('category')) onCategoryChange(searchParams.get('category')) + },[searchParams.get('category')]) + return (
diff --git a/apps/web/src/app/main/courses/page.tsx b/apps/web/src/app/main/courses/page.tsx index 30cd309..cfdd484 100755 --- a/apps/web/src/app/main/courses/page.tsx +++ b/apps/web/src/app/main/courses/page.tsx @@ -66,6 +66,7 @@ export default function CoursesPage() { selectedCategory={selectedCategory} selectedLevel={selectedLevel} onCategoryChange={(category) => { + console.log(category); setSelectedCategory(category); setCurrentPage(1); }} diff --git a/apps/web/src/app/main/home/components/CategorySection.tsx b/apps/web/src/app/main/home/components/CategorySection.tsx index a64b551..967336f 100755 --- a/apps/web/src/app/main/home/components/CategorySection.tsx +++ b/apps/web/src/app/main/home/components/CategorySection.tsx @@ -1,7 +1,9 @@ import React, { useState, useCallback, useEffect, useMemo } from 'react'; -import { Typography, Button } from 'antd'; +import { Typography, Button, Spin } from 'antd'; import { stringToColor, TaxonomySlug, TermDto } from '@nice/common'; -import { api } from '@nice/client'; +import { api,} from '@nice/client'; +import { ControlOutlined } from '@ant-design/icons'; +import { useNavigate } from 'react-router-dom'; const { Title, Text } = Typography; @@ -11,45 +13,45 @@ interface CourseCategory { 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 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(null); const [showAll, setShowAll] = useState(false); - /** - * const {data,isLoading} :{data:TermDto[],isLoading:boolean}= api.term.findMany.useQuery({ + //获得分类 + const {data:courseCategoriesData,isLoading} :{data:TermDto[],isLoading:boolean}= api.term.findMany.useQuery({ where:{ taxonomy: { slug:TaxonomySlug.CATEGORY @@ -57,16 +59,32 @@ const CategorySection = () => { }, include:{ children :true - } + }, + orderBy: { + createdAt: 'desc', // 按创建时间降序排列 + }, + take:10 }) - const courseCategories: CourseCategory[] = useMemo(() => { - return data?.map((term) => ({ - name: term.name, - count: term.hasChildren ? term.children.length : 0, - description: term.description - })) || []; - },[data]) - */ + // 分类展示 + const [displayedCategories,setDisplayedCategories] = useState([]) + useEffect(() => { + console.log(courseCategoriesData); + 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) => { @@ -77,9 +95,7 @@ const CategorySection = () => { setHoveredIndex(null); }, []); - const displayedCategories = showAll - ? courseCategories - : courseCategories.slice(0, 8); + const navigate = useNavigate() return (
@@ -93,78 +109,86 @@ const CategorySection = () => {
- {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}课程类别`} - > -
+ { + isLoading ? : + (displayedCategories.map((category, index) => { + const categoryColor = stringToColor(category.name); + const isHovered = hoveredIndex === index; + + return (
-
-
-
-
- - {category.name} - - - {category.count} 门课程 - -
- - {category.description} - + key={index} + className="group relative min-h-[130px] rounded-2xl transition-all duration-700 ease-out cursor-pointer will-change-transform hover:-translate-y-2" + onMouseEnter={() => handleMouseEnter(index)} + onMouseLeave={handleMouseLeave} + role="button" + tabIndex={0} + aria-label={`查看${category.name}课程类别`} + onClick={()=>{ + console.log(category.name) + navigate(`/courses?category=${category.name}`) + }} + > +
- 了解更多 - +
+
+
+
+ + {category.name} + + {/* + {category.children.length} 门课程 + */} +
+ + {category.description} + +
- → - + 了解更多 + + → + +
-
- ); - })} + ); + })) + } +
- {courseCategories.length > 8 && ( + {!isLoading && courseCategoriesData.length > 8 && (
{/* Stats Container */} -
-
+
+
{platformStats.map((stat, index) => (
{
{stat.value}
-
{stat.label}
+
+ {stat.label} +
))}
diff --git a/apps/web/src/app/main/home/page.tsx b/apps/web/src/app/main/home/page.tsx index 4d4be9e..956a2e4 100755 --- a/apps/web/src/app/main/home/page.tsx +++ b/apps/web/src/app/main/home/page.tsx @@ -2,6 +2,8 @@ import HeroSection from './components/HeroSection'; import CategorySection from './components/CategorySection'; import CoursesSection from './components/CoursesSection'; import FeaturedTeachersSection from './components/FeaturedTeachersSection'; +import { api } from '@nice/client'; +import { useEffect } from 'react'; const HomePage = () => { const mockCourses = [ { diff --git a/apps/web/src/hooks/useLocalSetting.ts b/apps/web/src/hooks/useLocalSetting.ts index 03b4057..cd78328 100755 --- a/apps/web/src/hooks/useLocalSetting.ts +++ b/apps/web/src/hooks/useLocalSetting.ts @@ -6,8 +6,8 @@ export function useLocalSettings() { return `${protocol}://${env.SERVER_IP}:${port}`; }, []); const tusUrl = useMemo(() => getBaseUrl('http', 8080), [getBaseUrl]); - const apiUrl = useMemo(() => getBaseUrl('http', 3000), [getBaseUrl]); - const websocketUrl = useMemo(() => getBaseUrl('ws', 3000), [getBaseUrl]); + const apiUrl = useMemo(() => getBaseUrl('http', parseInt(env.SERVER_PORT)), [getBaseUrl]); + const websocketUrl = useMemo(() => getBaseUrl('ws', parseInt(env.SERVER_PORT)), [getBaseUrl]); const checkIsTusUrl = useCallback((url: string) => { return url.startsWith(tusUrl) }, [tusUrl]) diff --git a/apps/web/src/utils/axios-client.ts b/apps/web/src/utils/axios-client.ts index 23877df..a42ae46 100755 --- a/apps/web/src/utils/axios-client.ts +++ b/apps/web/src/utils/axios-client.ts @@ -1,6 +1,6 @@ import axios from 'axios'; import { env } from '../env'; -const BASE_URL = `http://${env.SERVER_IP}:3000` +const BASE_URL = `http://${env.SERVER_IP}:${env?.SERVER_PORT}` const apiClient = axios.create({ baseURL: BASE_URL, // withCredentials: true, From 90c3795eccf85a14312ef78e89675a15284368c2 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 11:53:14 +0800 Subject: [PATCH 28/30] add --- packages/common/prisma/schema.prisma | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/common/prisma/schema.prisma b/packages/common/prisma/schema.prisma index 01bb99e..c65a392 100755 --- a/packages/common/prisma/schema.prisma +++ b/packages/common/prisma/schema.prisma @@ -204,7 +204,7 @@ model Post { // 日期时间类型字段 createdAt DateTime @default(now()) @map("created_at") publishedAt DateTime? @map("published_at") // 发布时间 - updatedAt DateTime @updatedAt @map("updated_at") + updatedAt DateTime @map("updated_at") deletedAt DateTime? @map("deleted_at") // 删除时间,可为空 instructors PostInstructor[] // 关系类型字段 From 8cb8de8fa9404c04d72f7d5aa39104c659c3ead9 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 12:19:09 +0800 Subject: [PATCH 29/30] add --- apps/server/src/models/post/post.service.ts | 45 ++++++++++++++++----- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/apps/server/src/models/post/post.service.ts b/apps/server/src/models/post/post.service.ts index eeb6e98..30d56e8 100755 --- a/apps/server/src/models/post/post.service.ts +++ b/apps/server/src/models/post/post.service.ts @@ -49,7 +49,7 @@ export class PostService extends BaseTreeService { meta: { type: type, }, - }, + } as any, }, { tx }, ); @@ -71,7 +71,7 @@ export class PostService extends BaseTreeService { parentId: courseId, title: title, authorId: staff?.id, - }, + } as any, }, { tx }, ); @@ -216,15 +216,38 @@ export class PostService extends BaseTreeService { return { ...result, items }; }); } - async findManyWithPagination(args: - { page?: number; - pageSize?: number; - where?: Prisma.PostWhereInput; - select?: Prisma.PostSelect; - }): Promise<{ items: { id: string; type: string | null; level: string | null; state: string | null; title: string | null; subTitle: string | null; content: string | null; important: boolean | null; domainId: string | null; order: number | null; duration: number | null; rating: number | null; createdAt: Date; publishedAt: Date | null; updatedAt: Date; deletedAt: Date | null; authorId: string | null; parentId: string | null; hasChildren: boolean | null; meta: Prisma.JsonValue | null; }[]; totalPages: number; }> - { - return super.findManyWithPagination(args); - } + async findManyWithPagination(args: { + page?: number; + pageSize?: number; + where?: Prisma.PostWhereInput; + select?: Prisma.PostSelect; + }): Promise<{ + items: { + id: string; + type: string | null; + level: string | null; + state: string | null; + title: string | null; + subTitle: string | null; + content: string | null; + important: boolean | null; + domainId: string | null; + order: number | null; + duration: number | null; + rating: number | null; + createdAt: Date; + publishedAt: Date | null; + updatedAt: Date; + deletedAt: Date | null; + authorId: string | null; + parentId: string | null; + hasChildren: boolean | null; + meta: Prisma.JsonValue | null; + }[]; + totalPages: number; + }> { + return super.findManyWithPagination(args); + } protected async setPerms(data: Post, staff?: UserProfile) { if (!staff) return; const perms: ResPerm = { From 5a5d4ec3ff6fe1b147fbb03e00203077e1d21bce Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 12:57:26 +0800 Subject: [PATCH 30/30] add --- apps/server/src/models/post/utils.ts | 5 +++++ apps/server/src/queue/models/post/post.queue.service.ts | 1 + .../editor/form/CourseContentForm/CourseContentForm.tsx | 3 +++ .../course/editor/form/CourseContentForm/LectureList.tsx | 3 +++ 4 files changed, 12 insertions(+) diff --git a/apps/server/src/models/post/utils.ts b/apps/server/src/models/post/utils.ts index 20bbe59..c257663 100755 --- a/apps/server/src/models/post/utils.ts +++ b/apps/server/src/models/post/utils.ts @@ -137,6 +137,11 @@ export async function setCourseInfo({ data }: { data: Post }) { id: true, descendant: true, }, + orderBy: { + descendant: { + order: 'asc', + }, + }, }); const descendants = ancestries.map((ancestry) => ancestry.descendant); const sections: SectionDto[] = descendants diff --git a/apps/server/src/queue/models/post/post.queue.service.ts b/apps/server/src/queue/models/post/post.queue.service.ts index f7370df..452076c 100644 --- a/apps/server/src/queue/models/post/post.queue.service.ts +++ b/apps/server/src/queue/models/post/post.queue.service.ts @@ -37,4 +37,5 @@ export class PostQueueService implements OnModuleInit { debounce: { id: `${QueueJobType.UPDATE_POST_STATE}_${data.id}` }, }); } + } diff --git a/apps/web/src/components/models/course/editor/form/CourseContentForm/CourseContentForm.tsx b/apps/web/src/components/models/course/editor/form/CourseContentForm/CourseContentForm.tsx index ee0916a..4e4d641 100755 --- a/apps/web/src/components/models/course/editor/form/CourseContentForm/CourseContentForm.tsx +++ b/apps/web/src/components/models/course/editor/form/CourseContentForm/CourseContentForm.tsx @@ -41,6 +41,9 @@ const CourseContentForm: React.FC = () => { type: PostType.SECTION, deletedAt: null, }, + orderBy: { + order: "asc", + }, }, { enabled: !!editId, diff --git a/apps/web/src/components/models/course/editor/form/CourseContentForm/LectureList.tsx b/apps/web/src/components/models/course/editor/form/CourseContentForm/LectureList.tsx index 1bbc610..dac0143 100755 --- a/apps/web/src/components/models/course/editor/form/CourseContentForm/LectureList.tsx +++ b/apps/web/src/components/models/course/editor/form/CourseContentForm/LectureList.tsx @@ -58,6 +58,9 @@ export const LectureList: React.FC = ({ type: PostType.LECTURE, deletedAt: null, }, + orderBy: { + order: "asc", + }, }, { enabled: !!sectionId,