From 29340b8bb293f5ef150b9957fe580fcf495e93b3 Mon Sep 17 00:00:00 2001 From: linfeng <2819853134@qq.com> Date: Wed, 12 Mar 2025 08:23:33 +0800 Subject: [PATCH] lin --- apps/web/src/app/main/course/detail/page.tsx | 7 - .../components/couresPreviewTabmsg.tsx | 25 -- .../preview/components/courseCatalog.tsx | 11 - .../components/coursePreviewAllmsg.tsx | 73 ----- apps/web/src/app/main/course/preview/page.tsx | 81 ------ apps/web/src/app/main/course/preview/type.ts | 8 - .../courses/components/CoursesContainer.tsx | 25 -- apps/web/src/app/main/courses/page.tsx | 18 -- .../main/home/components/CategorySection.tsx | 107 ------- .../home/components/CategorySectionCard.tsx | 58 ---- .../main/home/components/CoursesSection.tsx | 112 -------- .../home/components/CoursesSectionTag.tsx | 24 -- .../components/FeaturedTeachersSection.tsx | 222 --------------- .../app/main/home/components/HeroSection.tsx | 164 ----------- .../app/main/home/components/LookForMore.tsx | 27 -- apps/web/src/app/main/home/page.tsx | 41 +-- .../main/layout/BasePost/BasePostLayout.tsx | 29 -- .../main/layout/BasePost/FilterSection.tsx | 46 ---- .../main/layout/BasePost/SearchModeRadio.tsx | 25 -- apps/web/src/app/main/layout/MainFooter.tsx | 76 ----- apps/web/src/app/main/layout/MainHeader.tsx | 149 +++------- apps/web/src/app/main/layout/MainLayout.tsx | 28 +- apps/web/src/app/main/layout/MainProvider.tsx | 109 -------- .../src/app/main/layout/NavigationMenu.tsx | 92 +++---- .../main/layout/UserMenu/UserEditModal.tsx | 27 -- .../src/app/main/layout/UserMenu/UserForm.tsx | 164 ----------- .../src/app/main/layout/UserMenu/UserMenu.tsx | 246 ----------------- .../web/src/app/main/layout/UserMenu/types.ts | 6 - .../components/MyDutyPathContainer.tsx | 26 -- apps/web/src/app/main/my-duty-path/page.tsx | 17 -- .../components/MyDutyListContainer.tsx | 27 -- apps/web/src/app/main/my-duty/page.tsx | 16 -- .../components/MyLearningListContainer.tsx | 31 --- apps/web/src/app/main/my-learning/page.tsx | 17 -- .../components/MyPathListContainer.tsx | 33 --- apps/web/src/app/main/my-path/page.tsx | 17 -- .../src/app/main/path/components/DeptInfo.tsx | 42 --- .../path/components/PathListContainer.tsx | 25 -- .../src/app/main/path/components/TermInfo.tsx | 47 ---- apps/web/src/app/main/path/editor/page.tsx | 12 - apps/web/src/app/main/path/page.tsx | 20 -- .../search/components/SearchContainer.tsx | 33 --- apps/web/src/app/main/search/page.tsx | 20 -- apps/web/src/app/main/self/courses/page.tsx | 7 - apps/web/src/app/main/self/profiles/page.tsx | 3 - apps/web/src/app/main/staffpage/page.tsx | 260 ++++++++++++++++++ apps/web/src/routes/index.tsx | 115 +------- 47 files changed, 362 insertions(+), 2406 deletions(-) delete mode 100755 apps/web/src/app/main/course/detail/page.tsx delete mode 100755 apps/web/src/app/main/course/preview/components/couresPreviewTabmsg.tsx delete mode 100755 apps/web/src/app/main/course/preview/components/courseCatalog.tsx delete mode 100755 apps/web/src/app/main/course/preview/components/coursePreviewAllmsg.tsx delete mode 100755 apps/web/src/app/main/course/preview/page.tsx delete mode 100755 apps/web/src/app/main/course/preview/type.ts delete mode 100755 apps/web/src/app/main/courses/components/CoursesContainer.tsx delete mode 100755 apps/web/src/app/main/courses/page.tsx delete mode 100755 apps/web/src/app/main/home/components/CategorySection.tsx delete mode 100755 apps/web/src/app/main/home/components/CategorySectionCard.tsx delete mode 100755 apps/web/src/app/main/home/components/CoursesSection.tsx delete mode 100755 apps/web/src/app/main/home/components/CoursesSectionTag.tsx delete mode 100755 apps/web/src/app/main/home/components/FeaturedTeachersSection.tsx delete mode 100755 apps/web/src/app/main/home/components/HeroSection.tsx delete mode 100755 apps/web/src/app/main/home/components/LookForMore.tsx delete mode 100755 apps/web/src/app/main/layout/BasePost/BasePostLayout.tsx delete mode 100755 apps/web/src/app/main/layout/BasePost/FilterSection.tsx delete mode 100755 apps/web/src/app/main/layout/BasePost/SearchModeRadio.tsx delete mode 100755 apps/web/src/app/main/layout/MainFooter.tsx mode change 100755 => 100644 apps/web/src/app/main/layout/MainHeader.tsx mode change 100755 => 100644 apps/web/src/app/main/layout/MainLayout.tsx delete mode 100755 apps/web/src/app/main/layout/MainProvider.tsx mode change 100755 => 100644 apps/web/src/app/main/layout/NavigationMenu.tsx delete mode 100755 apps/web/src/app/main/layout/UserMenu/UserEditModal.tsx delete mode 100755 apps/web/src/app/main/layout/UserMenu/UserForm.tsx delete mode 100755 apps/web/src/app/main/layout/UserMenu/UserMenu.tsx delete mode 100755 apps/web/src/app/main/layout/UserMenu/types.ts delete mode 100755 apps/web/src/app/main/my-duty-path/components/MyDutyPathContainer.tsx delete mode 100755 apps/web/src/app/main/my-duty-path/page.tsx delete mode 100755 apps/web/src/app/main/my-duty/components/MyDutyListContainer.tsx delete mode 100755 apps/web/src/app/main/my-duty/page.tsx delete mode 100755 apps/web/src/app/main/my-learning/components/MyLearningListContainer.tsx delete mode 100755 apps/web/src/app/main/my-learning/page.tsx delete mode 100755 apps/web/src/app/main/my-path/components/MyPathListContainer.tsx delete mode 100755 apps/web/src/app/main/my-path/page.tsx delete mode 100755 apps/web/src/app/main/path/components/DeptInfo.tsx delete mode 100755 apps/web/src/app/main/path/components/PathListContainer.tsx delete mode 100755 apps/web/src/app/main/path/components/TermInfo.tsx delete mode 100755 apps/web/src/app/main/path/editor/page.tsx delete mode 100755 apps/web/src/app/main/path/page.tsx delete mode 100755 apps/web/src/app/main/search/components/SearchContainer.tsx delete mode 100755 apps/web/src/app/main/search/page.tsx delete mode 100755 apps/web/src/app/main/self/courses/page.tsx delete mode 100755 apps/web/src/app/main/self/profiles/page.tsx create mode 100644 apps/web/src/app/main/staffpage/page.tsx diff --git a/apps/web/src/app/main/course/detail/page.tsx b/apps/web/src/app/main/course/detail/page.tsx deleted file mode 100755 index 82dd7ae..0000000 --- a/apps/web/src/app/main/course/detail/page.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import CourseDetail from "@web/src/components/models/course/detail/CourseDetail"; -import { useParams } from "react-router-dom"; - -export function CourseDetailPage() { - const { id, lectureId } = useParams(); - return ; -} diff --git a/apps/web/src/app/main/course/preview/components/couresPreviewTabmsg.tsx b/apps/web/src/app/main/course/preview/components/couresPreviewTabmsg.tsx deleted file mode 100755 index 8f32fce..0000000 --- a/apps/web/src/app/main/course/preview/components/couresPreviewTabmsg.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { Checkbox, List } from 'antd'; -import React from 'react'; - -export function CoursePreviewTabmsg({data}){ - - - const renderItem = (item) => ( - - - - ); - - return( -
- -
- ) -} \ No newline at end of file diff --git a/apps/web/src/app/main/course/preview/components/courseCatalog.tsx b/apps/web/src/app/main/course/preview/components/courseCatalog.tsx deleted file mode 100755 index b13e87d..0000000 --- a/apps/web/src/app/main/course/preview/components/courseCatalog.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import type { MenuProps } from 'antd'; -import { Menu } from 'antd'; - -type MenuItem = Required['items'][number]; - -export function CourseCatalog(){ - return ( - <> - - ) -} \ No newline at end of file diff --git a/apps/web/src/app/main/course/preview/components/coursePreviewAllmsg.tsx b/apps/web/src/app/main/course/preview/components/coursePreviewAllmsg.tsx deleted file mode 100755 index 73ed1f9..0000000 --- a/apps/web/src/app/main/course/preview/components/coursePreviewAllmsg.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import { useEffect } from "react"; -import { CoursePreviewMsg } from "@web/src/app/main/course/preview/type.ts"; -import { Button, Tabs, Image, Skeleton } from "antd"; -import type { TabsProps } from "antd"; -import { PlayCircleOutlined } from "@ant-design/icons"; -export function CoursePreviewAllmsg({ - previewMsg, - items, - isLoading, -}: { - previewMsg?: CoursePreviewMsg; - items: TabsProps["items"]; - isLoading: boolean; -}) { - useEffect(() => { - console.log(previewMsg); - }); - const TapOnChange = (key: string) => { - console.log(key); - }; - return ( -
-
-
- example -
- -
-
-
- {isLoading ? ( - - ) : ( - <> - - {previewMsg.Title} - - - {previewMsg.SubTitle} - - - {previewMsg.Description} - - - )} - - -
-
-
- -
-
- ); -} diff --git a/apps/web/src/app/main/course/preview/page.tsx b/apps/web/src/app/main/course/preview/page.tsx deleted file mode 100755 index 367c21a..0000000 --- a/apps/web/src/app/main/course/preview/page.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import { Skeleton, type TabsProps } from 'antd'; -import { CoursePreviewAllmsg } from "./components/coursePreviewAllmsg"; -import { CoursePreviewTabmsg } from "./components/couresPreviewTabmsg"; -import { CoursePreviewMsg } from "./type"; -import { api } from '@nice/client' -import { useNavigate, useParams } from 'react-router-dom'; -import { useEffect, useState } from 'react'; -import { courseDetailSelect, CourseDto } from '@nice/common'; - -export function CoursePreview(){ - const { id } = useParams() - const { data:course,isLoading:courseIsLoading}:{data:CourseDto,isLoading:boolean}= api.post.findFirst.useQuery({ - where:{ - id - }, - select:courseDetailSelect - }) - // course.sections[0].lectures[0] - // `/course/${course.id}/detail/${Lecture.id}` - useEffect(() => { - if(!courseIsLoading){ - setPreviewMsg({ - videoPreview: course?.meta?.thumbnail, - Title: course?.title, - SubTitle:course?.subTitle, - Description:course?.content, - ToCourseUrl:`/course/${id}`, - isLoading:courseIsLoading - }) - } - - },[courseIsLoading]) - const [previewMsg,setPreviewMsg] = useState({ - videoPreview: '', - Title: '', - SubTitle:'', - Description:'', - ToCourseUrl:'', - isLoading:courseIsLoading - }) - const tapData = [ - { - title: '掌握R语言的基本概念语法', - description: '学生将学习R语言和RStudio的基本知识', - }, - { - title: '掌握R语言的基本概念语法', - description: '学生将学习R语言的变量、数据类型、循环和条件语句等', - }, - { - title: '掌握R语言的数据导入管理', - description: '学生将学会如何将数据导入R环境,并且使用各种类型的数据', - }, - { - title: '掌握R语言的基本数据清洗', - description: '学生将学会使用R语言进行数据清洗、整理和管理', - }, - { - title: '掌握R语言的基本数据统计', - description: '学生将学会使用R语言进行基本的数据统计', - }, - { - title: '掌握R语言的基本绘图功能', - description: '学生将学会使用R语言基本的绘图功能和ggplot2的应用', - }, - ]; - const isLoading = false - const items: TabsProps['items'] = [ - { - key: '1', - label: '课程学习目标', - children: isLoading ? : , - } - ]; - - return( -
- -
- ) -} \ No newline at end of file diff --git a/apps/web/src/app/main/course/preview/type.ts b/apps/web/src/app/main/course/preview/type.ts deleted file mode 100755 index fe3a2fd..0000000 --- a/apps/web/src/app/main/course/preview/type.ts +++ /dev/null @@ -1,8 +0,0 @@ -export interface CoursePreviewMsg { - videoPreview: string; - Title: string; - SubTitle: string; - Description: string; - ToCourseUrl: string; - isLoading: boolean; -} diff --git a/apps/web/src/app/main/courses/components/CoursesContainer.tsx b/apps/web/src/app/main/courses/components/CoursesContainer.tsx deleted file mode 100755 index 72b9499..0000000 --- a/apps/web/src/app/main/courses/components/CoursesContainer.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { useMainContext } from "../../layout/MainProvider"; -import { PostType, Prisma } from "@nice/common"; -import PostList from "@web/src/components/models/course/list/PostList"; -import CourseCard from "@web/src/components/models/post/SubPost/CourseCard"; - -export function CoursesContainer() { - const { searchCondition, termsCondition } = useMainContext(); - return ( - <> - } - params={{ - pageSize: 12, - where: { - type: PostType.COURSE, - ...termsCondition, - ...searchCondition, - }, - }} - cols={4}> - - ); -} - -export default CoursesContainer; diff --git a/apps/web/src/app/main/courses/page.tsx b/apps/web/src/app/main/courses/page.tsx deleted file mode 100755 index 79eda89..0000000 --- a/apps/web/src/app/main/courses/page.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import BasePostLayout from "../layout/BasePost/BasePostLayout"; -import CoursesContainer from "./components/CoursesContainer"; -import { useEffect } from "react"; -import { useMainContext } from "../layout/MainProvider"; -import { PostType } from "@nice/common"; -export default function CoursesPage() { - const { setSearchMode } = useMainContext(); - useEffect(() => { - setSearchMode(PostType.COURSE); - }, [setSearchMode]); - return ( - <> - - - - - ); -} diff --git a/apps/web/src/app/main/home/components/CategorySection.tsx b/apps/web/src/app/main/home/components/CategorySection.tsx deleted file mode 100755 index 7bddcf2..0000000 --- a/apps/web/src/app/main/home/components/CategorySection.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import React, { useState, useCallback, useEffect, useMemo } from "react"; -import { Typography, Skeleton } from "antd"; -import { stringToColor, TaxonomySlug, TermDto } from "@nice/common"; -import { api, useTrainSituation } from "@nice/client"; -import LookForMore from "./LookForMore"; -import CategorySectionCard from "./CategorySectionCard"; -import { useNavigate } from "react-router-dom"; -import { useMainContext } from "../../layout/MainProvider"; -import { useAuth } from "@web/src/providers/auth-provider"; - -const { Title, Text } = Typography; -const CategorySection = () => { - const [hoveredIndex, setHoveredIndex] = useState(null); - const { selectedTerms, setSelectedTerms } = useMainContext(); - const { - data: courseCategoriesData, - isLoading, - }: { data: TermDto[]; isLoading: boolean } = api.term.findMany.useQuery({ - where: { - taxonomy: { - slug: TaxonomySlug.CATEGORY, - }, - parentId: null, - }, - take: 8, - }); - const navigate = useNavigate(); - - const handleMouseEnter = useCallback((index: number) => { - setHoveredIndex(index); - }, []); - - const handleMouseLeave = useCallback(() => { - setHoveredIndex(null); - }, []); - - const handleMouseClick = useCallback((categoryId: string) => { - setSelectedTerms({ - ...selectedTerms, - [TaxonomySlug.CATEGORY]: [categoryId], - }); - navigate("/courses"); - window.scrollTo({ top: 0, behavior: "smooth" }); - }, []); - - - const {user} = useAuth() - const {create} = useTrainSituation() - useEffect(() => { - if (user?.id) { - create.mutate({ - data: { - //staffId: user.id, // 确保类型匹配 - mustTrainTime: "1", - alreadyTrainTime: "1", - //trainContentId: "cm83w52dr00ff3jc8ep4uf4a4", - staff: { connect: { id: user.id } }, - trainContent: { connect: { id: "cm847lcc805ne123v81l5h13e" } } - } - }); - console.log("create score time") - } - }, []); - - return ( -
-
-
- - 探索课程分类 - - - 选择你感兴趣的方向,开启学习之旅 - -
-
- {isLoading ? ( - - ) : ( - courseCategoriesData?.filter(c=>!c.deletedAt)?.map((category, index) => { - const categoryColor = stringToColor(category.name); - const isHovered = hoveredIndex === index; - - return ( - - ); - }) - )} -
- -
-
- ); -}; - -export default CategorySection; diff --git a/apps/web/src/app/main/home/components/CategorySectionCard.tsx b/apps/web/src/app/main/home/components/CategorySectionCard.tsx deleted file mode 100755 index e3e1273..0000000 --- a/apps/web/src/app/main/home/components/CategorySectionCard.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import { useNavigate } from "react-router-dom"; -import { Typography } from "antd"; -export default function CategorySectionCard({handleMouseClick, index,handleMouseEnter,handleMouseLeave,category,categoryColor,isHovered,}) { - const navigate = useNavigate() - const { Title, Text } = Typography; - return ( -
handleMouseEnter(index)} - onMouseLeave={handleMouseLeave} - role="button" - tabIndex={0} - aria-label={`查看${category.name}课程类别`} - onClick={()=>{ - handleMouseClick(category.id) - }} - > -
-
-
-
-
-
- - {category.name} - -
-
- 了解更多 - - → - -
-
-
- ) -} \ No newline at end of file diff --git a/apps/web/src/app/main/home/components/CoursesSection.tsx b/apps/web/src/app/main/home/components/CoursesSection.tsx deleted file mode 100755 index bd7e18d..0000000 --- a/apps/web/src/app/main/home/components/CoursesSection.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import React, { useState, useMemo, ReactNode } from "react"; -import { Typography, Skeleton } from "antd"; -import { TaxonomySlug, TermDto } from "@nice/common"; -import { api } from "@nice/client"; -import { CoursesSectionTag } from "./CoursesSectionTag"; -import LookForMore from "./LookForMore"; -import PostList from "@web/src/components/models/course/list/PostList"; -interface GetTaxonomyProps { - categories: string[]; - isLoading: boolean; -} -function useGetTaxonomy({ type }): GetTaxonomyProps { - const { data, isLoading }: { data: TermDto[]; isLoading: boolean } = - api.term.findMany.useQuery({ - where: { - taxonomy: { - slug: type, - }, - parentId: null, - }, - take: 11, // 只取前10个 - }); - const categories = useMemo(() => { - const allCategories = isLoading - ? [] - : data?.filter(c=>!c.deletedAt)?.map((course) => course.name); - return [...Array.from(new Set(allCategories))]; - }, [data]); - return { categories, isLoading }; -} -const { Title, Text } = Typography; -interface CoursesSectionProps { - title: string; - description: string; - initialVisibleCoursesCount?: number; - postType:string; - render?:(post)=>ReactNode; - to:string -} -const CoursesSection: React.FC = ({ - title, - description, - initialVisibleCoursesCount = 8, - postType, - render, - to -}) => { - const [selectedCategory, setSelectedCategory] = useState("全部"); - const gateGory: GetTaxonomyProps = useGetTaxonomy({ - type: TaxonomySlug.CATEGORY, - }); - return ( -
-
-
-
- - {title} - - - {description} - -
-
-
- {gateGory.isLoading ? ( - - ) : ( - <> - {["全部", ...gateGory.categories].map( - (category, idx) => ( - - ) - )} - - )} -
- render(post)} - params={{ - page: 1, - pageSize: initialVisibleCoursesCount, - where: { - terms: !(selectedCategory === "全部") - ? { - some: { - name: selectedCategory, - }, - } - : {}, - type: postType - }, - }} - showPagination={false} - cols={4}> - -
-
- ); -}; -export default CoursesSection; diff --git a/apps/web/src/app/main/home/components/CoursesSectionTag.tsx b/apps/web/src/app/main/home/components/CoursesSectionTag.tsx deleted file mode 100755 index c03d718..0000000 --- a/apps/web/src/app/main/home/components/CoursesSectionTag.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { Tag } from "antd"; - -export function CoursesSectionTag({category, selectedCategory, setSelectedCategory}) { - return ( - <> - { - setSelectedCategory(category); - }} - className={`px-6 py-2 text-base cursor-pointer rounded-full transition-all duration-300 ${selectedCategory === category - ? "bg-blue-600 text-white shadow-lg" - : "bg-white text-gray-600 hover:bg-gray-100" - }`}> - {category} - - - ) -} diff --git a/apps/web/src/app/main/home/components/FeaturedTeachersSection.tsx b/apps/web/src/app/main/home/components/FeaturedTeachersSection.tsx deleted file mode 100755 index c880b07..0000000 --- a/apps/web/src/app/main/home/components/FeaturedTeachersSection.tsx +++ /dev/null @@ -1,222 +0,0 @@ -import React, { useRef } from 'react'; -import { Typography, Tag, Carousel } from 'antd'; -import { StarFilled, UserOutlined, ReadOutlined, LeftOutlined, RightOutlined } from '@ant-design/icons'; - -const { Title, Text } = Typography; - -interface Teacher { - name: string; - title: string; - avatar: string; - courses: number; - students: number; - rating: number; - description: string; -} - -const featuredTeachers: Teacher[] = [ - { - name: '张教授', - title: '资深前端开发专家', - avatar: '/images/teacher1.jpg', - courses: 12, - students: 25000, - rating: 4.9, - description: '前 BAT 高级工程师,10年+开发经验' - }, - { - name: '李教授', - title: '算法与数据结构专家', - avatar: '/images/teacher2.jpg', - courses: 8, - students: 18000, - rating: 4.8, - description: '计算机博士,专注算法教育8年' - }, - { - name: '王博士', - title: '人工智能研究员', - avatar: '/images/teacher3.jpg', - courses: 15, - students: 30000, - rating: 4.95, - description: '人工智能领域专家,曾主导多个大型AI项目' - }, - { - name: '陈教授', - title: '云计算架构师', - avatar: '/images/teacher4.jpg', - courses: 10, - students: 22000, - rating: 4.85, - description: '知名云服务提供商技术总监,丰富的实战经验' - }, - { - name: '郑老师', - title: '移动开发专家', - avatar: '/images/teacher5.jpg', - courses: 14, - students: 28000, - rating: 4.88, - description: '资深移动端开发者,著名互联网公司技术专家' - } -]; - -const generateGradientColors = (name: string) => { - // 优化的哈希函数 - const hash = name.split('').reduce((acc, char, index) => { - return char.charCodeAt(0) + ((acc << 5) - acc) + index; - }, 0); - - // 定义蓝色色相范围(210-240) - const blueHueStart = 210; - const blueHueRange = 30; - - // 基础蓝色色相 - 将哈希值映射到蓝色范围内 - const baseHue = blueHueStart + Math.abs(hash % blueHueRange); - - // 生成第二个蓝色色相,保持在蓝色范围内 - let secondHue = baseHue + 15; // 在基础色相的基础上略微偏移 - if (secondHue > blueHueStart + blueHueRange) { - secondHue -= blueHueRange; - } - - // 基于输入字符串的特征调整饱和度和亮度 - const nameLength = name.length; - const saturation = Math.max(65, Math.min(85, 75 + (nameLength % 10))); // 65-85%范围 - const lightness = Math.max(45, Math.min(65, 55 + (hash % 10))); // 45-65%范围 - - // 为第二个颜色稍微调整饱和度和亮度,创造层次感 - const saturation2 = Math.max(60, saturation - 5); - const lightness2 = Math.min(70, lightness + 5); - - return { - from: `hsl(${Math.round(baseHue)}, ${Math.round(saturation)}%, ${Math.round(lightness)}%)`, - to: `hsl(${Math.round(secondHue)}, ${Math.round(saturation2)}%, ${Math.round(lightness2)}%)` - }; -}; - -const FeaturedTeachersSection: React.FC = () => { - const carouselRef = useRef(null); - - const settings = { - dots: true, - infinite: true, - speed: 500, - slidesToShow: 4, - slidesToScroll: 1, - autoplay: true, - autoplaySpeed: 5000, - responsive: [ - { - breakpoint: 1024, - settings: { - slidesToShow: 2, - slidesToScroll: 1 - } - }, - { - breakpoint: 640, - settings: { - slidesToShow: 1, - slidesToScroll: 1 - } - } - ] - }; - - const TeacherCard = ({ teacher }: { teacher: Teacher }) => { - const gradientColors = generateGradientColors(teacher.name); - return ( -
-
-
- {teacher.name} -
-
-
- - {teacher.name} - - - {teacher.title} - -
- - - {teacher.description} - - -
-
-
- - {teacher.courses} -
- 课程 -
-
-
- - {(teacher.students / 1000).toFixed(1)}k -
- 学员 -
-
-
- - {teacher.rating} -
- 评分 -
-
-
-
-
- ); - }; - - return ( -
-
-
- - 优秀讲师 - - - 业界专家实战分享,传授独家经验 - -
- -
- - {featuredTeachers.map((teacher, index) => ( - - ))} - - - - -
-
-
- ); -}; - -export default FeaturedTeachersSection; diff --git a/apps/web/src/app/main/home/components/HeroSection.tsx b/apps/web/src/app/main/home/components/HeroSection.tsx deleted file mode 100755 index 07b775e..0000000 --- a/apps/web/src/app/main/home/components/HeroSection.tsx +++ /dev/null @@ -1,164 +0,0 @@ -import React, { - useRef, - useCallback, - useEffect, - useMemo, - useState, -} from "react"; -import { Carousel, Typography } from "antd"; -import { - TeamOutlined, - BookOutlined, - StarOutlined, - LeftOutlined, - RightOutlined, - EyeOutlined, -} from "@ant-design/icons"; -import type { CarouselRef } from "antd/es/carousel"; -import { api, useAppConfig } from "@nice/client"; -import { useNavigate } from "react-router-dom"; - -interface PlatformStat { - icon: React.ReactNode; - value: number; - label: string; -} - -const HeroSection = () => { - const carouselRef = useRef(null); - const { statistics, slides, slideLinks = [] } = useAppConfig(); - const [countStatistics, setCountStatistics] = useState(4); - const navigator = useNavigate() - const platformStats: PlatformStat[] = useMemo(() => { - return [ - { - icon: , - value: statistics.staffs, - label: "注册学员", - }, - { - icon: , - value: statistics.courses, - label: "精品课程", - }, - { - icon: , - value: statistics.lectures, - label: "课程章节", - }, - { - icon: , - value: statistics.reads, - label: "播放次数", - }, - ]; - }, [statistics]); - const handlePrev = useCallback(() => { - carouselRef.current?.prev(); - }, []); - - const handleNext = useCallback(() => { - carouselRef.current?.next(); - }, []); - - const countNonZeroValues = (statistics: Record): number => { - return Object.values(statistics).filter((value) => value !== 0).length; - }; - - useEffect(() => { - const count = countNonZeroValues(statistics); - console.log(count); - setCountStatistics(count); - }, [statistics]); - - - - - - - - return ( -
-
- - {Array.isArray(slides) ? ( - slides.map((item, index) => ( -
{ - if(slideLinks?.[index])window.open(slideLinks?.[index],"_blank") - }} - > -
- {/*
*/} -
- - {/* Content Container */} -
-
- )) - ) : ( -
- )} - - - {/* Navigation Buttons */} - - -
- - {/* Stats Container */} - {countStatistics > 1 && ( -
-
- {platformStats.map((stat, index) => { - return stat.value ? ( -
-
- {stat.icon} -
-
- {stat.value} -
-
- {stat.label} -
-
- ) : null; - })} -
-
- )} -
- ); -}; - -export default HeroSection; diff --git a/apps/web/src/app/main/home/components/LookForMore.tsx b/apps/web/src/app/main/home/components/LookForMore.tsx deleted file mode 100755 index 2bd74cc..0000000 --- a/apps/web/src/app/main/home/components/LookForMore.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { ArrowRightOutlined } from "@ant-design/icons"; -import { Button } from "antd"; -import { useNavigate } from "react-router-dom"; - -export default function LookForMore({to}:{to:string}) { - const navigate = useNavigate(); - return ( - <> -
-
-
- -
-
- - ) - -} diff --git a/apps/web/src/app/main/home/page.tsx b/apps/web/src/app/main/home/page.tsx index 4482872..729e69d 100755 --- a/apps/web/src/app/main/home/page.tsx +++ b/apps/web/src/app/main/home/page.tsx @@ -1,34 +1,9 @@ -import HeroSection from "./components/HeroSection"; -import CategorySection from "./components/CategorySection"; -import CoursesSection from "./components/CoursesSection"; -import { PostType } from "@nice/common"; -import PathCard from "@web/src/components/models/post/SubPost/PathCard"; -import CourseCard from "@web/src/components/models/post/SubPost/CourseCard"; +import React from "react" - -const HomePage = () => { - - return ( -
- - } - to={"path"} - /> - } - to={"/courses"} - /> - - -
- ); -}; - -export default HomePage; +export default function HomePage() { + return ( +
+ 首页 +
+ ) +} \ No newline at end of file diff --git a/apps/web/src/app/main/layout/BasePost/BasePostLayout.tsx b/apps/web/src/app/main/layout/BasePost/BasePostLayout.tsx deleted file mode 100755 index 09c7852..0000000 --- a/apps/web/src/app/main/layout/BasePost/BasePostLayout.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { ReactNode, useEffect } from "react"; -import FilterSection from "./FilterSection"; -import { useMainContext } from "../MainProvider"; - -export function BasePostLayout({ - children, - showSearchMode = false, -}: { - children: ReactNode; - showSearchMode?: boolean; -}) { - const { setShowSearchMode } = useMainContext(); - useEffect(() => { - setShowSearchMode(showSearchMode); - }, [showSearchMode]); - return ( - <> -
-
-
- -
-
{children}
-
-
- - ); -} -export default BasePostLayout; diff --git a/apps/web/src/app/main/layout/BasePost/FilterSection.tsx b/apps/web/src/app/main/layout/BasePost/FilterSection.tsx deleted file mode 100755 index 084878c..0000000 --- a/apps/web/src/app/main/layout/BasePost/FilterSection.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { Divider } from "antd"; -import { api } from "@nice/client"; -import { useMainContext } from "../MainProvider"; -import TermParentSelector from "@web/src/components/models/term/term-parent-selector"; -import SearchModeRadio from "./SearchModeRadio"; -export default function FilterSection() { - const { data: taxonomies } = api.taxonomy.getAll.useQuery({}); - const { selectedTerms, setSelectedTerms, showSearchMode } = - useMainContext(); - const handleTermChange = (slug: string, selected: string[]) => { - setSelectedTerms({ - ...selectedTerms, - [slug]: selected, // 更新对应 slug 的选择 - }); - }; - return ( -
- {showSearchMode && } - {taxonomies?.map((tax, index) => { - const items = Object.entries(selectedTerms).find( - ([key, items]) => key === tax.slug - )?.[1]; - return ( -
-

- {tax?.name} - {/* {JSON.stringify(items)} */} -

- - handleTermChange( - tax?.slug, - selected as string[] - ) - } - taxonomyId={tax?.id}> - -
- ); - })} -
- ); -} diff --git a/apps/web/src/app/main/layout/BasePost/SearchModeRadio.tsx b/apps/web/src/app/main/layout/BasePost/SearchModeRadio.tsx deleted file mode 100755 index 507e94f..0000000 --- a/apps/web/src/app/main/layout/BasePost/SearchModeRadio.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { useMainContext } from "../MainProvider"; -import { Radio, Space, Typography } from "antd"; -import { PostType } from "@nice/common"; // Assuming PostType is defined in this path - -export default function SearchModeRadio() { - const { searchMode, setSearchMode } = useMainContext(); - - const handleModeChange = (e) => { - setSearchMode(e.target.value); - }; - - return ( - -

只搜索

- - 视频课程 - 思维导图 - 所有资源 - -
- ); -} diff --git a/apps/web/src/app/main/layout/MainFooter.tsx b/apps/web/src/app/main/layout/MainFooter.tsx deleted file mode 100755 index eb4ef75..0000000 --- a/apps/web/src/app/main/layout/MainFooter.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import { - CloudOutlined, - FileSearchOutlined, - HomeOutlined, - MailOutlined, - PhoneOutlined, -} from "@ant-design/icons"; - -export function MainFooter() { - return ( -
-
-
- {/* 开发组织信息 */} -
-

- 软件与数据小组 -

-

- 提供技术支持 -

-
- - {/* 联系方式 */} -
-
- - - 628532 - -
-
- - - ruanjian1@tx3l.nb.kj - -
-
- - {/* 系统链接 */} -
- -
-
- - {/* 版权信息 */} -
-

- © {new Date().getFullYear()} 南天烽火. All rights - reserved. -

-
-
-
- ); -} diff --git a/apps/web/src/app/main/layout/MainHeader.tsx b/apps/web/src/app/main/layout/MainHeader.tsx old mode 100755 new mode 100644 index 91b1771..fee3ad5 --- a/apps/web/src/app/main/layout/MainHeader.tsx +++ b/apps/web/src/app/main/layout/MainHeader.tsx @@ -1,107 +1,46 @@ -import { Input, Button } from "antd"; -import { PlusOutlined, SearchOutlined, UserOutlined } from "@ant-design/icons"; -import { useAuth } from "@web/src/providers/auth-provider"; -import { useNavigate, useParams } from "react-router-dom"; -import { UserMenu } from "./UserMenu/UserMenu"; -import { NavigationMenu } from "./NavigationMenu"; -import { useMainContext } from "./MainProvider"; -import { env } from "@web/src/env"; -export function MainHeader() { - const { isAuthenticated, user } = useAuth(); - const { id } = useParams(); - const navigate = useNavigate(); - const { searchValue, setSearchValue } = useMainContext(); +import { Layout, Menu, Avatar, Button } from 'antd'; +import { UserOutlined, SettingOutlined } from '@ant-design/icons'; +import { useNavigate, Outlet, useLocation } from 'react-router-dom'; +import NavigationMenu from './NavigationMenu'; - return ( -
- {/* 左侧区域 - 设置为不收缩 */} -
- -
navigate("/")} - className="text-2xl font-bold bg-gradient-to-r from-primary-600 via-primary-500 to-primary-400 bg-clip-text text-transparent hover:scale-105 transition-transform cursor-pointer whitespace-nowrap"> - {env.APP_NAME} -
- -
+const { Sider, Content } = Layout; - {/* 右侧区域 - 可以灵活收缩 */} -
-
- - } - placeholder="搜索课程" - className="w-full md:w-96 rounded-full" - value={searchValue} - onClick={(e) => { - if ( - !window.location.pathname.startsWith("/search") - ) { - navigate(`/search`); - window.scrollTo({ - top: 0, - behavior: "smooth", - }); - } - }} - onChange={(e) => setSearchValue(e.target.value)} - onPressEnter={(e) => { - if ( - !window.location.pathname.startsWith("/search") - ) { - navigate(`/search`); - window.scrollTo({ - top: 0, - behavior: "smooth", - }); - } - }} - /> - {isAuthenticated && ( - <> - - - )} - {isAuthenticated && ( - - )} - {isAuthenticated ? ( - - ) : ( - - )} -
-
-
- ); -} +export default function MainHeader() { + const navigate = useNavigate(); + + + + return ( + + {/* 左侧导航栏 */} + + {/* 用户头像区域 */} +
+
+ } + className=" transition-all duration-300" + /> +
+
+ +
+ {/* 新增可滚动内容区域 */} + + + + + +
+ ); +} \ No newline at end of file diff --git a/apps/web/src/app/main/layout/MainLayout.tsx b/apps/web/src/app/main/layout/MainLayout.tsx old mode 100755 new mode 100644 index fa3bad7..6957b9a --- a/apps/web/src/app/main/layout/MainLayout.tsx +++ b/apps/web/src/app/main/layout/MainLayout.tsx @@ -1,21 +1,11 @@ -import { Layout } from "antd"; import { Outlet } from "react-router-dom"; -import { MainHeader } from "./MainHeader"; -import { MainFooter } from "./MainFooter"; -import { MainProvider } from "./MainProvider"; +import MainHeader from "./MainHeader"; +import { Content } from "antd/es/layout/layout"; +export default function MainLayout() { + return ( + <> + + -const { Content } = Layout; - -export function MainLayout() { - return ( - -
- - - - - -
-
- ); -} + ) +} \ No newline at end of file diff --git a/apps/web/src/app/main/layout/MainProvider.tsx b/apps/web/src/app/main/layout/MainProvider.tsx deleted file mode 100755 index 1d0396c..0000000 --- a/apps/web/src/app/main/layout/MainProvider.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import { PostType, Prisma } from "@nice/common"; -import React, { - createContext, - ReactNode, - useContext, - useMemo, - useState, -} from "react"; -import { useDebounce } from "use-debounce"; -interface SelectedTerms { - [key: string]: string[]; // 每个 slug 对应一个 string 数组 -} - -interface MainContextType { - searchValue?: string; - selectedTerms?: SelectedTerms; - setSearchValue?: React.Dispatch>; - setSelectedTerms?: React.Dispatch>; - searchCondition?: Prisma.PostWhereInput; - termsCondition?: Prisma.PostWhereInput; - searchMode?: PostType.COURSE | PostType.PATH | "both"; - setSearchMode?: React.Dispatch< - React.SetStateAction - >; - showSearchMode?: boolean; - setShowSearchMode?: React.Dispatch>; -} - -const MainContext = createContext(null); -interface MainProviderProps { - children: ReactNode; -} - -export function MainProvider({ children }: MainProviderProps) { - const [searchMode, setSearchMode] = useState< - PostType.COURSE | PostType.PATH | "both" - >("both"); - const [showSearchMode, setShowSearchMode] = useState(false); - const [searchValue, setSearchValue] = useState(""); - const [debouncedValue] = useDebounce(searchValue, 500); - const [selectedTerms, setSelectedTerms] = useState({}); // 初始化状态 - 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: debouncedValue, - mode: "insensitive" as Prisma.QueryMode, // 使用类型断言 - }; - return debouncedValue - ? { - OR: [ - { title: containTextCondition }, - { subTitle: containTextCondition }, - { content: containTextCondition }, - { - terms: { - some: { - name: containTextCondition, - }, - }, - }, - ], - } - : {}; - }, [debouncedValue]); - return ( - - {children} - - ); -} -export const useMainContext = () => { - const context = useContext(MainContext); - if (!context) { - throw new Error("useMainContext must be used within MainProvider"); - } - return context; -}; diff --git a/apps/web/src/app/main/layout/NavigationMenu.tsx b/apps/web/src/app/main/layout/NavigationMenu.tsx old mode 100755 new mode 100644 index 1f50140..126b0fa --- a/apps/web/src/app/main/layout/NavigationMenu.tsx +++ b/apps/web/src/app/main/layout/NavigationMenu.tsx @@ -1,59 +1,37 @@ -import { useAuth } from "@web/src/providers/auth-provider"; import { Menu } from "antd"; -import { useMemo } from "react"; -import { useNavigate, useLocation } from "react-router-dom"; +import { useNavigate } from "react-router-dom"; -export const NavigationMenu = () => { - const navigate = useNavigate(); - const { isAuthenticated } = useAuth(); - const { pathname } = useLocation(); - - const menuItems = useMemo(() => { - const baseItems = [ - { key: "home", path: "/", label: "首页" }, - { key: "path", path: "/path", label: "全部思维导图" }, - { key: "courses", path: "/courses", label: "所有课程" }, - ]; - - if (!isAuthenticated) { - return baseItems; - } else { - return [ - ...baseItems, - { key: "my-duty", path: "/my-duty", label: "我创建的课程" }, - { key: "my-learning", path: "/my-learning", label: "我学习的课程" }, - { key: "my-duty-path", path: "/my-duty-path", label: "我创建的思维导图" }, - { key: "my-path", path: "/my-path", label: "我学习的思维导图" }, - ]; - } - }, [isAuthenticated]); - - const selectedKey = useMemo(() => { - const normalizePath = (path: string): string => path.replace(/\/$/, ""); - return pathname === '/' ? "home" : menuItems.find((item) => normalizePath(pathname) === item.path)?.key || ""; - }, [pathname]); - - return ( - { - const selectedItem = menuItems.find((item) => item.key === key); - if (selectedItem) navigate(selectedItem.path); - window.scrollTo({ - top: 0, - behavior: "smooth", - }); - }}> - {menuItems.map(({ key, label }) => ( - - {label} - - ))} - - ); -}; +export default function NavigationMenu() { + const navigate = useNavigate(); + // 导航菜单项配置 + const menuItems = [ + { key: 'home', label: '首页', path: '/' }, + { key: 'staff', label: '人员总览', path: '/staff' }, + { key: 'day', label: '日统计', path: '/day' }, + { key: 'month', label: '月统计', path: '/month' }, + { key: 'year', label: '年度统计', path: '/year' } + ]; + return ( + <> + {/* 导航菜单 */} + + {menuItems.map((item) => ( + navigate(item.path)} + > +
+ {item.label} +
+
+ ))} +
+ + ); +} \ No newline at end of file diff --git a/apps/web/src/app/main/layout/UserMenu/UserEditModal.tsx b/apps/web/src/app/main/layout/UserMenu/UserEditModal.tsx deleted file mode 100755 index ed30812..0000000 --- a/apps/web/src/app/main/layout/UserMenu/UserEditModal.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { Button, Drawer, Modal } from "antd"; -import React, { useContext, useEffect, useState } from "react"; - -import { UserEditorContext } from "./UserMenu"; -import UserForm from "./UserForm"; - -export default function UserEditModal() { - const { formLoading, modalOpen, setModalOpen, form } = - useContext(UserEditorContext); - const handleOk = () => { - form.submit(); - }; - return ( - { - setModalOpen(false); - }} - title={"编辑个人信息"}> - - - ); -} diff --git a/apps/web/src/app/main/layout/UserMenu/UserForm.tsx b/apps/web/src/app/main/layout/UserMenu/UserForm.tsx deleted file mode 100755 index edef377..0000000 --- a/apps/web/src/app/main/layout/UserMenu/UserForm.tsx +++ /dev/null @@ -1,164 +0,0 @@ -import { Button, Form, Input, Spin, Switch, message } from "antd"; -import { useContext, useEffect } from "react"; -import { useStaff } from "@nice/client"; -import DepartmentSelect from "@web/src/components/models/department/department-select"; -import { api } from "@nice/client"; - -import { useAuth } from "@web/src/providers/auth-provider"; -import AvatarUploader from "@web/src/components/common/uploader/AvatarUploader"; -import { StaffDto } from "@nice/common"; -import { UserEditorContext } from "./UserMenu"; -import toast from "react-hot-toast"; -export default function StaffForm() { - const { user } = useAuth(); - const { create, update } = useStaff(); // Ensure you have these methods in your hooks - const { formLoading, modalOpen, setModalOpen, domainId, setDomainId, form, setFormLoading, } = useContext(UserEditorContext); - const { - data, - isLoading, - }: { - data: StaffDto; - isLoading: boolean; - } = api.staff.findFirst.useQuery( - { where: { id: user?.id } }, - { enabled: !!user?.id } - ); - const { isRoot } = useAuth(); - async function handleFinish(values: any) { - const { - username, - showname, - deptId, - domainId, - password, - phoneNumber, - officerId, - enabled, - avatar, - photoUrl, - email, - rank, - office, - } = values; - setFormLoading(true); - try { - if (data && user?.id) { - await update.mutateAsync({ - where: { id: data.id }, - data: { - username, - deptId, - showname, - domainId, - password, - phoneNumber, - officerId, - enabled, - avatar, - }, - }); - } - toast.success("提交成功"); - setModalOpen(false); - } catch (err: any) { - toast.error(err.message); - } finally { - setFormLoading(false); - } - } - useEffect(() => { - form.resetFields(); - console.log('cc', data); - - if (data) { - form.setFieldValue("username", data.username); - form.setFieldValue("showname", data.showname); - form.setFieldValue("domainId", data.domainId); - form.setFieldValue("deptId", data.deptId); - form.setFieldValue("officerId", data.officerId); - form.setFieldValue("phoneNumber", data.phoneNumber); - form.setFieldValue("enabled", data.enabled); - form.setFieldValue("avatar", data.avatar); - } - }, [data]); - // useEffect(() => { - // if (!data && domainId) { - // form.setFieldValue("domainId", domainId); - // form.setFieldValue("deptId", domainId); - // } - // }, [domainId, data as any]); - return ( -
- {isLoading && ( -
- -
- )} -
-
-
- - - -
- -
- - - - - { - setDomainId(value as string); - }} - domain={true} - /> - - - - - - - - -
-
-
-
- ); -} diff --git a/apps/web/src/app/main/layout/UserMenu/UserMenu.tsx b/apps/web/src/app/main/layout/UserMenu/UserMenu.tsx deleted file mode 100755 index fc63758..0000000 --- a/apps/web/src/app/main/layout/UserMenu/UserMenu.tsx +++ /dev/null @@ -1,246 +0,0 @@ -import { useClickOutside } from "@web/src/hooks/useClickOutside"; -import { useAuth } from "@web/src/providers/auth-provider"; -import { motion, AnimatePresence } from "framer-motion"; -import React, { - useState, - useRef, - useCallback, - useMemo, - createContext, -} from "react"; -import { Avatar } from "@web/src/components/common/element/Avatar"; -import { - UserOutlined, - SettingOutlined, - LogoutOutlined, -} from "@ant-design/icons"; -import { FormInstance, Spin } from "antd"; -import { useNavigate } from "react-router-dom"; -import { MenuItemType } from "./types"; -import { RolePerms } from "@nice/common"; -import { useForm } from "antd/es/form/Form"; -import UserEditModal from "./UserEditModal"; -const menuVariants = { - hidden: { opacity: 0, scale: 0.95, y: -10 }, - visible: { - opacity: 1, - scale: 1, - y: 0, - transition: { - type: "spring", - stiffness: 300, - damping: 30, - }, - }, - exit: { - opacity: 0, - scale: 0.95, - y: -10, - transition: { - duration: 0.2, - }, - }, -}; - -export const UserEditorContext = createContext<{ - domainId: string; - setDomainId: React.Dispatch>; - modalOpen: boolean; - setModalOpen: React.Dispatch>; - form: FormInstance; - formLoading: boolean; - setFormLoading: React.Dispatch>; -}>({ - modalOpen: false, - domainId: undefined, - setDomainId: undefined, - setModalOpen: undefined, - form: undefined, - formLoading: undefined, - setFormLoading: undefined, -}); - -export function UserMenu() { - const [form] = useForm(); - const [formLoading, setFormLoading] = useState(); - const [showMenu, setShowMenu] = useState(false); - const menuRef = useRef(null); - const { user, logout, isLoading, hasSomePermissions } = useAuth(); - const navigate = useNavigate(); - useClickOutside(menuRef, () => setShowMenu(false)); - const [modalOpen, setModalOpen] = useState(false); - const [domainId, setDomainId] = useState(); - const toggleMenu = useCallback(() => { - setShowMenu((prev) => !prev); - }, []); - const canManageAnyStaff = useMemo(() => { - return hasSomePermissions(RolePerms.MANAGE_ANY_STAFF); - }, [user]); - const menuItems: MenuItemType[] = useMemo( - () => - [ - { - icon: , - label: "个人信息", - action: () => { - setModalOpen(true); - }, - }, - - canManageAnyStaff && { - icon: , - label: "设置", - action: () => { - navigate("/admin/staff"); - }, - }, - - { - icon: , - label: "注销", - action: () => logout(), - }, - ].filter(Boolean), - [logout] - ); - - const handleMenuItemClick = useCallback((action: () => void) => { - action(); - setShowMenu(false); - }, []); - - if (isLoading) { - return ( -
- -
- ); - } - - return ( - -
- - {/* Avatar 容器,相对定位 */} -
- - {/* 小绿点 */} -
-
- - - {showMenu && ( - - {/* User Profile Section */} -
-
- -
- - {user?.showname || user?.username} - - - - 在线 - -
-
-
- - {/* Menu Items */} -
- {menuItems.map((item, index) => ( - - ))} -
-
- )} -
-
- -
- ); -} diff --git a/apps/web/src/app/main/layout/UserMenu/types.ts b/apps/web/src/app/main/layout/UserMenu/types.ts deleted file mode 100755 index dfe4b00..0000000 --- a/apps/web/src/app/main/layout/UserMenu/types.ts +++ /dev/null @@ -1,6 +0,0 @@ -import React, { ReactNode } from "react"; -export interface MenuItemType { - icon: ReactNode; - label: string; - action: () => void; -} diff --git a/apps/web/src/app/main/my-duty-path/components/MyDutyPathContainer.tsx b/apps/web/src/app/main/my-duty-path/components/MyDutyPathContainer.tsx deleted file mode 100755 index 4b7f273..0000000 --- a/apps/web/src/app/main/my-duty-path/components/MyDutyPathContainer.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import PostList from "@web/src/components/models/course/list/PostList"; -import { useAuth } from "@web/src/providers/auth-provider"; -import { useMainContext } from "../../layout/MainProvider"; -import { PostType } from "@nice/common"; -import PathCard from "@web/src/components/models/post/SubPost/PathCard"; - -export default function MyDutyPathContainer() { - const { user } = useAuth(); - const { searchCondition, termsCondition } = useMainContext(); - return ( - <> - } - params={{ - pageSize: 12, - where: { - type: PostType.PATH, - authorId: user?.id, - ...termsCondition, - ...searchCondition, - }, - }} - cols={4}> - - ); -} diff --git a/apps/web/src/app/main/my-duty-path/page.tsx b/apps/web/src/app/main/my-duty-path/page.tsx deleted file mode 100755 index 24d7931..0000000 --- a/apps/web/src/app/main/my-duty-path/page.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { useEffect } from "react"; -import BasePostLayout from "../layout/BasePost/BasePostLayout"; -import { useMainContext } from "../layout/MainProvider"; -import { PostType } from "@nice/common"; -import MyDutyPathContainer from "./components/MyDutyPathContainer"; - -export default function MyDutyPathPage() { - const { setSearchMode } = useMainContext(); - useEffect(() => { - setSearchMode(PostType.PATH); - }, [setSearchMode]); - return ( - - - - ); -} diff --git a/apps/web/src/app/main/my-duty/components/MyDutyListContainer.tsx b/apps/web/src/app/main/my-duty/components/MyDutyListContainer.tsx deleted file mode 100755 index 727e828..0000000 --- a/apps/web/src/app/main/my-duty/components/MyDutyListContainer.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import PostList from "@web/src/components/models/course/list/PostList"; -import { useAuth } from "@web/src/providers/auth-provider"; -import { PostType } from "@nice/common"; -import { useMainContext } from "../../layout/MainProvider"; -import PostCard from "@web/src/components/models/post/PostCard"; -import CourseCard from "@web/src/components/models/post/SubPost/CourseCard"; - -export default function MyDutyListContainer() { - const { user } = useAuth(); - const { searchCondition, termsCondition } = useMainContext(); - return ( - <> - } - params={{ - pageSize: 12, - where: { - type: PostType.COURSE, - authorId: user.id, - ...termsCondition, - ...searchCondition, - }, - }} - cols={4}> - - ); -} diff --git a/apps/web/src/app/main/my-duty/page.tsx b/apps/web/src/app/main/my-duty/page.tsx deleted file mode 100755 index fff4c91..0000000 --- a/apps/web/src/app/main/my-duty/page.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import BasePostLayout from "../layout/BasePost/BasePostLayout"; -import MyDutyListContainer from "./components/MyDutyListContainer"; -import { useEffect } from "react"; -import { useMainContext } from "../layout/MainProvider"; -import { PostType } from "@nice/common"; -export default function MyDutyPage() { - const { setSearchMode } = useMainContext(); - useEffect(() => { - setSearchMode(PostType.COURSE); - }, [setSearchMode]); - return ( - - - - ); -} diff --git a/apps/web/src/app/main/my-learning/components/MyLearningListContainer.tsx b/apps/web/src/app/main/my-learning/components/MyLearningListContainer.tsx deleted file mode 100755 index be281ae..0000000 --- a/apps/web/src/app/main/my-learning/components/MyLearningListContainer.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import PostList from "@web/src/components/models/course/list/PostList"; -import { useAuth } from "@web/src/providers/auth-provider"; -import { useMainContext } from "../../layout/MainProvider"; -import { PostType } from "@nice/common"; -import PostCard from "@web/src/components/models/post/PostCard"; -import CourseCard from "@web/src/components/models/post/SubPost/CourseCard"; - -export default function MyLearningListContainer() { - const { user } = useAuth(); - const { searchCondition, termsCondition } = useMainContext(); - return ( - <> - } - params={{ - pageSize: 12, - where: { - type: PostType.COURSE, - students: { - some: { - id: user?.id, - }, - }, - ...termsCondition, - ...searchCondition, - }, - }} - cols={4}> - - ); -} diff --git a/apps/web/src/app/main/my-learning/page.tsx b/apps/web/src/app/main/my-learning/page.tsx deleted file mode 100755 index cee2c94..0000000 --- a/apps/web/src/app/main/my-learning/page.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { useEffect } from "react"; -import BasePostLayout from "../layout/BasePost/BasePostLayout"; -import { useMainContext } from "../layout/MainProvider"; -import MyLearningListContainer from "./components/MyLearningListContainer"; -import { PostType } from "@nice/common"; - -export default function MyLearningPage() { - const { setSearchMode } = useMainContext(); - useEffect(() => { - setSearchMode(PostType.COURSE); - }, [setSearchMode]); - return ( - - - - ); -} diff --git a/apps/web/src/app/main/my-path/components/MyPathListContainer.tsx b/apps/web/src/app/main/my-path/components/MyPathListContainer.tsx deleted file mode 100755 index b7dfd33..0000000 --- a/apps/web/src/app/main/my-path/components/MyPathListContainer.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import PostList from "@web/src/components/models/course/list/PostList"; -import { useAuth } from "@web/src/providers/auth-provider"; - -import { PostType } from "@nice/common"; -import { useMainContext } from "../../layout/MainProvider"; -import PostCard from "@web/src/components/models/post/PostCard"; -import PathCard from "@web/src/components/models/post/SubPost/PathCard"; - -export default function MyPathListContainer() { - const { user } = useAuth(); - const { searchCondition, termsCondition } = useMainContext(); - return ( - <> - } - params={{ - pageSize: 12, - where: { - type: PostType.PATH, - students: { - some: { - id: user?.id, - }, - }, - - ...termsCondition, - ...searchCondition, - }, - }} - cols={4}> - - ); -} diff --git a/apps/web/src/app/main/my-path/page.tsx b/apps/web/src/app/main/my-path/page.tsx deleted file mode 100755 index 81f7298..0000000 --- a/apps/web/src/app/main/my-path/page.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { useEffect } from "react"; -import BasePostLayout from "../layout/BasePost/BasePostLayout"; -import { useMainContext } from "../layout/MainProvider"; -import MyPathListContainer from "./components/MyPathListContainer"; -import { PostType } from "@nice/common"; - -export default function MyPathPage() { - const { setSearchMode } = useMainContext(); - useEffect(() => { - setSearchMode(PostType.PATH); - }, [setSearchMode]); - return ( - - - - ); -} diff --git a/apps/web/src/app/main/path/components/DeptInfo.tsx b/apps/web/src/app/main/path/components/DeptInfo.tsx deleted file mode 100755 index ed6510b..0000000 --- a/apps/web/src/app/main/path/components/DeptInfo.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { BookOutlined, EyeOutlined, TeamOutlined } from "@ant-design/icons"; -import { Typography } from "antd"; -import { PostDto } from "@nice/common"; - -const { Title, Text } = Typography; -const DeptInfo = ({ post }: { post: PostDto }) => { - return ( -
-
- - {post?.depts && post?.depts?.length > 0 ? ( - - {post?.depts?.length > 1 - ? `${post.depts[0].name}等` - : post?.depts?.[0]?.name} - - ) : ( - - 未设置单位 - - )} -
- {post && ( -
- - 浏览量 - - {`${post?.views || 0}`} - - {post?.studentIds && post?.studentIds?.length > 0 && ( - - - {`${post?.studentIds?.length || 0}`} - - )} -
- )} -
- ); -}; - -export default DeptInfo; diff --git a/apps/web/src/app/main/path/components/PathListContainer.tsx b/apps/web/src/app/main/path/components/PathListContainer.tsx deleted file mode 100755 index 4e7ade6..0000000 --- a/apps/web/src/app/main/path/components/PathListContainer.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import PostList from "@web/src/components/models/course/list/PostList"; -import { useMainContext } from "../../layout/MainProvider"; -import { PostType, Prisma } from "@nice/common"; -import PostCard from "@web/src/components/models/post/PostCard"; -import PathCard from "@web/src/components/models/post/SubPost/PathCard"; - -export function PathListContainer() { - const { searchCondition, termsCondition } = useMainContext(); - return ( - <> - } - params={{ - pageSize: 12, - where: { - type: PostType.PATH, - ...termsCondition, - ...searchCondition, - }, - }} - cols={4}> - - ); -} -export default PathListContainer; diff --git a/apps/web/src/app/main/path/components/TermInfo.tsx b/apps/web/src/app/main/path/components/TermInfo.tsx deleted file mode 100755 index 21fed6d..0000000 --- a/apps/web/src/app/main/path/components/TermInfo.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { Tag } from "antd"; -import { PostDto, TaxonomySlug, TermDto } from "@nice/common"; - -const TermInfo = ({ terms = [] }: { terms?: TermDto[] }) => { - return ( -
- {terms && terms?.length > 0 ? ( -
- {terms - ?.sort((a, b) => - String(a?.taxonomy?.id || "").localeCompare( - String(b?.taxonomy?.id || "") - ) - ) - ?.map((term: any) => { - return ( - - {term.name} - - ); - })} -
- ) : ( -
- - {"未设置分类"} - -
- )} -
- ); -}; - -export default TermInfo; diff --git a/apps/web/src/app/main/path/editor/page.tsx b/apps/web/src/app/main/path/editor/page.tsx deleted file mode 100755 index 2c0b8b0..0000000 --- a/apps/web/src/app/main/path/editor/page.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import MindEditor from "@web/src/components/common/editor/MindEditor"; -import { PostDetailProvider } from "@web/src/components/models/course/detail/PostDetailContext"; -import { useParams } from "react-router-dom"; - -export default function PathEditorPage() { - const { id } = useParams(); - return ( - - ; - - ); -} diff --git a/apps/web/src/app/main/path/page.tsx b/apps/web/src/app/main/path/page.tsx deleted file mode 100755 index 542689b..0000000 --- a/apps/web/src/app/main/path/page.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { useEffect } from "react"; -import BasePostLayout from "../layout/BasePost/BasePostLayout"; -import { useMainContext } from "../layout/MainProvider"; -import PathListContainer from "./components/PathListContainer"; -import { PostType } from "@nice/common"; -import { PostDetailProvider } from "@web/src/components/models/course/detail/PostDetailContext"; -import { useParams } from "react-router-dom"; - -export default function PathPage() { - const { setSearchMode } = useMainContext(); - useEffect(() => { - setSearchMode(PostType.PATH); - }, [setSearchMode]); - const { id } = useParams(); - return ( - - - - ); -} diff --git a/apps/web/src/app/main/search/components/SearchContainer.tsx b/apps/web/src/app/main/search/components/SearchContainer.tsx deleted file mode 100755 index 292d9b5..0000000 --- a/apps/web/src/app/main/search/components/SearchContainer.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import PostList from "@web/src/components/models/course/list/PostList"; -import { useMainContext } from "../../layout/MainProvider"; -import PostCard from "@web/src/components/models/post/PostCard"; -import { PostType } from "@nice/common"; -import CourseCard from "@web/src/components/models/post/SubPost/CourseCard"; -import PathCard from "@web/src/components/models/post/SubPost/PathCard"; -const POST_TYPE_COMPONENTS = { - [PostType.COURSE]: CourseCard, - [PostType.PATH]: PathCard, -}; -export default function SearchListContainer() { - const { searchCondition, termsCondition, searchMode } = useMainContext(); - - return ( - <> - { - const Component = - POST_TYPE_COMPONENTS[post.type] || PostCard; - return ; - }} - params={{ - pageSize: 12, - where: { - type: searchMode === "both" ? undefined : searchMode, - ...termsCondition, - ...searchCondition, - }, - }} - cols={4}> - - ); -} diff --git a/apps/web/src/app/main/search/page.tsx b/apps/web/src/app/main/search/page.tsx deleted file mode 100755 index cfb6153..0000000 --- a/apps/web/src/app/main/search/page.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { useEffect } from "react"; -import BasePostLayout from "../layout/BasePost/BasePostLayout"; -import SearchListContainer from "./components/SearchContainer"; -import { useMainContext } from "../layout/MainProvider"; - -export default function SearchPage() { - const { setShowSearchMode, setSearchValue } = useMainContext(); - useEffect(() => { - setShowSearchMode(true); - return () => { - setShowSearchMode(false); - setSearchValue(""); - }; - }, [setShowSearchMode]); - return ( - - - - ); -} diff --git a/apps/web/src/app/main/self/courses/page.tsx b/apps/web/src/app/main/self/courses/page.tsx deleted file mode 100755 index 36b358f..0000000 --- a/apps/web/src/app/main/self/courses/page.tsx +++ /dev/null @@ -1,7 +0,0 @@ -export default function MyCoursePage() { - return ( -
- My Course Page -
- ) -} \ No newline at end of file diff --git a/apps/web/src/app/main/self/profiles/page.tsx b/apps/web/src/app/main/self/profiles/page.tsx deleted file mode 100755 index 70ac75b..0000000 --- a/apps/web/src/app/main/self/profiles/page.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function ProfilesPage() { - return <>Profiles -} \ No newline at end of file diff --git a/apps/web/src/app/main/staffpage/page.tsx b/apps/web/src/app/main/staffpage/page.tsx new file mode 100644 index 0000000..7170da7 --- /dev/null +++ b/apps/web/src/app/main/staffpage/page.tsx @@ -0,0 +1,260 @@ +import { MagnifyingGlassIcon } from "@heroicons/react/24/outline"; +import { api, useStaff } from "@nice/client"; +import { Button, Form, Input, Modal, Select, Table } from "antd"; +import { StaffDto } from "@nice/common"; +import { useEffect, useState } from "react"; +import toast from "react-hot-toast"; + +export default function StaffMessage() { + const initialValues = { + username: "", + deptId: "", + absent: "是", + }; + const { create, update } = useStaff(); + const [searchName, setSearchName] = useState(""); + const { data: staffs, isLoading } = api.staff.findMany.useQuery({ + where: { + username: { + contains: searchName + } + } + }); + console.log(staffs); + const [form] = Form.useForm(); + const [visible, setVisible] = useState(false); + const [editingRecord, setEditingRecord] = useState(null); + const colnums = [ + { + title: "姓名", + dataIndex: "username", + key: "username", + }, + { + title: "部门", + dataIndex: "deptId", + key: "deptId", + }, + { + title: "在位", + dataIndex: "absent", + key: "absent", + render: (_, record) => ( + + ) + }, + { + title: "操作", + key: "action", + render: (_, record) => ( + + ), + } + ]; + + const handleNew = () => { + form.setFieldsValue(initialValues); + setVisible(true); + } + + useEffect(() => { + if (editingRecord) { + form.setFieldsValue(editingRecord); + console.log(editingRecord); + } + }, [editingRecord]); + + const handleEdit = (record) => { + setEditingRecord(record); + form.setFieldsValue(editingRecord); + setVisible(true); + }; + + const handleOk = async () => { + const values = await form.getFieldsValue(); + const orderValue = values.order ? parseFloat(values.order) : null; + console.log(values.username); + try { + if (editingRecord && editingRecord.id) { + // console.log(editingRecord); + const result = await update.mutateAsync( + { + where: { + id: editingRecord.id, + }, + data: { + username: values.username, + deptId: values.deptId, + order: orderValue, + updatedAt: new Date() + } + } + ); + // console.log(result); + } else { + await create.mutateAsync( + { + data: { + username: values.username, + deptId: values.deptId, + order: orderValue, + createdAt: new Date(), + showname: values.username, + } + } + ); + } + toast.success("保存成功"); + setVisible(false); + } catch (error) { + toast.error("保存失败"); + throw error; + } + }; + + const handleCancel = () => { + setVisible(false); + }; + + const handleSearch = (e) => { + setSearchName(e.target.value); + }; + + return ( +
+
+
{/* 修改为flex布局 */} +
{/* 添加flex容器 */} + {/* 头部区域保持不变... */} +
+
XX 公司人员信息表
+
+ + +
+ +
+ {/* 表格容器增加flex布局 */} + {isLoading ? ( +
+
+
+ ) : ( +
+ ({ + className: "hover:bg-gray-800/50 transition-colors even:bg-gray-800/50 hover:shadow-lg hover:shadow-blue-500/20", + })} + > + + + {colnums.map((column) => ( + + ))} + + + {/* 移除原有text-gray-300 */} + {staffs?.map((record) => ( + + {colnums.map((column) => ( + + ))} + + ))} + +
+ {column.title} +
+ {column.render?.(record[column.dataIndex], record) || record[column.dataIndex]} +
+
+ )} + + {/* 模态框样式更新 */} + + + + + + + + + + +
+
+ +
+ ); +} + diff --git a/apps/web/src/routes/index.tsx b/apps/web/src/routes/index.tsx index e48165d..85a7d84 100755 --- a/apps/web/src/routes/index.tsx +++ b/apps/web/src/routes/index.tsx @@ -6,25 +6,10 @@ import { useParams, } from "react-router-dom"; import ErrorPage from "../app/error"; -import WithAuth from "../components/utils/with-auth"; import LoginPage from "../app/login"; import HomePage from "../app/main/home/page"; -import { CourseDetailPage } from "../app/main/course/detail/page"; -import { CourseBasicForm } from "../components/models/course/editor/form/CourseBasicForm"; -import CourseContentForm from "../components/models/course/editor/form/CourseContentForm/CourseContentForm"; -import CourseEditorLayout from "../components/models/course/editor/layout/CourseEditorLayout"; -import { MainLayout } from "../app/main/layout/MainLayout"; -import CoursesPage from "../app/main/courses/page"; -import PathPage from "../app/main/path/page"; -import { adminRoute } from "./admin-route"; -import PathEditorPage from "../app/main/path/editor/page"; - -import { CoursePreview } from "../app/main/course/preview/page"; -import MyLearningPage from "../app/main/my-learning/page"; -import MyDutyPage from "../app/main/my-duty/page"; -import MyPathPage from "../app/main/my-path/page"; -import SearchPage from "../app/main/search/page"; -import MyDutyPathPage from "../app/main/my-duty-path/page"; +import StaffMessage from "../app/main/staffpage/page"; +import MainLayout from "../app/main/layout/MainLayout"; interface CustomIndexRouteObject extends IndexRouteObject { name?: string; breadcrumb?: string; @@ -60,103 +45,15 @@ export const routes: CustomRouteObject[] = [ children: [ { index: true, - element: , + element: , }, { - path: "path", - children: [ - { - index: true, - element: , - }, - { - path: "editor/:id?", - element: ( - - ), - }, - ], - }, - { - path: "courses", - element: , - }, - { - path: "my-path", - element: ( - - - - ), - }, - { - path: "my-duty-path", - element: ( - - - - ), - }, - { - path: "my-duty", - element: ( - - - - ), - }, - { - path: "my-learning", - element: ( - - - - ), - }, - { - path: "search", - element: , - }, - { - path: "course/:id?/detail/:lectureId?", // 使用 ? 表示 id 参数是可选的 - element: , + path: "/staff", + element: , }, ], }, - - { - path: "course", - children: [ - { - path: ":id?/editor", - element: ( - - - - ), - children: [ - { - index: true, - element: ( - - - - ), - }, - - { - path: "content", - element: ( - - - - ), - }, - ], - }, - ], - }, - adminRoute, + ], }, {