diff --git a/src/api/login.ts b/src/api/login.ts index 8b41e40..6806d92 100644 --- a/src/api/login.ts +++ b/src/api/login.ts @@ -10,3 +10,11 @@ export function login(email: string, password: string) { export function logout() { return client.post("/api/v1/auth/logout", {}); } + +export function loginLdap(email: string, password: string) { + return client.post("/api/v1/auth/login/ldap", { + username: email, + password: password, + }); +} + diff --git a/src/pages/course/index.tsx b/src/pages/course/index.tsx index 01a8549..f112e1a 100644 --- a/src/pages/course/index.tsx +++ b/src/pages/course/index.tsx @@ -8,12 +8,12 @@ import { HourCompenent } from "./compenents/hour"; import { Empty } from "../../compenents"; import iconRoute from "../../assets/images/commen/icon-route.png"; -type tabModal = { +type TabModel = { key: number; label: string; }; -type attachModal = { +type AttachModel = { id: number; course_id: number; rid: number; @@ -23,19 +23,40 @@ type attachModal = { url?: string; }; +type HoursModel = { + [key: number]: HourModel[]; +}; + +type ChapterModel = { + course_id: number; + created_at: string; + id: number; + name: string; + sort: number; + updated_at: string; +}; + +type LearnHourRecordsModel = { + [key: number]: HourRecordModel; +}; + 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 [course, setCourse] = useState(null); + const [chapters, setChapters] = useState([]); + const [hours, setHours] = useState({}); + const [learnRecord, setLearnRecord] = useState( + null + ); + const [learnHourRecord, setLearnHourRecord] = useState( + {} + ); const [tabKey, setTabKey] = useState(Number(result.get("tab") || 1)); - const [attachments, setAttachments] = useState([]); - const [items, setItems] = useState([]); + const [attachments, setAttachments] = useState([]); + const [items, setItems] = useState([]); useEffect(() => { getDetail(); @@ -55,8 +76,8 @@ const CoursePage = () => { if (res.data.learn_hour_records) { setLearnHourRecord(res.data.learn_hour_records); } - let arr = res.data.attachments; - let tabs = [ + let arr: AttachModel[] = res.data.attachments; + let tabs: TabModel[] = [ { key: 1, label: `课程目录`, @@ -115,18 +136,18 @@ const CoursePage = () => { height={90} style={{ borderRadius: 10 }} preview={false} - src={course.thumb} + src={course?.thumb} />
-
{course.title}
+
{course?.title}
- {course.is_required === 1 && ( + {course?.is_required === 1 && (
必修课
)} - {course.is_required === 0 && ( + {course?.is_required === 0 && (
选修课
)} - {learnRecord.progress / 100 >= 100 && ( + {learnRecord && learnRecord.progress / 100 >= 100 && (
{
- {JSON.stringify(learnRecord) === "{}" && + {(!learnRecord || + (learnRecord && JSON.stringify(learnRecord) === "{}")) && JSON.stringify(learnHourRecord) === "{}" && ( { format={(percent) => `${percent}%`} /> )} - {JSON.stringify(learnRecord) === "{}" && + {(!learnRecord || + (learnRecord && JSON.stringify(learnRecord) === "{}")) && JSON.stringify(learnHourRecord) !== "{}" && ( { format={(percent) => `${percent}%`} /> )} - {JSON.stringify(learnRecord) !== "{}" && + {learnRecord && + JSON.stringify(learnRecord) !== "{}" && JSON.stringify(learnHourRecord) !== "{}" && ( { /> )} - {course.short_desc && ( + {course?.short_desc && (
{course.short_desc}
)} diff --git a/src/pages/course/video.tsx b/src/pages/course/video.tsx index 5b7e2ee..c49117b 100644 --- a/src/pages/course/video.tsx +++ b/src/pages/course/video.tsx @@ -13,15 +13,15 @@ const CoursePalyPage = () => { const params = useParams(); const systemConfig = useSelector((state: any) => state.systemConfig.value); const user = useSelector((state: any) => state.loginUser.value.user); - const [playUrl, setPlayUrl] = useState(""); + const [playUrl, setPlayUrl] = useState(""); const [playDuration, setPlayDuration] = useState(0); - const [playendedStatus, setPlayendedStatus] = useState(false); + const [playendedStatus, setPlayendedStatus] = useState(false); const [lastSeeValue, setLastSeeValue] = useState({}); - const [course, setCourse] = useState({}); - const [hour, setHour] = useState({}); - const [loading, setLoading] = useState(false); - const [isLastpage, setIsLastpage] = useState(false); - const [totalHours, setTotalHours] = useState([]); + const [course, setCourse] = useState(null); + const [hour, setHour] = useState(null); + const [loading, setLoading] = useState(false); + const [isLastpage, setIsLastpage] = useState(false); + const [totalHours, setTotalHours] = useState([]); const [playingTime, setPlayingTime] = useState(0); const [watchedSeconds, setWatchedSeconds] = useState(0); const myRef = useRef(0); @@ -59,17 +59,17 @@ const CoursePalyPage = () => { }, [watchedSeconds]); useEffect(() => { - totalRef.current = hour.duration; + totalRef.current = hour?.duration || 0; }, [hour]); const getCourse = () => { Course.detail(Number(params.courseId)).then((res: any) => { - let totalHours: any = []; + let totalHours: HourModel[] = []; if (res.data.chapters.length === 0) { setTotalHours(res.data.hours[0]); totalHours = res.data.hours[0]; } else if (res.data.chapters.length > 0) { - const arr: any = []; + const arr: HourModel[] = []; for (let key in res.data.hours) { res.data.hours[key].map((item: any) => { arr.push(item); @@ -97,7 +97,7 @@ const CoursePalyPage = () => { setCourse(res.data.course); setHour(res.data.hour); document.title = res.data.hour.title; - let record = res.data.user_hour_record; + let record: HourRecordModel = res.data.user_hour_record; let params = null; if (record && record.finished_duration && record.is_finished === 0) { params = { @@ -249,7 +249,7 @@ const CoursePalyPage = () => {
-
{hour.title}
+
{hour?.title}
{ const navigate = useNavigate(); const result = new URLSearchParams(useLocation().search); @@ -18,8 +41,8 @@ const IndexPage = () => { const [open, setOpen] = useState(false); const [loading, setLoading] = useState(false); const [tabKey, setTabKey] = useState(Number(result.get("tab") || 0)); - const [coursesList, setCoursesList] = useState([]); - const [categories, setCategories] = useState([]); + const [coursesList, setCoursesList] = useState([]); + const [categories, setCategories] = useState([]); const [categoryId, setCategoryId] = useState( Number(result.get("cid") || 0) ); @@ -27,9 +50,10 @@ const IndexPage = () => { String(result.get("catName") || "所有分类") ); const [selectKey, setSelectKey] = useState([0]); - const [learnCourseRecords, setLearnCourseRecords] = useState({}); + const [learnCourseRecords, setLearnCourseRecords] = + useState({}); const [learnCourseHourCount, setLearnCourseHourCount] = useState({}); - const [stats, setStats] = useState({}); + const [stats, setStats] = useState(null); const currentDepId = useSelector( (state: any) => state.loginUser.value.currentDepId ); @@ -62,14 +86,14 @@ const IndexPage = () => { const getData = () => { setLoading(true); user.courses(currentDepId, categoryId).then((res: any) => { - const records = res.data.learn_course_records; + const records: LearnCourseRecordsModel = res.data.learn_course_records; setStats(res.data.stats); setLearnCourseRecords(records); setLearnCourseHourCount(res.data.user_course_hour_count); if (tabKey === 0) { setCoursesList(res.data.courses); } else if (tabKey === 1) { - const arr: any = []; + const arr: CourseModel[] = []; res.data.courses.map((item: any) => { if (item.is_required === 1) { arr.push(item); @@ -77,7 +101,7 @@ const IndexPage = () => { }); setCoursesList(arr); } else if (tabKey === 2) { - const arr: any = []; + const arr: CourseModel[] = []; res.data.courses.map((item: any) => { if (item.is_required === 0) { arr.push(item); @@ -85,7 +109,7 @@ const IndexPage = () => { }); setCoursesList(arr); } else if (tabKey === 3) { - const arr: any = []; + const arr: CourseModel[] = []; res.data.courses.map((item: any) => { if (records[item.id] && records[item.id].progress >= 10000) { arr.push(item); @@ -93,7 +117,7 @@ const IndexPage = () => { }); setCoursesList(arr); } else if (tabKey === 4) { - const arr: any = []; + const arr: CourseModel[] = []; res.data.courses.map((item: any) => { if ( !records[item.id] || @@ -112,7 +136,7 @@ const IndexPage = () => { user.coursesCategories().then((res: any) => { const categories = res.data.categories; if (JSON.stringify(categories) !== "{}") { - const new_arr: any[] = checkArr(categories, 0); + const new_arr: CategoryModel[] = checkArr(categories, 0); new_arr.unshift({ key: 0, title: "所有分类", @@ -123,7 +147,7 @@ const IndexPage = () => { }; const checkArr = (categories: any[], id: number) => { - const arr = []; + const arr: CategoryModel[] = []; for (let i = 0; i < categories[id].length; i++) { if (!categories[categories[id][i].id]) { arr.push({ @@ -133,7 +157,10 @@ const IndexPage = () => { key: categories[id][i].id, }); } else { - const new_arr: any[] = checkArr(categories, categories[id][i].id); + const new_arr: CategoryModel[] = checkArr( + categories, + categories[id][i].id + ); arr.push({ title: ( {categories[id][i].name} @@ -240,17 +267,17 @@ const IndexPage = () => {
必修课:已学完课程 - {stats.required_finished_course_count || 0} - / {stats.required_course_count || 0} + {stats?.required_finished_course_count || 0} + / {stats?.required_course_count || 0}
- {stats.nun_required_course_count > 0 && ( + {stats && stats.nun_required_course_count > 0 && (
选修课:已学完课程 {" "} - {stats.nun_required_finished_course_count || 0}{" "} + {stats?.nun_required_finished_course_count || 0}{" "} - / {stats.nun_required_course_count || 0} + / {stats?.nun_required_course_count || 0}
)}
@@ -260,70 +287,76 @@ const IndexPage = () => { 学习时长
-
-
- 今日: - {studyTimeFormat(stats.today_learn_duration)[0] !== 0 && ( - <> - - {" "} - {studyTimeFormat(stats.today_learn_duration)[0] || 0}{" "} - - 天 - - )} - {studyTimeFormat(stats.today_learn_duration)[1] !== 0 && ( - <> - - {" "} - {studyTimeFormat(stats.today_learn_duration)[1] || 0}{" "} - - 小时 - - )} - - {" "} - {studyTimeFormat(stats.today_learn_duration)[2] || 0}{" "} - - 分钟 - - {" "} - {studyTimeFormat(stats.today_learn_duration)[3] || 0}{" "} - - 秒 + {stats ? ( +
+
+ 今日: + {studyTimeFormat(stats.today_learn_duration)[0] !== 0 && ( + <> + + {" "} + {studyTimeFormat(stats.today_learn_duration)[0] || + 0}{" "} + + 天 + + )} + {studyTimeFormat(stats.today_learn_duration)[1] !== 0 && ( + <> + + {" "} + {studyTimeFormat(stats.today_learn_duration)[1] || + 0}{" "} + + 小时 + + )} + + {" "} + {studyTimeFormat(stats.today_learn_duration)[2] || 0}{" "} + + 分钟 + + {" "} + {studyTimeFormat(stats.today_learn_duration)[3] || 0}{" "} + + 秒 +
+
+ 累计: + {studyTimeFormat(stats.learn_duration || 0)[0] !== 0 && ( + <> + + {" "} + {studyTimeFormat(stats.learn_duration || 0)[0] || + 0}{" "} + + 天 + + )} + {studyTimeFormat(stats.learn_duration || 0)[1] !== 0 && ( + <> + + {" "} + {studyTimeFormat(stats.learn_duration || 0)[1] || + 0}{" "} + + 小时 + + )} + + {" "} + {studyTimeFormat(stats.learn_duration || 0)[2] || 0}{" "} + + 分钟 + + {" "} + {studyTimeFormat(stats.learn_duration || 0)[3] || 0}{" "} + + 秒 +
-
- 累计: - {studyTimeFormat(stats.learn_duration || 0)[0] !== 0 && ( - <> - - {" "} - {studyTimeFormat(stats.learn_duration || 0)[0] || 0}{" "} - - 天 - - )} - {studyTimeFormat(stats.learn_duration || 0)[1] !== 0 && ( - <> - - {" "} - {studyTimeFormat(stats.learn_duration || 0)[1] || 0}{" "} - - 小时 - - )} - - {" "} - {studyTimeFormat(stats.learn_duration || 0)[2] || 0}{" "} - - 分钟 - - {" "} - {studyTimeFormat(stats.learn_duration || 0)[3] || 0}{" "} - - 秒 -
-
+ ) : null}
diff --git a/src/pages/init/index.tsx b/src/pages/init/index.tsx index 7ea6f5c..e6e54a7 100644 --- a/src/pages/init/index.tsx +++ b/src/pages/init/index.tsx @@ -24,6 +24,7 @@ export const InitPage = (props: Props) => { if (props.configData) { let config: SystemConfigStoreInterface = { //系统配置 + "ldap-enabled": props.configData["ldap-enabled"], systemApiUrl: props.configData["system-api-url"], systemH5Url: props.configData["system-h5-url"], systemLogo: props.configData["system-logo"], diff --git a/src/pages/latest-learn/index.tsx b/src/pages/latest-learn/index.tsx index 8ebcc45..db3328b 100644 --- a/src/pages/latest-learn/index.tsx +++ b/src/pages/latest-learn/index.tsx @@ -7,12 +7,46 @@ import mediaIcon from "../../assets/images/commen/icon-medal.png"; import { useNavigate } from "react-router-dom"; import { useSelector } from "react-redux"; +type LastLearnModel = { + [key: number]: LearnModel; +}; + +type LearnModel = { + course: LastCourseModel; + hour_record: HourRecordModel; + last_learn_hour: LastHourModel; + record: CourseRecordModel; +}; + +type LastCourseModel = { + charge?: number; + class_hour: number; + created_at?: string; + id: number; + is_required: number; + is_show?: number; + short_desc: string; + thumb: string; + title: string; +}; + +type LastHourModel = { + chapter_id: number; + course_id: number; + duration: number; + id: number; + rid: number; + sort: number; + title: string; + type: string; +}; + const LatestLearnPage = () => { document.title = "最近学习"; const navigate = useNavigate(); const systemConfig = useSelector((state: any) => state.systemConfig.value); const [loading, setLoading] = useState(false); - const [courses, setCourses] = useState([]); + const [courses, setCourses] = useState([]); useEffect(() => { getCourses(); diff --git a/src/pages/login/index.tsx b/src/pages/login/index.tsx index 8a13546..baccf83 100644 --- a/src/pages/login/index.tsx +++ b/src/pages/login/index.tsx @@ -1,8 +1,8 @@ import { Input, Button, message } from "antd"; -import React, { useState, useEffect } from "react"; +import React, { useState } from "react"; import styles from "./index.module.scss"; import banner from "../../assets/images/login/banner.png"; -import { useDispatch } from "react-redux"; +import { useDispatch, useSelector } from "react-redux"; import { useNavigate } from "react-router-dom"; import { loginAction } from "../../store/user/loginUserSlice"; import { login, user } from "../../api/index"; @@ -15,10 +15,11 @@ const LoginPage: React.FC = () => { const [loading, setLoading] = useState(false); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); + const systemConfig = useSelector((state: any) => state.systemConfig.value); const loginSubmit = (e: any) => { if (!email) { - message.error("请输入学员邮箱账号"); + message.error("请输入邮箱或UID"); return; } if (!password) { @@ -42,16 +43,29 @@ const LoginPage: React.FC = () => { return; } setLoading(true); - login - .login(email, password) - .then((res: any) => { - const token = res.data.token; - setToken(token); - getUser(); - }) - .catch((e) => { - setLoading(false); - }); + if (systemConfig["ldap-enabled"] === "1") { + login + .loginLdap(email, password) + .then((res: any) => { + const token = res.data.token; + setToken(token); + getUser(); + }) + .catch((e) => { + setLoading(false); + }); + } else { + login + .login(email, password) + .then((res: any) => { + const token = res.data.token; + setToken(token); + getUser(); + }) + .catch((e) => { + setLoading(false); + }); + } }; const getUser = () => { @@ -79,7 +93,7 @@ const LoginPage: React.FC = () => { setEmail(e.target.value); }} style={{ width: 400, height: 54 }} - placeholder="请输入学员邮箱账号" + placeholder={"请输入邮箱或UID"} onKeyUp={(e) => keyUp(e)} />
diff --git a/src/playedu.d.ts b/src/playedu.d.ts new file mode 100644 index 0000000..b69bf2c --- /dev/null +++ b/src/playedu.d.ts @@ -0,0 +1,53 @@ +declare global { + interface CourseModel { + charge: number; + class_hour: number; + created_at: string; + id: number; + is_required: number; + is_show: number; + short_desc: string; + thumb: string; + title: string; + } + + interface HourModel { + chapter_id: number; + course_id: number; + duration: number; + id: number; + rid: number; + sort: number; + title: string; + type: string; + } + + interface HourRecordModel { + course_id: number; + created_at: string; + finished_at?: string; + finished_duration: number; + hour_id: number; + id: number; + is_finished: number; + real_duration: number; + total_duration: number; + updated_at: string; + user_id: number; + } + + interface CourseRecordModel { + course_id: number; + created_at: string; + finished_at?: string; + finished_count: number; + hour_count: number; + id: number; + is_finished: number; + progress: number; + updated_at: string; + user_id: number; + } +} + +export {}; diff --git a/src/store/system/systemConfigSlice.ts b/src/store/system/systemConfigSlice.ts index 0fa2e39..eaae24f 100644 --- a/src/store/system/systemConfigSlice.ts +++ b/src/store/system/systemConfigSlice.ts @@ -1,6 +1,7 @@ import { createSlice } from "@reduxjs/toolkit"; type SystemConfigStoreInterface = { + "ldap-enabled": string; systemApiUrl: string; systemPcUrl: string; systemH5Url: string; @@ -16,6 +17,7 @@ type SystemConfigStoreInterface = { }; let defaultValue: SystemConfigStoreInterface = { + "ldap-enabled": "", systemApiUrl: "", systemPcUrl: "", systemH5Url: "",