addd
This commit is contained in:
parent
358d2ea9d5
commit
4a6957f181
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
});
|
||||
|
|
|
@ -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) => {
|
||||
navigate(`/course/${course.id}/detail`);
|
||||
window.scrollTo({ top: 0, behavior: "smooth", })
|
||||
if (!edit) {
|
||||
navigate(`/course/${course.id}/detail`);
|
||||
} else {
|
||||
navigate(`/course/${course.id}/editor`);
|
||||
}
|
||||
window.scrollTo({ top: 0, behavior: "smooth" });
|
||||
};
|
||||
return (
|
||||
<Card
|
||||
|
@ -46,10 +51,10 @@ export default function CourseCard({ course }: CourseCardProps) {
|
|||
key={term.id}
|
||||
color={
|
||||
term?.taxonomy?.slug ===
|
||||
TaxonomySlug.CATEGORY
|
||||
TaxonomySlug.CATEGORY
|
||||
? "blue"
|
||||
: term?.taxonomy?.slug ===
|
||||
TaxonomySlug.LEVEL
|
||||
TaxonomySlug.LEVEL
|
||||
? "green"
|
||||
: "orange"
|
||||
}
|
||||
|
@ -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>
|
||||
|
|
|
@ -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 = [
|
||||
{ key: "home", path: "/", label: "首页" },
|
||||
{ key: "courses", path: "/courses", label: "全部课程" },
|
||||
{ key: "paths", path: "/paths", label: "学习路径" },
|
||||
];
|
||||
|
||||
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]);
|
||||
|
||||
const selectedKey =
|
||||
menuItems.find((item) => item.path === pathname)?.key || "";
|
||||
return (
|
||||
|
|
|
@ -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 && {
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,15 +65,32 @@ 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: [
|
||||
{
|
||||
path: ":id?/editor",
|
||||
element: (
|
||||
<WithAuth >
|
||||
<WithAuth>
|
||||
<CourseEditorLayout></CourseEditorLayout>
|
||||
</WithAuth>
|
||||
),
|
||||
|
|
|
@ -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
|
||||
|
||||
// 索引
|
||||
|
|
|
@ -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: {
|
||||
|
|
Loading…
Reference in New Issue