add
This commit is contained in:
parent
f8659b90ca
commit
c9199a7709
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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={() => {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
// ),
|
||||
// },
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue