diff --git a/src/api/course.ts b/src/api/course.ts index 53d62bf..70a4dec 100644 --- a/src/api/course.ts +++ b/src/api/course.ts @@ -31,3 +31,8 @@ export function playPing(courseId: number, hourId: number) { export function latestLearn() { return client.get(`/api/v1/user/latest-learn`, {}); } + +//下载课件 +export function downloadAttachment(courseId: number, id: number) { + return client.get(`/api/v1/course/${courseId}/attach/${id}/download`, {}); +} diff --git a/src/api/internal/httpClient.ts b/src/api/internal/httpClient.ts index 0b29793..8c75dee 100644 --- a/src/api/internal/httpClient.ts +++ b/src/api/internal/httpClient.ts @@ -7,6 +7,10 @@ const GoLogin = () => { window.location.href = "/login"; }; +const GoError = () => { + window.location.href = "/error"; +}; + export class HttpClient { axios: Axios; @@ -52,13 +56,13 @@ export class HttpClient { GoLogin(); } else if (status === 404) { // 跳转到404页面 - GoLogin(); + GoError(); } else if (status === 403) { // 跳转到无权限页面 - GoLogin(); + GoError(); } else if (status === 500) { // 跳转到500异常页面 - GoLogin(); + GoError(); } return Promise.reject(error.response); } diff --git a/src/pages/course/index.module.scss b/src/pages/course/index.module.scss index 1f5c8aa..38ecc86 100644 --- a/src/pages/course/index.module.scss +++ b/src/pages/course/index.module.scss @@ -92,13 +92,67 @@ } } +.tabs { + width: 1200px; + height: 48px; + margin: 0 auto; + margin-top: 24px; + display: flex; + align-items: center; + position: relative; + .tab-item { + width: 64px; + height: 48px; + margin-right: 50px; + transition: all 0.2s; + position: relative; + cursor: pointer; + &:hover { + opacity: 0.8; + .tit { + color: #ff4d4f; + } + } + .tit { + width: 64px; + height: 40px; + font-size: 16px; + font-weight: 400; + color: rgba(0, 0, 0, 0.88); + line-height: 40px; + } + } + .tab-active-item { + width: 64px; + height: 48px; + cursor: pointer; + margin-right: 50px; + transition: all 0.2s; + + &:hover { + opacity: 0.8; + } + .tit { + width: 64px; + height: 40px; + font-size: 16px; + font-weight: 500; + color: #ff4d4f; + line-height: 40px; + } + .banner { + animation: scaleTransX 0.3s; + } + } +} + .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; + margin-top: 24px; box-sizing: border-box; padding: 24px; .hours-list-box { @@ -135,3 +189,58 @@ } } } + +.attachments-cont { + width: 100%; + height: auto; + background: #ffffff; + box-shadow: 0px 2px 8px 4px rgba(0, 0, 0, 0.04); + border-radius: 12px; + margin-top: 24px; + box-sizing: border-box; + padding: 24px; + .attachments-item { + width: 100%; + height: 56px; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + box-sizing: border-box; + padding: 0px 24px; + margin-bottom: 8px; + text-align: left; + &:last-child { + margin-bottom: 0px; + } + .left-cont { + flex: 1; + display: flex; + flex-direction: row; + align-items: center; + .title { + flex: 1; + font-size: 14px; + font-weight: 400; + color: rgba(0, 0, 0, 0.88); + line-height: 24px; + margin-right: 10px; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + } + } + .download { + width: auto; + height: 24px; + font-size: 14px; + font-weight: 400; + color: #ff4d4f; + line-height: 24px; + cursor: pointer; + &:hover { + opacity: 0.8; + } + } + } +} diff --git a/src/pages/course/index.tsx b/src/pages/course/index.tsx index 715bfb4..f661566 100644 --- a/src/pages/course/index.tsx +++ b/src/pages/course/index.tsx @@ -1,20 +1,41 @@ import { useEffect, useState } from "react"; -import { Row, Col, Spin, Image, Progress } from "antd"; +import { Row, Spin, Image, Progress } from "antd"; import styles from "./index.module.scss"; -import { useParams } from "react-router-dom"; +import { useParams, useNavigate, useLocation } 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"; import { Empty } from "../../compenents"; +import iconRoute from "../../assets/images/commen/icon-route.png"; + +interface tabModal { + key: number; + label: string; +} + +interface attachModal { + id: number; + course_id: number; + rid: number; + sort: number; + title: string; + type: string; + url?: string; +} const CoursePage = () => { const params = useParams(); + const navigate = useNavigate(); + const result = new URLSearchParams(useLocation().search); const [loading, setLoading] = useState(true); const [course, setCourse] = useState({}); const [chapters, setChapters] = useState([]); const [hours, setHours] = useState({}); const [learnRecord, setLearnRecord] = useState({}); const [learnHourRecord, setLearnHourRecord] = useState({}); + const [tabKey, setTabKey] = useState(Number(result.get("tab") || 1)); + const [attachments, setAttachments] = useState([]); + const [items, setItems] = useState([]); useEffect(() => { getDetail(); @@ -34,6 +55,22 @@ const CoursePage = () => { if (res.data.learn_hour_records) { setLearnHourRecord(res.data.learn_hour_records); } + let arr = res.data.attachments; + let tabs = [ + { + key: 1, + label: `课程目录`, + }, + ]; + if (arr.length > 0) { + tabs.push({ + key: 2, + label: `课程附件`, + }); + setAttachments(arr); + } + setItems(tabs); + setLoading(false); }) .catch((e) => { @@ -41,6 +78,17 @@ const CoursePage = () => { }); }; + const onChange = (key: number) => { + setTabKey(key); + navigate("/course/" + params.courseId + "?tab=" + key); + }; + + const downLoadFile = (cid: number, id: number) => { + Course.downloadAttachment(cid, id).then((res: any) => { + window.open(res.data.download_url); + }); + }; + return (
{loading && ( @@ -133,80 +181,134 @@ const CoursePage = () => {
{course.short_desc}
)}
-
- {chapters.length === 0 && JSON.stringify(hours) === "{}" && ( - - )} - {chapters.length === 0 && JSON.stringify(hours) !== "{}" && ( -
- {hours[0].map((item: any, index: number) => ( -
- {learnHourRecord[item.id] && ( - - )} - {!learnHourRecord[item.id] && ( - - )} -
- ))} +
+ {items.map((item: any) => ( +
{ + onChange(item.key); + }} + > +
{item.label}
+ {item.key === tabKey && ( + + )}
- )} - {chapters.length > 0 && JSON.stringify(hours) !== "{}" && ( -
- {chapters.map((item: any, index: number) => ( -
-
{item.name}
- {hours[item.id] && - hours[item.id].map((it: any, int: number) => ( -
- {learnHourRecord[it.id] && ( - - )} - {!learnHourRecord[it.id] && ( - - )} -
- ))} -
- ))} -
- )} + ))}
+ {tabKey === 1 && ( +
+ {chapters.length === 0 && JSON.stringify(hours) === "{}" && ( + + )} + {chapters.length === 0 && JSON.stringify(hours) !== "{}" && ( +
+ {hours[0].map((item: any, index: number) => ( +
+ {learnHourRecord[item.id] && ( + + )} + {!learnHourRecord[item.id] && ( + + )} +
+ ))} +
+ )} + {chapters.length > 0 && JSON.stringify(hours) !== "{}" && ( +
+ {chapters.map((item: any, index: number) => ( +
+
{item.name}
+ {hours[item.id] && + hours[item.id].map((it: any, int: number) => ( +
+ {learnHourRecord[it.id] && ( + + )} + {!learnHourRecord[it.id] && ( + + )} +
+ ))} +
+ ))} +
+ )} +
+ )} + {tabKey === 2 && ( +
+ {attachments.map((item: any, index: number) => ( +
+
+ + {item.title} +
+
downLoadFile(item.course_id, item.id)} + > + 下载 +
+
+ ))} +
+ )} )}
diff --git a/src/pages/error/index.module.scss b/src/pages/error/index.module.scss new file mode 100644 index 0000000..6e35a80 --- /dev/null +++ b/src/pages/error/index.module.scss @@ -0,0 +1,4 @@ +.main { + width: 100vw; + height: 100vh; +} diff --git a/src/pages/error/index.tsx b/src/pages/error/index.tsx new file mode 100644 index 0000000..28460b6 --- /dev/null +++ b/src/pages/error/index.tsx @@ -0,0 +1,28 @@ +import { Button, Result } from "antd"; +import { useNavigate } from "react-router-dom"; +import styles from "./index.module.scss"; + +const ErrorPage = () => { + const navigate = useNavigate(); + + return ( + { + navigate("/", { replace: true }); + }} + > + 返回首页 + + } + /> + ); +}; + +export default ErrorPage; diff --git a/src/pages/index/index.tsx b/src/pages/index/index.tsx index 002c5a0..b5e7a1d 100644 --- a/src/pages/index/index.tsx +++ b/src/pages/index/index.tsx @@ -30,10 +30,6 @@ const IndexPage = () => { const [learnCourseRecords, setLearnCourseRecords] = useState({}); const [learnCourseHourCount, setLearnCourseHourCount] = useState({}); const [stats, setStats] = useState({}); - - const departments = useSelector( - (state: any) => state.loginUser.value.departments - ); const currentDepId = useSelector( (state: any) => state.loginUser.value.currentDepId ); diff --git a/src/routes/index.tsx b/src/routes/index.tsx index 63993b2..b17a49a 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -17,6 +17,8 @@ const CoursePage = lazy(() => import("../pages/course/index")); const CoursePlayPage = lazy(() => import("../pages/course/video")); //最近学习 const LatestLearnPage = lazy(() => import("../pages/latest-learn")); +//错误页面 +const ErrorPage = lazy(() => import("../pages/error")); import PrivateRoute from "../compenents/private-route"; @@ -96,6 +98,14 @@ const routes: RouteObject[] = [ path: "/course/:courseId/hour/:hourId", element: } />, }, + { + path: "/error", + element: , + }, + { + path: "*", + element: , + }, ], }, ],