This commit is contained in:
ditiqi 2025-02-26 21:08:38 +08:00
parent 358d2ea9d5
commit 4a6957f181
11 changed files with 147 additions and 64 deletions

View File

@ -306,37 +306,37 @@ export class PostService extends BaseTreeService<Prisma.PostDelegate> {
staff?.id && {
authorId: staff.id,
},
staff?.id && {
watchableStaffs: {
some: {
id: staff.id,
},
},
},
deptId && {
watchableDepts: {
some: {
id: {
in: parentDeptIds,
},
},
},
},
// staff?.id && {
// watchableStaffs: {
// some: {
// id: staff.id,
// },
// },
// },
// deptId && {
// watchableDepts: {
// some: {
// id: {
// in: parentDeptIds,
// },
// },
// },
// },
{
AND: [
{
watchableStaffs: {
none: {}, // 匹配 watchableStaffs 为空
},
},
{
watchableDepts: {
none: {}, // 匹配 watchableDepts 为空
},
},
],
},
// {
// AND: [
// {
// watchableStaffs: {
// none: {}, // 匹配 watchableStaffs 为空
// },
// },
// {
// watchableDepts: {
// none: {}, // 匹配 watchableDepts 为空
// },
// },
// ],
// },
].filter(Boolean);
if (orCondition?.length > 0) return orCondition;

View File

@ -23,7 +23,7 @@ export async function updateTotalCourseViewCount(type: VisitType) {
views: true,
},
where: {
postId: { in: lectures.map((lecture) => lecture.id) },
postId: { in: posts.map((post) => post.id) },
type: type,
},
});

View File

@ -9,13 +9,18 @@ import { useNavigate } from "react-router-dom";
interface CourseCardProps {
course: CourseDto;
edit?: boolean;
}
const { Title, Text } = Typography;
export default function CourseCard({ course }: CourseCardProps) {
export default function CourseCard({ course, edit = false }: CourseCardProps) {
const navigate = useNavigate();
const handleClick = (course: CourseDto) => {
if (!edit) {
navigate(`/course/${course.id}/detail`);
window.scrollTo({ top: 0, behavior: "smooth", })
} else {
navigate(`/course/${course.id}/editor`);
}
window.scrollTo({ top: 0, behavior: "smooth" });
};
return (
<Card
@ -80,9 +85,8 @@ export default function CourseCard({ course }: CourseCardProps) {
</Text>
</div>
<span className="text-xs font-medium text-gray-500 flex items-center">
<EyeOutlined className="mr-1" />{course?.meta?.views
? `观看次数 ${course?.meta?.views}`
: null}
<EyeOutlined className="mr-1" />
{`观看次数 ${course?.meta?.views || 0}`}
</span>
</div>
<div className="pt-4 border-t border-gray-100 text-center">
@ -91,7 +95,7 @@ export default function CourseCard({ course }: CourseCardProps) {
size="large"
className="w-full shadow-[0_8px_20px_-6px_rgba(59,130,246,0.5)] hover:shadow-[0_12px_24px_-6px_rgba(59,130,246,0.6)]
transform hover:translate-y-[-2px] transition-all duration-500 ease-out">
{edit ? "进行编辑" : "立即学习"}
</Button>
</div>
</div>

View File

@ -1,15 +1,30 @@
import { useAuth } from "@web/src/providers/auth-provider";
import { Menu } from "antd";
import { useMemo } from "react";
import { useNavigate, useLocation } from "react-router-dom";
const menuItems = [
export const NavigationMenu = () => {
const navigate = useNavigate();
const { isAuthenticated } = useAuth();
const { pathname } = useLocation();
const menuItems = useMemo(() => {
const baseItems = [
{ key: "home", path: "/", label: "首页" },
{ key: "courses", path: "/courses", label: "全部课程" },
{ key: "paths", path: "/paths", label: "学习路径" },
];
if (!isAuthenticated) {
return baseItems;
} else {
return [
...baseItems,
{ key: "my-duty", path: "/my-duty", label: "我创建的" },
{ key: "my-learning", path: "/my-learning", label: "我学习的" },
];
}
}, [isAuthenticated]);
export const NavigationMenu = () => {
const navigate = useNavigate();
const { pathname } = useLocation();
const selectedKey =
menuItems.find((item) => item.path === pathname)?.key || "";
return (

View File

@ -90,14 +90,14 @@ export function UserMenu() {
icon: <UserOutlined className="text-lg" />,
label: "我创建的课程",
action: () => {
setModalOpen(true);
navigate("/my/duty");
},
},
{
icon: <UserOutlined className="text-lg" />,
label: "我学习的课程",
action: () => {
setModalOpen(true);
navigate("/my/learning");
},
},
canManageAnyStaff && {

View File

@ -1,7 +1,21 @@
import CourseList from "@web/src/components/models/course/list/CourseList";
import { useAuth } from "@web/src/providers/auth-provider";
export default function MyDutyPage() {
return <>
const { user } = useAuth();
return (
<>
<div className="p-4">
<CourseList
edit
params={{
pageSize: 12,
where: {
authorId: user.id,
},
}}
cols={4}></CourseList>
</div>
</>
);
}

View File

@ -1,3 +1,21 @@
import CourseList from "@web/src/components/models/course/list/CourseList";
import { useAuth } from "@web/src/providers/auth-provider";
export default function MyLearningPage() {
return <></>;
const { user } = useAuth();
return (
<>
<div className="p-4">
<CourseList
edit
params={{
pageSize: 12,
where: {
authorId: user.id,
},
}}
cols={4}></CourseList>
</div>
</>
);
}

View File

@ -13,6 +13,7 @@ interface CourseListProps {
};
cols?: number;
showPagination?: boolean;
edit?: boolean;
}
interface CoursesPagnationProps {
data: {
@ -25,6 +26,7 @@ export default function CourseList({
params,
cols = 3,
showPagination = true,
edit = false,
}: CourseListProps) {
const [currentPage, setCurrentPage] = useState<number>(params?.page || 1);
const { data, isLoading }: CoursesPagnationProps =
@ -55,7 +57,11 @@ export default function CourseList({
window.scrollTo({ top: 0, behavior: "smooth" });
}
if (isLoading) {
return <Skeleton paragraph={{ rows: 10 }}></Skeleton>;
return (
<div className="space-y-6">
<Skeleton paragraph={{ rows: 10 }}></Skeleton>
</div>
);
}
return (
<div className="space-y-6">
@ -66,7 +72,11 @@ export default function CourseList({
<Skeleton paragraph={{ rows: 5 }}></Skeleton>
) : (
courses.map((course) => (
<CourseCard key={course.id} course={course} />
<CourseCard
edit={edit}
key={course.id}
course={course}
/>
))
)}
</div>

View File

@ -18,6 +18,8 @@ import CoursesPage from "../app/main/courses/page";
import PathsPage from "../app/main/paths/page";
import { adminRoute } from "./admin-route";
import { CoursePreview } from "../app/main/course/preview/page";
import MyLearningPage from "../app/main/my-learning/page";
import MyDutyPage from "../app/main/my-duty/page";
interface CustomIndexRouteObject extends IndexRouteObject {
name?: string;
breadcrumb?: string;
@ -63,8 +65,25 @@ export const routes: CustomRouteObject[] = [
path: "courses",
element: <CoursesPage></CoursesPage>,
},
{
path: "my-duty",
element: (
<WithAuth>
<MyDutyPage></MyDutyPage>
</WithAuth>
),
},
{
path: "my-learning",
element: (
<WithAuth>
<MyLearningPage></MyLearningPage>
</WithAuth>
),
},
],
},
{
path: "course",
children: [

View File

@ -88,9 +88,12 @@ model Staff {
deletedAt DateTime? @map("deleted_at")
officerId String? @map("officer_id")
watchedPost Post[] @relation("post_watch_staff")
// watchedPost Post[] @relation("post_watch_staff")
visits Visit[]
posts Post[]
learningPost Post[] @relation("post_student")
sentMsgs Message[] @relation("message_sender")
receivedMsgs Message[] @relation("message_receiver")
registerToken String?
@ -124,7 +127,7 @@ model Department {
deptStaffs Staff[] @relation("DeptStaff")
terms Term[] @relation("department_term")
watchedPost Post[] @relation("post_watch_dept")
// watchedPost Post[] @relation("post_watch_dept")
hasChildren Boolean? @default(false) @map("has_children")
@@index([parentId])
@ -201,7 +204,7 @@ model Post {
order Float? @default(0) @map("order")
duration Int?
rating Int? @default(0)
students Staff[] @relation("post_student")
depts Department[] @relation("post_dept")
// 索引
// 日期时间类型字段
@ -223,8 +226,8 @@ model Post {
ancestors PostAncestry[] @relation("DescendantPosts")
descendants PostAncestry[] @relation("AncestorPosts")
resources Resource[] // 附件列表
watchableStaffs Staff[] @relation("post_watch_staff") // 可观看的员工列表,关联 Staff 模型
watchableDepts Department[] @relation("post_watch_dept") // 可观看的部门列表,关联 Department 模型
// watchableStaffs Staff[] @relation("post_watch_staff")
// watchableDepts Department[] @relation("post_watch_dept") // 可观看的部门列表,关联 Department 模型
meta Json? // 封面url 视频url objectives具体的学习目标 rating评分Int
// 索引

View File

@ -6,8 +6,8 @@ export const postDetailSelect: Prisma.PostSelect = {
title: true,
content: true,
resources: true,
watchableDepts: true,
watchableStaffs: true,
// watchableDepts: true,
// watchableStaffs: true,
updatedAt: true,
author: {
select: {