diff --git a/apps/server/src/models/post/utils.ts b/apps/server/src/models/post/utils.ts
index 40ea595..9185a0f 100644
--- a/apps/server/src/models/post/utils.ts
+++ b/apps/server/src/models/post/utils.ts
@@ -124,7 +124,10 @@ export async function updateCourseEnrollmentStats(courseId: string) {
},
});
}
+
export async function setCourseInfo({ data }: { data: Post }) {
+ // await db.term
+
if (data?.type === PostType.COURSE) {
const ancestries = await db.postAncestry.findMany({
where: {
diff --git a/apps/web/src/app/main/course/detail/page.tsx b/apps/web/src/app/main/course/detail/page.tsx
index d1bf172..16f7173 100644
--- a/apps/web/src/app/main/course/detail/page.tsx
+++ b/apps/web/src/app/main/course/detail/page.tsx
@@ -2,7 +2,7 @@ import CourseDetail from "@web/src/components/models/course/detail/CourseDetail"
import { useParams } from "react-router-dom";
export function CourseDetailPage() {
- const { id } = useParams();
+ const { id, lectureId } = useParams();
console.log("Course ID:", id);
- return ;
+ return ;
}
diff --git a/apps/web/src/app/main/courses/components/FilterSection.tsx b/apps/web/src/app/main/courses/components/FilterSection.tsx
index 678c227..ae4da2b 100644
--- a/apps/web/src/app/main/courses/components/FilterSection.tsx
+++ b/apps/web/src/app/main/courses/components/FilterSection.tsx
@@ -1,6 +1,7 @@
import { Checkbox, Divider, Radio, Space } from "antd";
import { categories, levels } from "../mockData";
import { api } from "@nice/client";
+import { TaxonomySlug } from "@nice/common";
interface FilterSectionProps {
selectedCategory: string;
@@ -15,6 +16,13 @@ export default function FilterSection({
onCategoryChange,
onLevelChange,
}: FilterSectionProps) {
+ const { data: levels, isLoading } = api.term.findMany.useQuery({
+ where: {
+ taxonomy: {
+ slug: TaxonomySlug.LEVEL,
+ },
+ },
+ });
// const { data } = api.term;
return (
@@ -42,9 +50,9 @@ export default function FilterSection({
onChange={(e) => onLevelChange(e.target.value)}
className="flex flex-col space-y-3">
全部难度
- {levels.map((level) => (
-
- {level}
+ {levels?.map((level) => (
+
+ {level.name}
))}
diff --git a/apps/web/src/app/main/layout/MainHeader.tsx b/apps/web/src/app/main/layout/MainHeader.tsx
index d7d089b..80ea733 100644
--- a/apps/web/src/app/main/layout/MainHeader.tsx
+++ b/apps/web/src/app/main/layout/MainHeader.tsx
@@ -1,65 +1,75 @@
-import { useState } from 'react';
-import { Input, Layout, Avatar, Button, Dropdown } from 'antd';
-import { SearchOutlined, UserOutlined } from '@ant-design/icons';
-import { useAuth } from '@web/src/providers/auth-provider';
-import { useNavigate } from 'react-router-dom';
-import { UserMenu } from './UserMenu';
-import { NavigationMenu } from './NavigationMenu';
+import { useState } from "react";
+import { Input, Layout, Avatar, Button, Dropdown } from "antd";
+import { EditFilled, SearchOutlined, UserOutlined } from "@ant-design/icons";
+import { useAuth } from "@web/src/providers/auth-provider";
+import { useNavigate } from "react-router-dom";
+import { UserMenu } from "./UserMenu";
+import { NavigationMenu } from "./NavigationMenu";
const { Header } = Layout;
export function MainHeader() {
- const [searchValue, setSearchValue] = useState('');
- const { isAuthenticated, user } = useAuth();
- const navigate = useNavigate();
+ const [searchValue, setSearchValue] = useState("");
+ const { isAuthenticated, user } = useAuth();
+ const navigate = useNavigate();
- return (
-
-
-
-
navigate('/')}
- className="text-2xl font-bold bg-gradient-to-r from-primary-600 via-primary-500 to-primary-400 bg-clip-text text-transparent hover:scale-105 transition-transform cursor-pointer"
- >
- 烽火慕课
-
-
-
-
-
- }
- placeholder="搜索课程"
- className="w-72 rounded-full"
- value={searchValue}
- onChange={(e) => setSearchValue(e.target.value)}
- />
-
- {isAuthenticated ? (
-
}
- trigger={['click']}
- placement="bottomRight"
- >
-
- {(user?.showname || user?.username || '')[0]?.toUpperCase()}
-
-
- ) : (
-
- )}
-
-
-
- );
-}
\ No newline at end of file
+ return (
+
+
+
+
navigate("/")}
+ className="text-2xl font-bold bg-gradient-to-r from-primary-600 via-primary-500 to-primary-400 bg-clip-text text-transparent hover:scale-105 transition-transform cursor-pointer">
+ 烽火慕课
+
+
+
+
+
+
+ }
+ placeholder="搜索课程"
+ className="w-72 rounded-full"
+ value={searchValue}
+ onChange={(e) => setSearchValue(e.target.value)}
+ />
+
+ {isAuthenticated && (
+ <>
+
+ >
+ )}
+ {isAuthenticated ? (
+
}
+ trigger={["click"]}
+ placement="bottomRight">
+
+ {(user?.showname ||
+ user?.username ||
+ "")[0]?.toUpperCase()}
+
+
+ ) : (
+
+ )}
+
+
+
+ );
+}
diff --git a/apps/web/src/components/models/course/detail/CourseDetail.tsx b/apps/web/src/components/models/course/detail/CourseDetail.tsx
index 402fbd7..353ec4f 100644
--- a/apps/web/src/components/models/course/detail/CourseDetail.tsx
+++ b/apps/web/src/components/models/course/detail/CourseDetail.tsx
@@ -1,7 +1,13 @@
import { CourseDetailProvider } from "./CourseDetailContext";
import CourseDetailLayout from "./CourseDetailLayout";
-export default function CourseDetail({ id }: { id?: string }) {
+export default function CourseDetail({
+ id,
+ lectureId,
+}: {
+ id?: string;
+ lectureId?: string;
+}) {
const iframeStyle = {
width: "50%",
height: "100vh",
diff --git a/apps/web/src/components/models/course/detail/CourseDetailContext.tsx b/apps/web/src/components/models/course/detail/CourseDetailContext.tsx
index dbb7b87..60d1bd3 100644
--- a/apps/web/src/components/models/course/detail/CourseDetailContext.tsx
+++ b/apps/web/src/components/models/course/detail/CourseDetailContext.tsx
@@ -21,12 +21,13 @@ export function CourseDetailProvider({
children,
editId,
}: CourseFormProviderProps) {
+
const { data: course, isLoading }: { data: CourseDto; isLoading: boolean } =
(api.post as any).findFirst.useQuery(
{
where: { id: editId },
include: {
- sections: { include: { lectures: true } },
+ // sections: { include: { lectures: true } },
enrollments: true,
},
},
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 58212a1..aef7064 100644
--- a/apps/web/src/components/models/course/detail/CourseSyllabus/CourseSyllabus.tsx
+++ b/apps/web/src/components/models/course/detail/CourseSyllabus/CourseSyllabus.tsx
@@ -7,11 +7,12 @@ import {
import { ChevronLeftIcon, ChevronRightIcon } from "@heroicons/react/24/outline";
import React, { useState, useRef, useContext } from "react";
import { motion, AnimatePresence } from "framer-motion";
-import { SectionDto } from "@nice/common";
+import { SectionDto, TaxonomySlug } from "@nice/common";
import { SyllabusHeader } from "./SyllabusHeader";
import { SectionItem } from "./SectionItem";
import { CollapsedButton } from "./CollapsedButton";
import { CourseDetailContext } from "../CourseDetailContext";
+import { api } from "@nice/client";
interface CourseSyllabusProps {
sections: SectionDto[];
@@ -29,7 +30,11 @@ 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)
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 9a87d75..0999f3c 100644
--- a/apps/web/src/components/models/course/detail/CourseSyllabus/LectureItem.tsx
+++ b/apps/web/src/components/models/course/detail/CourseSyllabus/LectureItem.tsx
@@ -1,9 +1,8 @@
// components/CourseSyllabus/LectureItem.tsx
-import { Lecture } from "@nice/common";
+import { Lecture, LectureType } from "@nice/common";
import React from "react";
-import { motion } from "framer-motion";
-import { ClockIcon, PlayCircleIcon } from "@heroicons/react/24/outline";
+import { ClockCircleOutlined, FileTextOutlined, PlayCircleOutlined } from "@ant-design/icons"; // 使用 Ant Design 图标
interface LectureItemProps {
lecture: Lecture;
@@ -14,23 +13,24 @@ export const LectureItem: React.FC = ({
lecture,
onClick,
}) => (
- onClick(lecture.id)}>
-
+ {lecture.type === LectureType.VIDEO && (
+
+ )}
+ {lecture.type === LectureType.ARTICLE && (
+ // 为文章类型添加图标
+ )}
{lecture.title}
- {lecture.description && (
-
- {lecture.description}
-
+ {lecture.subTitle && (
+
{lecture.subTitle}
)}
-
+
{lecture.duration}分钟
-
+
);
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 100fb6e..95c61db 100644
--- a/apps/web/src/components/models/course/detail/CourseSyllabus/SectionItem.tsx
+++ b/apps/web/src/components/models/course/detail/CourseSyllabus/SectionItem.tsx
@@ -33,8 +33,8 @@ export const SectionItem = React.forwardRef(
{section.title}
- {section.totalLectures}节课 ·{" "}
- {Math.floor(section.totalDuration / 60)}分钟
+ {section?.lectures?.length}节课 ·{" "}
+ {/* {Math.floor(section?.totalDuration / 60)}分钟 */}
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 fc3dc51..efa4962 100644
--- a/apps/web/src/components/models/course/editor/context/CourseEditorContext.tsx
+++ b/apps/web/src/components/models/course/editor/context/CourseEditorContext.tsx
@@ -96,7 +96,7 @@ export function CourseFormProvider({
};
// 删除原始的 taxonomy 字段
taxonomies.forEach((tax) => {
- delete formattedValues[tax.name];
+ delete formattedValues[tax.id];
});
delete formattedValues.requirements;
delete formattedValues.objectives;
diff --git a/apps/web/src/components/models/course/editor/form/CourseBasicForm.tsx b/apps/web/src/components/models/course/editor/form/CourseBasicForm.tsx
index 14eae28..f038144 100644
--- a/apps/web/src/components/models/course/editor/form/CourseBasicForm.tsx
+++ b/apps/web/src/components/models/course/editor/form/CourseBasicForm.tsx
@@ -53,7 +53,9 @@ export function CourseBasicForm() {
label={tax.name}
name={tax.id}
key={index}>
-
+
))}
{/*
diff --git a/apps/web/src/routes/index.tsx b/apps/web/src/routes/index.tsx
index cd51fcf..cee94f9 100755
--- a/apps/web/src/routes/index.tsx
+++ b/apps/web/src/routes/index.tsx
@@ -56,11 +56,10 @@ export const routes: CustomRouteObject[] = [
{
index: true,
element: ,
-
},
{
path: "paths",
- element:
+ element: ,
},
{
path: "courses",
@@ -125,7 +124,7 @@ export const routes: CustomRouteObject[] = [
],
},
{
- path: ":id?/detail", // 使用 ? 表示 id 参数是可选的
+ path: ":id?/detail/:lectureId?", // 使用 ? 表示 id 参数是可选的
element: ,
},
],
diff --git a/packages/common/prisma/schema.prisma b/packages/common/prisma/schema.prisma
index 8ad7da3..103ea10 100644
--- a/packages/common/prisma/schema.prisma
+++ b/packages/common/prisma/schema.prisma
@@ -198,7 +198,8 @@ model Post {
terms Term[] @relation("post_term")
order Float? @default(0) @map("order")
duration Int?
-
+ rating Int? @default(0)
+ // 索引
// 日期时间类型字段
createdAt DateTime @default(now()) @map("created_at")
publishedAt DateTime? @map("published_at") // 发布时间
@@ -242,7 +243,6 @@ model PostAncestry {
relDepth Int @map("rel_depth")
ancestor Post? @relation("AncestorPosts", fields: [ancestorId], references: [id])
descendant Post @relation("DescendantPosts", fields: [descendantId], references: [id])
-
// 复合索引优化
// 索引建议
@@index([ancestorId]) // 针对祖先的查询
diff --git a/packages/common/src/enum.ts b/packages/common/src/enum.ts
index c642ca9..9598a55 100755
--- a/packages/common/src/enum.ts
+++ b/packages/common/src/enum.ts
@@ -6,8 +6,8 @@ export enum PostType {
POST_COMMENT = "post_comment",
COURSE_REVIEW = "course_review",
COURSE = "couse",
- LECTURE = "lecture",
SECTION = "section",
+ LECTURE = "lecture",
}
export enum LectureType {
VIDEO = "video",