From 351e755fe2bf9445a8f750daa3d0728ebb52c0d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A6=BA=E7=8B=A8?= <18119604035@163.com> Date: Fri, 24 Mar 2023 17:45:47 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AF=BE=E7=A8=8B=E8=AF=A6=E6=83=85=E5=88=9D?= =?UTF-8?q?=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/compenents/footer/index.tsx | 1 + src/compenents/header/index.tsx | 2 +- src/index.scss | 10 ++ src/pages/course/compenents/hour.module.scss | 67 +++++++++ src/pages/course/compenents/hour.tsx | 65 +++++++++ src/pages/course/index.module.scss | 136 +++++++++++++++++++ src/pages/course/index.tsx | 129 ++++++++++++++++++ src/pages/index/compenents/courses-model.tsx | 12 +- src/pages/index/index.module.scss | 1 - src/pages/index/index.tsx | 2 + src/routes/index.tsx | 5 + src/store/user/loginUserSlice.ts | 8 +- src/utils/index.ts | 11 +- 13 files changed, 438 insertions(+), 11 deletions(-) create mode 100644 src/pages/course/compenents/hour.module.scss create mode 100644 src/pages/course/compenents/hour.tsx create mode 100644 src/pages/course/index.module.scss create mode 100644 src/pages/course/index.tsx diff --git a/src/compenents/footer/index.tsx b/src/compenents/footer/index.tsx index 44b1481..05d731e 100644 --- a/src/compenents/footer/index.tsx +++ b/src/compenents/footer/index.tsx @@ -9,6 +9,7 @@ export const Footer: React.FC = () => { backgroundColor: "#333333", height: 90, textAlign: "center", + marginTop: 80, }} > {
- {user.name && ( + {user && user.name && ( .ant-btn-default:hover { diff --git a/src/pages/course/compenents/hour.module.scss b/src/pages/course/compenents/hour.module.scss new file mode 100644 index 0000000..001af9e --- /dev/null +++ b/src/pages/course/compenents/hour.module.scss @@ -0,0 +1,67 @@ +.item { + width: 100%; + height: 56px; + background: #ffffff; + border-radius: 6px; + display: flex; + align-items: center; + justify-content: space-between; + box-sizing: border-box; + padding: 0 24px; + cursor: pointer; + &:hover { + background: rgba(255, 77, 79, 0.05); + } + + .left-item { + width: 900px; + height: 20px; + display: flex; + align-items: center; + i { + color: rgba(0, 0, 0, 0.3); + } + .title { + width: 850px; + margin-left: 10px; + height: 24px; + font-size: 14px; + font-weight: 400; + color: rgba(0, 0, 0, 0.88); + line-height: 24px; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + text-align: left; + } + } + + .record { + height: 24px; + font-size: 14px; + font-weight: 400; + color: rgba(0, 0, 0, 0.45); + line-height: 24px; + margin-right: 24px; + } + + .link { + height: 24px; + font-size: 14px; + font-weight: 400; + color: #ff4d4f; + line-height: 24px; + cursor: pointer; + &:hover { + opacity: 0.8; + } + } + + .complete { + height: 24px; + font-size: 14px; + font-weight: 400; + color: rgba(0, 0, 0, 0.88); + line-height: 24px; + } +} diff --git a/src/pages/course/compenents/hour.tsx b/src/pages/course/compenents/hour.tsx new file mode 100644 index 0000000..c1ce1dc --- /dev/null +++ b/src/pages/course/compenents/hour.tsx @@ -0,0 +1,65 @@ +import React, { useState, useEffect } from "react"; +import { Image, Progress } from "antd"; +import { useNavigate } from "react-router-dom"; +import styles from "./hour.module.scss"; +import mediaIcon from "../../../assets/images/commen/icon-medal.png"; +import { Navigate } from "react-router-dom"; +import { durationFormat } from "../../../utils/index"; + +interface PropInterface { + id: number; + title: string; + duration: number; + record: any; + progress: number; +} + +export const HourCompenent: React.FC = ({ + id, + title, + duration, + record, + progress, +}) => { + const navigate = useNavigate(); + return ( +
+
+ +
+ {title}({durationFormat(Number(duration))}) +
+
+
+ {progress >= 0 && progress < 100 && ( + <> +
+ 上次学习到{durationFormat(Number(duration))} +
+ {progress === 0 && ( +
{ + navigate(`/course/play/${id}`); + }} + > + 开始学习 +
+ )} + {progress !== 0 && ( +
{ + navigate(`/course/play/${id}`); + }} + > + 继续学习 +
+ )} + + )} + {progress === 100 &&
已学完
} +
+
+ ); +}; diff --git a/src/pages/course/index.module.scss b/src/pages/course/index.module.scss new file mode 100644 index 0000000..ec3226c --- /dev/null +++ b/src/pages/course/index.module.scss @@ -0,0 +1,136 @@ +.top-cont { + width: 100%; + height: auto; + background: #ffffff; + box-shadow: 0px 2px 8px 4px rgba(0, 0, 0, 0.04); + border-radius: 12px; + margin-top: 30px; + display: flex; + flex-direction: column; + box-sizing: border-box; + padding: 24px; + .info { + width: 720px; + height: 90px; + text-align: left; + display: flex; + flex-direction: column; + justify-content: space-between; + margin-left: 24px; + .title { + width: 100%; + height: 36px; + font-size: 20px; + font-weight: 600; + color: rgba(0, 0, 0, 0.88); + text-overflow: ellipsis; + line-height: 36px; + white-space: nowrap; + overflow: hidden; + } + .status { + width: 100%; + height: 24px; + display: flex; + align-items: center; + .type { + width: 52px; + height: 24px; + background: rgba(255, 77, 79, 0.1); + border-radius: 6px; + font-size: 14px; + font-weight: 400; + color: #ff4d4f; + line-height: 24px; + display: flex; + align-items: center; + justify-content: center; + } + .active-type { + width: 52px; + height: 24px; + background: rgba(#ff9900, 0.1); + border-radius: 6px; + font-size: 14px; + font-weight: 400; + color: #ff9900; + line-height: 24px; + display: flex; + align-items: center; + justify-content: center; + } + .success { + height: 24px; + display: flex; + align-items: center; + margin-left: 24px; + span { + height: 24px; + font-size: 14px; + font-weight: 400; + color: #ff4d4f; + line-height: 24px; + } + } + } + } + .desc { + width: 100%; + height: 112px; + font-size: 16px; + font-weight: 400; + color: rgba(0, 0, 0, 0.6); + line-height: 28px; + text-align: left; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 4; + -webkit-box-orient: vertical; + margin-top: 34px; + } +} + +.chapters-hours-cont { + width: 100%; + height: auto; + background: #ffffff; + box-shadow: 0px 2px 8px 4px rgba(0, 0, 0, 0.04); + border-radius: 12px; + margin-top: 30px; + box-sizing: border-box; + padding: 24px; + .hours-list-box { + width: 100%; + height: auto; + display: flex; + flex-direction: column; + + .chapter-it { + width: 100%; + height: auto; + margin-bottom: 24px; + &:last-child { + margin-bottom: 0px; + } + .chapter-name { + width: 100%; + height: 24px; + font-size: 16px; + font-weight: 500; + color: rgba(0, 0, 0, 0.88); + line-height: 24px; + text-align: left; + margin-bottom: 24px; + } + } + .hours-it { + width: 100%; + height: auto; + margin-bottom: 8px; + &:last-child { + margin-bottom: 0px; + } + } + } +} diff --git a/src/pages/course/index.tsx b/src/pages/course/index.tsx new file mode 100644 index 0000000..4544bd7 --- /dev/null +++ b/src/pages/course/index.tsx @@ -0,0 +1,129 @@ +import { useEffect, useState } from "react"; +import { Image, Progress } from "antd"; +import styles from "./index.module.scss"; +import { useParams } from "react-router-dom"; +import { course as Course } from "../../api/index"; +import mediaIcon from "../../assets/images/commen/icon-medal.png"; +import { HourCompenent } from "./compenents/hour"; + +const CoursePage = () => { + const params = useParams(); + const [loading, setLoading] = useState(false); + const [course, setCourse] = useState({}); + const [chapters, setChapters] = useState([]); + const [hours, setHours] = useState({}); + const [learnRecord, setLearnRecord] = useState({}); + const [learnHourRecord, setLearnHourRecord] = useState({}); + const [progress, setprogresP] = useState(20); + + useEffect(() => { + getDetail(); + }, [params.courseId]); + + const getDetail = () => { + setLoading(true); + Course.detail(Number(params.courseId)).then((res: any) => { + setCourse(res.data.course); + setChapters(res.data.chapters); + setHours(res.data.hours); + if (res.data.learn_record) { + setLearnRecord(res.data.learn_record); + } + if (res.data.learn_hour_records) { + setLearnHourRecord(res.data.learn_hour_records); + } + setLoading(false); + }); + }; + + return ( +
+
+
+
+ +
+
{course.title}
+
+ {course.is_required === 1 && ( +
必修课
+ )} + {course.is_required === 0 && ( +
选修课
+ )} + {progress === 100 && ( +
+ + 恭喜你学完此套课程! +
+ )} +
+
+
+ `${percent}%`} + /> +
+ {course.short_desc && ( +
{course.short_desc}
+ )} +
+
+ {chapters.length === 0 && JSON.stringify(hours) !== "{}" && ( +
+ {hours[0].map((item: any) => ( +
+ +
+ ))} +
+ )} + {chapters.length > 0 && JSON.stringify(hours) !== "{}" && ( +
+ {chapters.map((item: any) => ( +
+
{item.name}
+ {hours[item.id].map((it: any) => ( +
+ +
+ ))} +
+ ))} +
+ )} +
+
+ ); +}; + +export default CoursePage; diff --git a/src/pages/index/compenents/courses-model.tsx b/src/pages/index/compenents/courses-model.tsx index ad3f2be..6a1017b 100644 --- a/src/pages/index/compenents/courses-model.tsx +++ b/src/pages/index/compenents/courses-model.tsx @@ -1,9 +1,12 @@ import React, { useState, useEffect } from "react"; import { Image, Progress } from "antd"; +import { useNavigate } from "react-router-dom"; import styles from "./courses-model.module.scss"; import mediaIcon from "../../../assets/images/commen/icon-medal.png"; +import { Navigate } from "react-router-dom"; interface PropInterface { + id: number; title: string; thumb: string; isRequired: number; @@ -11,13 +14,20 @@ interface PropInterface { } export const CoursesModel: React.FC = ({ + id, title, thumb, isRequired, progress, }) => { + const navigate = useNavigate(); return ( -
+
{ + navigate(`/course/${id}`); + }} + >
{
{learnCourseRecords[item.id] && ( { )} {!learnCourseRecords[item.id] && ( { // 懒加载 const LoginPage = lazy(() => import("../pages/login")); const IndexPage = lazy(() => import("../pages/index")); +const CoursePage = lazy(() => import("../pages/course")); const routes: RouteObject[] = [ { @@ -46,6 +47,10 @@ const routes: RouteObject[] = [ path: "/login", element: , }, + { + path: "/course/:courseId", + element: , + }, ], }, ]; diff --git a/src/store/user/loginUserSlice.ts b/src/store/user/loginUserSlice.ts index 9f7e7da..9d6beb8 100644 --- a/src/store/user/loginUserSlice.ts +++ b/src/store/user/loginUserSlice.ts @@ -1,13 +1,7 @@ import { createSlice } from "@reduxjs/toolkit"; -type UserInterface = { - id: number; - name: string; - email: string; - avatar: string; -}; type UserStoreInterface = { - user: UserInterface | null; + user: null; departments: string[]; isLogin: boolean; }; diff --git a/src/utils/index.ts b/src/utils/index.ts index f858540..14751dc 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -16,8 +16,17 @@ export function dateFormat(dateStr: string) { return moment(dateStr).format("YYYY-MM-DD HH:mm"); } +export function durationFormat(dateStr: number) { + var d = moment.duration(dateStr, "seconds"); + let hour = d.hours() === 0 ? "" : d.hours() + ":"; + let minute = d.minutes() >= 10 ? d.minutes() + ":" : "0" + d.minutes() + ":"; + let second = d.seconds() >= 10 ? d.seconds() : "0" + d.seconds(); + + return hour + minute + second; +} + export function studyTimeFormat(dateStr: number) { - var d = moment.duration(dateStr/1000, "seconds"); + var d = moment.duration(dateStr / 1000, "seconds"); let value = []; value.push(Math.floor(d.asDays())); value.push(d.hours());