This commit is contained in:
ditiqi 2025-02-26 11:39:53 +08:00
parent f8659b90ca
commit c9199a7709
5 changed files with 66 additions and 65 deletions

View File

@ -1,38 +1,42 @@
import React from 'react';
import { useLocation, Link, useMatches } from 'react-router-dom';
import { theme } from 'antd';
import { RightOutlined } from '@ant-design/icons';
import React from "react";
import { useLocation, Link, useMatches } from "react-router-dom";
import { theme } from "antd";
import { RightOutlined } from "@ant-design/icons";
export default function Breadcrumb() {
let matches = useMatches();
const { token } = theme.useToken()
const matches = useMatches();
const { token } = theme.useToken();
let crumbs = matches
// first get rid of any matches that don't have handle and crumb
.filter((match) => Boolean((match.handle as any)?.crumb))
// now map them into an array of elements, passing the loader
// data to each one
.map((match) => (match.handle as any).crumb(match.data));
const crumbs = matches
// first get rid of any matches that don't have handle and crumb
.filter((match) => Boolean((match.handle as any)?.crumb))
// now map them into an array of elements, passing the loader
// data to each one
.map((match) => (match.handle as any).crumb(match.data));
return (
<ol className='flex items-center space-x-2 text-gray-600'>
{crumbs.map((crumb, index) => (
<React.Fragment key={index}>
<li className={`inline-flex items-center `}
style={{
color: (index === crumbs.length - 1) ? token.colorPrimaryText : token.colorTextSecondary,
fontWeight: (index === crumbs.length - 1) ? "bold" : "normal",
}}
>
{crumb}
</li>
{index < crumbs.length - 1 && (
<li className='mx-2'>
<RightOutlined></RightOutlined>
</li>
)}
</React.Fragment>
))}
</ol>
);
return (
<ol className="flex items-center space-x-2 text-gray-600">
{crumbs.map((crumb, index) => (
<React.Fragment key={index}>
<li
className={`inline-flex items-center `}
style={{
color:
index === crumbs.length - 1
? token.colorPrimaryText
: token.colorTextSecondary,
fontWeight:
index === crumbs.length - 1 ? "bold" : "normal",
}}>
{crumb}
</li>
{index < crumbs.length - 1 && (
<li className="mx-2">
<RightOutlined></RightOutlined>
</li>
)}
</React.Fragment>
))}
</ol>
);
}

View File

@ -3,10 +3,17 @@ import {
courseDetailSelect,
CourseDto,
Lecture,
RolePerms,
VisitType,
} from "@nice/common";
import { useAuth } from "@web/src/providers/auth-provider";
import React, { createContext, ReactNode, useEffect, useState } from "react";
import React, {
createContext,
ReactNode,
useEffect,
useMemo,
useState,
} from "react";
import { useNavigate, useParams } from "react-router-dom";
interface CourseDetailContextType {
@ -19,11 +26,14 @@ interface CourseDetailContextType {
lectureIsLoading?: boolean;
isHeaderVisible: boolean; // 新增
setIsHeaderVisible: (visible: boolean) => void; // 新增
canEdit?: boolean;
}
interface CourseFormProviderProps {
children: ReactNode;
editId?: string; // 添加 editId 参数
}
export const CourseDetailContext =
createContext<CourseDetailContextType | null>(null);
export function CourseDetailProvider({
@ -32,8 +42,9 @@ export function CourseDetailProvider({
}: CourseFormProviderProps) {
const navigate = useNavigate();
const { read } = useVisitor();
const { user } = useAuth();
const { user, hasSomePermissions } = useAuth();
const { lectureId } = useParams();
const { data: course, isLoading }: { data: CourseDto; isLoading: boolean } =
(api.post as any).findFirst.useQuery(
{
@ -45,7 +56,14 @@ export function CourseDetailProvider({
},
{ enabled: Boolean(editId) }
);
const canEdit = useMemo(() => {
const isAuthor = user?.id === course?.authorId;
const isDept = course?.depts
?.map((dept) => dept.id)
.includes(user?.deptId);
const isRoot = hasSomePermissions(RolePerms?.MANAGE_ANY_POST);
return isAuthor || isDept || isRoot;
}, [user, course]);
const [selectedLectureId, setSelectedLectureId] = useState<
string | undefined
>(lectureId || undefined);
@ -57,9 +75,9 @@ export function CourseDetailProvider({
},
{ enabled: Boolean(editId) }
);
useEffect(() => {
if (course) {
console.log("read");
read.mutateAsync({
data: {
visitorId: user?.id || null,
@ -85,6 +103,7 @@ export function CourseDetailProvider({
lectureIsLoading,
isHeaderVisible,
setIsHeaderVisible,
canEdit,
}}>
{children}
</CourseDetailContext.Provider>

View File

@ -10,7 +10,7 @@ import { useAuth } from "@web/src/providers/auth-provider";
import { useNavigate, useParams } from "react-router-dom";
import { UserMenu } from "@web/src/app/main/layout/UserMenu/UserMenu";
import { CourseDetailContext } from "../CourseDetailContext";
import { Department, RolePerms } from "@nice/common";
const { Header } = Layout;
@ -20,9 +20,8 @@ export function CourseDetailHeader() {
const { isAuthenticated, user, hasSomePermissions, hasEveryPermissions } =
useAuth();
const navigate = useNavigate();
const { course } = useContext(CourseDetailContext);
hasSomePermissions(RolePerms.MANAGE_ANY_POST, RolePerms.MANAGE_DOM_POST);
hasEveryPermissions(RolePerms.MANAGE_ANY_POST, RolePerms.MANAGE_DOM_POST);
const { course, canEdit } = useContext(CourseDetailContext);
return (
<Header className="select-none flex items-center justify-center bg-white shadow-md border-b border-gray-100 fixed w-full z-30">
<div className="w-full flex items-center justify-between h-full">
@ -52,7 +51,7 @@ export function CourseDetailHeader() {
onChange={(e) => setSearchValue(e.target.value)}
/>
</div>
{isAuthenticated && (
{canEdit && (
<>
<Button
onClick={() => {

View File

@ -9,9 +9,7 @@ import { CourseDetailHeader } from "./CourseDetailHeader/CourseDetailHeader";
export default function CourseDetailLayout() {
const {
course,
selectedLectureId,
lecture,
isLoading,
setSelectedLectureId,
} = useContext(CourseDetailContext);
@ -38,10 +36,7 @@ export default function CourseDetailLayout() {
}}
transition={{ type: "spring", stiffness: 300, damping: 30 }}
className="relative">
<CourseDetailDisplayArea
// course={course}
// isLoading={isLoading}
/>
<CourseDetailDisplayArea />
</motion.div>
{/* 课程大纲侧边栏 */}
<CourseSyllabus

View File

@ -63,16 +63,6 @@ export const routes: CustomRouteObject[] = [
path: "courses",
element: <CoursesPage></CoursesPage>,
},
{
path: "profiles",
},
// // 课程预览页面
// {
// path: "coursePreview/:id?",
// element: <CoursePreview></CoursePreview>,
// },
],
},
{
@ -103,12 +93,6 @@ export const routes: CustomRouteObject[] = [
</WithAuth>
),
},
// {
// path: "setting",
// element: (
// <CourseSettingForm></CourseSettingForm>
// ),
// },
],
},
{