This commit is contained in:
ditiqi 2025-02-27 10:23:36 +08:00
parent 1fe33f9f6c
commit 96351ac9ac
9 changed files with 66 additions and 98 deletions

View File

@ -5,30 +5,18 @@ import { useMemo } from "react";
import CourseCard from "./CourseCard";
export function CoursesContainer() {
const { selectedTerms, searchCondition } = useMainContext();
const termFilters = useMemo(() => {
return Object.entries(selectedTerms)
.filter(([, terms]) => terms.length > 0)
.map(([, terms]) => terms);
}, [selectedTerms]);
const {searchCondition, termsCondition } = useMainContext();
return (
<>
<PostList
renderItem={(post) => <CourseCard course={post} edit={false}></CourseCard>}
renderItem={(post) => (
<CourseCard course={post} edit={false}></CourseCard>
)}
params={{
pageSize: 12,
where: {
type: PostType.COURSE,
AND: termFilters.map((termFilter) => ({
terms: {
some: {
id: {
in: termFilter, // 确保至少有一个 term.id 在当前 termFilter 中
},
},
},
})),
...termsCondition,
...searchCondition,
},
}}

View File

@ -43,7 +43,8 @@ export function MainHeader() {
onPressEnter={(e) => {
if (
!window.location.pathname.startsWith("/courses/") &&
!window.location.pathname.startsWith("my")
!window.location.pathname.startsWith("/my") &&
!window.location.pathname.startsWith("/path")
) {
navigate(`/courses/`);
window.scrollTo({

View File

@ -16,6 +16,7 @@ interface MainContextType {
setSearchValue?: React.Dispatch<React.SetStateAction<string>>;
setSelectedTerms?: React.Dispatch<React.SetStateAction<SelectedTerms>>;
searchCondition?: Prisma.PostWhereInput;
termsCondition?: Prisma.PostWhereInput;
}
const MainContext = createContext<MainContextType | null>(null);
@ -26,7 +27,27 @@ interface MainProviderProps {
export function MainProvider({ children }: MainProviderProps) {
const [searchValue, setSearchValue] = useState("");
const [selectedTerms, setSelectedTerms] = useState<SelectedTerms>({}); // 初始化状态
const termFilters = useMemo(() => {
return Object.entries(selectedTerms)
.filter(([, terms]) => terms.length > 0)
?.map(([, terms]) => terms);
}, [selectedTerms]);
const termsCondition: Prisma.PostWhereInput = useMemo(() => {
return termFilters && termFilters?.length > 0
? {
AND: termFilters.map((termFilter) => ({
terms: {
some: {
id: {
in: termFilter, // 确保至少有一个 term.id 在当前 termFilter 中
},
},
},
})),
}
: {};
}, [termFilters]);
const searchCondition: Prisma.PostWhereInput = useMemo(() => {
const containTextCondition: Prisma.StringNullableFilter = {
contains: searchValue,
@ -57,6 +78,7 @@ export function MainProvider({ children }: MainProviderProps) {
selectedTerms,
setSelectedTerms,
searchCondition,
termsCondition,
}}>
{children}
</MainContext.Provider>

View File

@ -20,7 +20,8 @@ export const NavigationMenu = () => {
return [
...baseItems,
{ key: "my-duty", path: "/my-duty", label: "我创建的" },
{ key: "my-learning", path: "/my-learning", label: "我学习的" },
{ key: "my-learning", path: "/my-learning", label: "我的课表" },
{ key: "my-path", path: "/my-path", label: "我的路径" },
];
}
}, [isAuthenticated]);
@ -31,6 +32,7 @@ export const NavigationMenu = () => {
<Menu
mode="horizontal"
className="border-none font-medium"
disabledOverflow={true}
selectedKeys={[selectedKey]}
onClick={({ key }) => {
const selectedItem = menuItems.find((item) => item.key === key);

View File

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

View File

@ -0,0 +1,29 @@
import PostList from "@web/src/components/models/course/list/PostList";
import { useAuth } from "@web/src/providers/auth-provider";
import CourseCard from "../../courses/components/CourseCard";
import { PostType } from "@nice/common";
import { useMainContext } from "../../layout/MainProvider";
export default function MyDutyPage() {
const { user } = useAuth();
const { searchCondition, termsCondition } = useMainContext();
return (
<>
<PostList
renderItem={(post) => (
<CourseCard edit course={post}></CourseCard>
)}
params={{
pageSize: 12,
where: {
type: PostType.COURSE,
authorId: user.id,
...termsCondition,
...searchCondition,
},
}}
cols={4}></PostList>
</>
);
}

View File

@ -1,44 +0,0 @@
import { api } from "@nice/client";
import { useMainContext } from "../../layout/MainProvider";
import TermParentSelector from "@web/src/components/models/term/term-parent-selector";
export default function PathFilter() {
const { data: taxonomies } = api.taxonomy.getAll.useQuery({});
const { selectedTerms, setSelectedTerms } = useMainContext();
const handleTermChange = (slug: string, selected: string[]) => {
setSelectedTerms({
...selectedTerms,
[slug]: selected, // 更新对应 slug 的选择
});
};
return (
<div className="bg-white p-6 rounded-lg shadow-sm space-y-6 h-full">
{taxonomies?.map((tax, index) => {
const items = Object.entries(selectedTerms).find(
([key, items]) => key === tax.slug
)?.[1];
return (
<div key={index}>
<h3 className="text-lg font-medium mb-4">
{tax?.name}
</h3>
<TermParentSelector
value={items}
slug = {tax?.slug}
className="w-70 max-h-[500px] overscroll-contain overflow-x-hidden"
onChange={(selected) =>
handleTermChange(
tax?.slug,
selected as string[]
)
}
taxonomyId={tax?.id}
></TermParentSelector>
</div>
);
})}
</div>
);
}

View File

@ -1,17 +1,9 @@
import PostList from "@web/src/components/models/course/list/PostList";
import { useMainContext } from "../../layout/MainProvider";
import { PostType, Prisma } from "@nice/common";
import { useMemo } from "react";
import PathCard from "./PathCard";
export function PathListContainer() {
const { searchValue, selectedTerms, searchCondition } = useMainContext();
const termFilters = useMemo(() => {
return Object.entries(selectedTerms)
.filter(([, terms]) => terms.length > 0)
.map(([, terms]) => terms);
}, [selectedTerms]);
const { searchCondition, termsCondition } = useMainContext();
return (
<>
<PostList
@ -20,15 +12,7 @@ export function PathListContainer() {
pageSize: 12,
where: {
type: PostType.PATH,
AND: termFilters.map((termFilter) => ({
terms: {
some: {
id: {
in: termFilter, // 确保至少有一个 term.id 在当前 termFilter 中
},
},
},
})),
...termsCondition,
...searchCondition,
},
}}
@ -36,5 +20,4 @@ export function PathListContainer() {
</>
);
}
export default PathListContainer;

View File

@ -1,5 +1,5 @@
import FilterSection from "../../courses/components/FilterSection";
import PathFilter from "../components/PathFilter";
import PathListContainer from "../components/PathListContainer";
export function PathListLayout() {
@ -9,7 +9,7 @@ export function PathListLayout() {
<div className=" flex">
<div className="w-1/6">
<FilterSection></FilterSection>
{/* <PathFilter></PathFilter> */}
</div>
<div className="w-5/6 p-4 ">
<PathListContainer></PathListContainer>