Merge branch 'main' of http://113.45.157.195:3003/insiinc/re-mooc
This commit is contained in:
commit
5c943711a4
|
@ -24,8 +24,7 @@ export default function CourseCard({ course }: CourseCardProps) {
|
||||||
onClick={() => handleClick(course)}
|
onClick={() => handleClick(course)}
|
||||||
key={course.id}
|
key={course.id}
|
||||||
hoverable
|
hoverable
|
||||||
className="group overflow-hidden rounded-2xl border border-gray-200 bg-white
|
className="group overflow-hidden rounded-2xl border border-gray-200 bg-white shadow-xl hover:shadow-2xl transition-all duration-300 transform hover:-translate-y-2"
|
||||||
shadow-xl hover:shadow-2xl transition-all duration-300 transform hover:-translate-y-2"
|
|
||||||
cover={
|
cover={
|
||||||
<div className="relative h-56 bg-gradient-to-br from-gray-900 to-gray-800 overflow-hidden">
|
<div className="relative h-56 bg-gradient-to-br from-gray-900 to-gray-800 overflow-hidden">
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -43,7 +43,7 @@ const CategorySection = () => {
|
||||||
return (
|
return (
|
||||||
<section className="py-8 relative overflow-hidden">
|
<section className="py-8 relative overflow-hidden">
|
||||||
<div className="max-w-screen-2xl mx-auto px-4 relative">
|
<div className="max-w-screen-2xl mx-auto px-4 relative">
|
||||||
<div className="text-center mb-24">
|
<div className="text-center mb-12">
|
||||||
<Title
|
<Title
|
||||||
level={2}
|
level={2}
|
||||||
className="font-bold text-5xl mb-6 bg-gradient-to-r from-gray-900 via-gray-700 to-gray-800 bg-clip-text text-transparent motion-safe:animate-gradient-x">
|
className="font-bold text-5xl mb-6 bg-gradient-to-r from-gray-900 via-gray-700 to-gray-800 bg-clip-text text-transparent motion-safe:animate-gradient-x">
|
||||||
|
|
|
@ -16,8 +16,9 @@ function useGetTaxonomy({ type }): GetTaxonomyProps {
|
||||||
taxonomy: {
|
taxonomy: {
|
||||||
slug: type,
|
slug: type,
|
||||||
},
|
},
|
||||||
|
parentId : null
|
||||||
},
|
},
|
||||||
take: 10, // 只取前10个
|
take: 11, // 只取前10个
|
||||||
});
|
});
|
||||||
const categories = useMemo(() => {
|
const categories = useMemo(() => {
|
||||||
const allCategories = isLoading
|
const allCategories = isLoading
|
||||||
|
@ -43,16 +44,16 @@ const CoursesSection: React.FC<CoursesSectionProps> = ({
|
||||||
type: TaxonomySlug.CATEGORY,
|
type: TaxonomySlug.CATEGORY,
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<section className="relative py-20 overflow-hidden bg-gradient-to-b from-gray-50 to-white">
|
<section className="relative py-16 overflow-hidden bg-gray-200">
|
||||||
|
<div className="absolute inset-0 bg-white max-w-screen-2xl mx-auto px-6"></div>
|
||||||
<div className="max-w-screen-2xl mx-auto px-6 relative">
|
<div className="max-w-screen-2xl mx-auto px-6 relative">
|
||||||
<div className="flex justify-between items-end mb-16">
|
<div className="flex justify-between items-end mb-16 ">
|
||||||
<div>
|
<div>
|
||||||
<Title
|
<Title
|
||||||
level={2}
|
level={2}
|
||||||
className="font-bold text-5xl mb-6 bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent">
|
className="font-bold text-5xl mb-6 bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent">
|
||||||
{title}
|
{title}
|
||||||
</Title>
|
</Title>
|
||||||
|
|
||||||
<Text
|
<Text
|
||||||
type="secondary"
|
type="secondary"
|
||||||
className="text-xl font-light text-gray-600">
|
className="text-xl font-light text-gray-600">
|
||||||
|
|
|
@ -30,7 +30,7 @@ interface PlatformStat {
|
||||||
const HeroSection = () => {
|
const HeroSection = () => {
|
||||||
const carouselRef = useRef<CarouselRef>(null);
|
const carouselRef = useRef<CarouselRef>(null);
|
||||||
const { statistics, slides } = useAppConfig();
|
const { statistics, slides } = useAppConfig();
|
||||||
const [countStatistics, setCountStatistics] = useState<number>(0)
|
const [countStatistics, setCountStatistics] = useState<number>(4)
|
||||||
const platformStats: PlatformStat[] = useMemo(() => {
|
const platformStats: PlatformStat[] = useMemo(() => {
|
||||||
return [
|
return [
|
||||||
{ icon: <TeamOutlined />, value: statistics.staffs, label: "注册学员" },
|
{ icon: <TeamOutlined />, value: statistics.staffs, label: "注册学员" },
|
||||||
|
@ -111,7 +111,7 @@ const HeroSection = () => {
|
||||||
{
|
{
|
||||||
countStatistics > 1 && (
|
countStatistics > 1 && (
|
||||||
<div className="absolute -bottom-20 left-1/2 -translate-x-1/2 w-3/5 max-w-6xl px-4">
|
<div className="absolute -bottom-20 left-1/2 -translate-x-1/2 w-3/5 max-w-6xl px-4">
|
||||||
<div className={`rounded-2xl grid grid-cols-${countStatistics} md:grid-cols-${countStatistics} gap-4 md:gap-8 p-6 md:p-8 bg-white border shadow-xl hover:shadow-2xl transition-shadow duration-500 will-change-[transform,box-shadow]`}>
|
<div className={`rounded-2xl grid grid-cols-${countStatistics} lg:grid-cols-${countStatistics} md:grid-cols-${countStatistics} gap-4 md:gap-8 p-6 md:p-8 bg-white border shadow-xl hover:shadow-2xl transition-shadow duration-500 will-change-[transform,box-shadow]`}>
|
||||||
{platformStats.map((stat, index) => {
|
{platformStats.map((stat, index) => {
|
||||||
return stat.value
|
return stat.value
|
||||||
? (<div
|
? (<div
|
||||||
|
|
|
@ -11,7 +11,7 @@ export function MainLayout() {
|
||||||
<MainProvider>
|
<MainProvider>
|
||||||
<Layout className="min-h-screen bg-gray-100">
|
<Layout className="min-h-screen bg-gray-100">
|
||||||
<MainHeader />
|
<MainHeader />
|
||||||
<Content className="mt-16 bg-gray-50 ">
|
<Content className="mt-16 bg-gray-200 ">
|
||||||
<Outlet />
|
<Outlet />
|
||||||
</Content>
|
</Content>
|
||||||
<MainFooter />
|
<MainFooter />
|
||||||
|
|
|
@ -50,10 +50,13 @@ export function CourseDetailProvider({
|
||||||
(api.post as any).findFirst.useQuery(
|
(api.post as any).findFirst.useQuery(
|
||||||
{
|
{
|
||||||
where: { id: editId },
|
where: { id: editId },
|
||||||
include: {
|
// include: {
|
||||||
// sections: { include: { lectures: true } },
|
// // sections: { include: { lectures: true } },
|
||||||
enrollments: true,
|
// enrollments: true,
|
||||||
},
|
// terms:true
|
||||||
|
// },
|
||||||
|
|
||||||
|
select:courseDetailSelect
|
||||||
},
|
},
|
||||||
{ enabled: Boolean(editId) }
|
{ enabled: Boolean(editId) }
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
import { Course } from "@nice/common";
|
import { Course, TaxonomySlug } from "@nice/common";
|
||||||
import React, { useContext, useMemo } from "react";
|
import React, { useContext, useMemo } from "react";
|
||||||
import { Image, Typography, Skeleton } from "antd"; // 引入 antd 组件
|
import { Image, Typography, Skeleton, Tag } from "antd"; // 引入 antd 组件
|
||||||
import { CourseDetailContext } from "./CourseDetailContext";
|
import { CourseDetailContext } from "./CourseDetailContext";
|
||||||
import {
|
import {
|
||||||
CalendarOutlined,
|
CalendarOutlined,
|
||||||
|
EditTwoTone,
|
||||||
EyeOutlined,
|
EyeOutlined,
|
||||||
PlayCircleOutlined,
|
PlayCircleOutlined,
|
||||||
|
ReloadOutlined,
|
||||||
} from "@ant-design/icons";
|
} from "@ant-design/icons";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
|
|
||||||
export const CourseDetailDescription: React.FC = () => {
|
export const CourseDetailDescription: React.FC = () => {
|
||||||
const { course, isLoading, selectedLectureId, setSelectedLectureId } =
|
const { course, isLoading, selectedLectureId, setSelectedLectureId } =
|
||||||
|
@ -18,12 +20,14 @@ export const CourseDetailDescription: React.FC = () => {
|
||||||
return course?.sections?.[0]?.lectures?.[0]?.id;
|
return course?.sections?.[0]?.lectures?.[0]?.id;
|
||||||
}, [course]);
|
}, [course]);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const { canEdit } = useContext(CourseDetailContext);
|
||||||
|
const { id } = useParams();
|
||||||
return (
|
return (
|
||||||
<div className="w-full bg-white shadow-md rounded-lg border border-gray-200 p-6">
|
<div className="w-full bg-white shadow-md rounded-lg border border-gray-200 p-5 my-4">
|
||||||
{isLoading || !course ? (
|
{isLoading || !course ? (
|
||||||
<Skeleton active paragraph={{ rows: 4 }} />
|
<Skeleton active paragraph={{ rows: 4 }} />
|
||||||
) : (
|
) : (
|
||||||
<div className="space-y-4">
|
<div className="space-y-2">
|
||||||
{!selectedLectureId && (
|
{!selectedLectureId && (
|
||||||
<>
|
<>
|
||||||
<div className="relative my-4 overflow-hidden flex justify-center items-center">
|
<div className="relative my-4 overflow-hidden flex justify-center items-center">
|
||||||
|
@ -43,16 +47,61 @@ export const CourseDetailDescription: React.FC = () => {
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<div className="text-lg font-bold">{"课程简介:"}</div>
|
<div className="text-lg font-bold">{"课程简介:"}</div>
|
||||||
<div className="text-gray-600 flex justify-start gap-4">
|
<div className="flex gap-2 flex-wrap items-center">
|
||||||
<div>{course?.subTitle}</div>
|
<div>{course?.subTitle}</div>
|
||||||
<div className="flex gap-1">
|
{
|
||||||
<EyeOutlined></EyeOutlined>
|
course.terms.map((term) => {
|
||||||
<div>{course?.meta?.views || 0}</div>
|
return (
|
||||||
|
<Tag
|
||||||
|
key={term.id}
|
||||||
|
// color={term.taxonomy.slug===TaxonomySlug.CATEGORY? "blue" : "green"}
|
||||||
|
color={
|
||||||
|
term?.taxonomy?.slug ===
|
||||||
|
TaxonomySlug.CATEGORY
|
||||||
|
? "blue"
|
||||||
|
: term?.taxonomy?.slug ===
|
||||||
|
TaxonomySlug.LEVEL
|
||||||
|
? "green"
|
||||||
|
: "orange"
|
||||||
|
}
|
||||||
|
className="px-3 py-1 rounded-full bg-blue-100 text-blue-600 border-0">
|
||||||
|
{term.name}
|
||||||
|
</Tag>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="text-gray-800 flex justify-start gap-5">
|
||||||
|
|
||||||
|
|
||||||
<div className="flex gap-1">
|
<div className="flex gap-1">
|
||||||
<CalendarOutlined></CalendarOutlined>
|
<CalendarOutlined></CalendarOutlined>
|
||||||
{dayjs(course?.createdAt).format("YYYY年M月D日")}
|
{dayjs(course?.createdAt).format("YYYY年M月D日")}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex gap-1">
|
||||||
|
<ReloadOutlined></ReloadOutlined>
|
||||||
|
{dayjs(course?.updatedAt).format("YYYY年M月D日")}
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-1">
|
||||||
|
<EyeOutlined></EyeOutlined>
|
||||||
|
<div>{course?.meta?.views || 0}</div>
|
||||||
|
</div>
|
||||||
|
{
|
||||||
|
canEdit && (
|
||||||
|
<div
|
||||||
|
className="flex gap-1 text-primary hover:cursor-pointer"
|
||||||
|
onClick={() => {
|
||||||
|
const url = id
|
||||||
|
? `/course/${id}/editor`
|
||||||
|
: "/course/editor";
|
||||||
|
navigate(url);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<EditTwoTone></EditTwoTone>
|
||||||
|
{"点击编辑课程"}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<Paragraph
|
<Paragraph
|
||||||
className="text-gray-600"
|
className="text-gray-600"
|
||||||
|
|
|
@ -25,7 +25,7 @@ export function CourseDetailHeader() {
|
||||||
return (
|
return (
|
||||||
<Header className="select-none flex items-center justify-center bg-white shadow-md border-b border-gray-100 fixed w-full z-30">
|
<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">
|
<div className="w-full flex items-center justify-between h-full">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-10">
|
||||||
<HomeOutlined
|
<HomeOutlined
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
navigate("/");
|
navigate("/");
|
||||||
|
@ -33,7 +33,7 @@ export function CourseDetailHeader() {
|
||||||
className="text-2xl text-primary-500 hover:scale-105 cursor-pointer"
|
className="text-2xl text-primary-500 hover:scale-105 cursor-pointer"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="text-2xl font-bold bg-gradient-to-r from-primary-600 via-primary-500 to-primary-400 bg-clip-text text-transparent transition-transform ">
|
<div className="text-2xl tracking-widest font-bold bg-gradient-to-r from-primary-600 via-primary-500 to-primary-400 bg-clip-text text-transparent transition-transform ">
|
||||||
{course?.title}
|
{course?.title}
|
||||||
</div>
|
</div>
|
||||||
{/* <NavigationMenu /> */}
|
{/* <NavigationMenu /> */}
|
||||||
|
|
|
@ -111,7 +111,7 @@ export function CourseFormProvider({
|
||||||
delete formattedValues.sections;
|
delete formattedValues.sections;
|
||||||
delete formattedValues.deptIds;
|
delete formattedValues.deptIds;
|
||||||
|
|
||||||
console.log(course.meta);
|
console.log(course?.meta);
|
||||||
console.log(formattedValues?.meta);
|
console.log(formattedValues?.meta);
|
||||||
try {
|
try {
|
||||||
if (editId) {
|
if (editId) {
|
||||||
|
|
|
@ -2,7 +2,6 @@ import { api } from "@nice/client/";
|
||||||
import { Checkbox, Form } from "antd";
|
import { Checkbox, Form } from "antd";
|
||||||
import { TermDto } from "@nice/common";
|
import { TermDto } from "@nice/common";
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
|
|
||||||
export default function TermParentSelector({
|
export default function TermParentSelector({
|
||||||
value,
|
value,
|
||||||
onChange,
|
onChange,
|
||||||
|
@ -13,11 +12,7 @@ export default function TermParentSelector({
|
||||||
domainId,
|
domainId,
|
||||||
style,
|
style,
|
||||||
}: any) {
|
}: any) {
|
||||||
const utils = api.useUtils();
|
|
||||||
const [selectedValues, setSelectedValues] = useState<string[]>([]); // 用于存储选中的值
|
const [selectedValues, setSelectedValues] = useState<string[]>([]); // 用于存储选中的值
|
||||||
const [termsData, setTermsData] = useState<any[]>([]);
|
|
||||||
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data,
|
data,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
|
Loading…
Reference in New Issue