From 939a313c9ef140ab494c2bd00ba49d8300922281 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 09:01:23 +0800 Subject: [PATCH 01/27] add --- apps/web/src/hooks/useLocalSetting.ts | 36 ++++++++++++++++----------- config/nginx/conf.d/web.template | 1 + 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/apps/web/src/hooks/useLocalSetting.ts b/apps/web/src/hooks/useLocalSetting.ts index 03b4057..7bc84ee 100755 --- a/apps/web/src/hooks/useLocalSetting.ts +++ b/apps/web/src/hooks/useLocalSetting.ts @@ -1,17 +1,25 @@ - import { useCallback, useMemo } from "react"; import { env } from "../env"; export function useLocalSettings() { - const getBaseUrl = useCallback((protocol: string, port: number) => { - 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 checkIsTusUrl = useCallback((url: string) => { - return url.startsWith(tusUrl) - }, [tusUrl]) - return { - apiUrl, websocketUrl, checkIsTusUrl, tusUrl - } -} \ No newline at end of file + const getBaseUrl = useCallback((protocol: string, port: number) => { + return `${protocol}://${env.SERVER_IP}:${port}`; + }, []); + const tusUrl = useMemo(() => getBaseUrl("http", 8080), [getBaseUrl]); + const apiUrl = useMemo( + () => getBaseUrl("http", parseInt(env.SERVER_PORT)), + [getBaseUrl] + ); + const websocketUrl = useMemo(() => getBaseUrl("ws", 3000), [getBaseUrl]); + const checkIsTusUrl = useCallback( + (url: string) => { + return url.startsWith(tusUrl); + }, + [tusUrl] + ); + return { + apiUrl, + websocketUrl, + checkIsTusUrl, + tusUrl, + }; +} diff --git a/config/nginx/conf.d/web.template b/config/nginx/conf.d/web.template index 7f564bb..779c9b2 100755 --- a/config/nginx/conf.d/web.template +++ b/config/nginx/conf.d/web.template @@ -101,6 +101,7 @@ server { internal; # 代理到认证服务 proxy_pass http://${SERVER_IP}:${SERVER_PORT}/auth/file; + # 请求优化:不传递请求体 proxy_pass_request_body off; proxy_set_header Content-Length ""; From 0081ccf3f2de55ef253f35dd4b689e6c826fbc87 Mon Sep 17 00:00:00 2001 From: ditiqi Date: Mon, 24 Feb 2025 09:32:55 +0800 Subject: [PATCH 02/27] 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 03/27] 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 04/27] 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 05/27] 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 06/27] 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 07/27] 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 08/27] 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 09/27] 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 10/27] 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 11/27] 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 12/27] 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 13/27] 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 14/27] 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 15/27] 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 16/27] 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 17/27] 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 18/27] 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 19/27] 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 20/27] 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 21/27] 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 22/27] 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 23/27] 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 24/27] 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 25/27] 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 26/27] 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 27/27] 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: "难度等级",