feat: sub页 bg
This commit is contained in:
parent
a153137604
commit
a3c17101d6
|
@ -70,9 +70,9 @@ export class CourseController {
|
||||||
const user = await this.userService.select({ user_login });
|
const user = await this.userService.select({ user_login });
|
||||||
// 用户订阅鉴权
|
// 用户订阅鉴权
|
||||||
if (!user.user_sub)
|
if (!user.user_sub)
|
||||||
return { code: BizCode.FORBID, msg: '无权访问订阅课程' };
|
return { code: BizCode.AUTH, msg: '无权访问订阅课程' };
|
||||||
if (+user.user_sub_expired < Date.now())
|
if (+user.user_sub_expired < Date.now())
|
||||||
return { code: BizCode.FORBID, msg: '订阅已过期' };
|
return { code: BizCode.AUTH, msg: '订阅已过期' };
|
||||||
const course = await this.courseService.select({ course_id });
|
const course = await this.courseService.select({ course_id });
|
||||||
const chapterList = await this.chapterService.select(course_id);
|
const chapterList = await this.chapterService.select(course_id);
|
||||||
const guide = await this.guideService.select(course_id);
|
const guide = await this.guideService.select(course_id);
|
||||||
|
|
|
@ -127,7 +127,8 @@ export class UserController {
|
||||||
// 防止接口调用 end
|
// 防止接口调用 end
|
||||||
const code = Math.floor(Math.random() * 9000 + 1000);
|
const code = Math.floor(Math.random() * 9000 + 1000);
|
||||||
await this.redisService.set('' + phoneNumbers, code, 'EX', 60);
|
await this.redisService.set('' + phoneNumbers, code, 'EX', 60);
|
||||||
await this.smsService.send({ code, phoneNumbers });
|
if (process.env.EGG_SERVER_ENV === 'prod')
|
||||||
|
await this.smsService.send({ code, phoneNumbers });
|
||||||
return { code: BizCode.OK };
|
return { code: BizCode.OK };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.ctx.logger.error(error);
|
this.ctx.logger.error(error);
|
||||||
|
|
|
@ -8,7 +8,6 @@ import CaretDown20Filled from "@ricons/fluent/CaretDown20Filled";
|
||||||
import Alert20Regular from "@ricons/fluent/Alert20Regular";
|
import Alert20Regular from "@ricons/fluent/Alert20Regular";
|
||||||
import DoorArrowRight20Regular from "@ricons/fluent/DoorArrowRight20Regular";
|
import DoorArrowRight20Regular from "@ricons/fluent/DoorArrowRight20Regular";
|
||||||
import Settings20Regular from "@ricons/fluent/Settings20Regular";
|
import Settings20Regular from "@ricons/fluent/Settings20Regular";
|
||||||
import PremiumPerson20Regular from "@ricons/fluent/PremiumPerson20Regular";
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useMount } from "../../hook";
|
import { useMount } from "../../hook";
|
||||||
|
|
||||||
|
@ -103,15 +102,6 @@ function Nav() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="main">
|
<div className="main">
|
||||||
{/* <div
|
|
||||||
className="bs fc sb"
|
|
||||||
onClick={() => onClickProfileItem("sub")}
|
|
||||||
>
|
|
||||||
<span>订阅</span>
|
|
||||||
<Icon color="var(--color-text-3)">
|
|
||||||
<PremiumPerson20Regular />
|
|
||||||
</Icon>
|
|
||||||
</div> */}
|
|
||||||
<div className="bs fc sb">
|
<div className="bs fc sb">
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
|
|
|
@ -51,9 +51,7 @@ export default function Result(props: IProps) {
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (props.code) {
|
if (props.code) setView(table[props.code]);
|
||||||
setView(table[props.code]);
|
|
||||||
}
|
|
||||||
}, [props.code]);
|
}, [props.code]);
|
||||||
|
|
||||||
return <>{view}</>;
|
return <>{view}</>;
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import { lazy } from "react";
|
import { lazy } from "react";
|
||||||
import Course from "../view/Course";
|
import Course from "../view/Course";
|
||||||
import CourseDetail from "../view/CourseDetail";
|
|
||||||
import Login from "../view/Login";
|
import Login from "../view/Login";
|
||||||
import Subscribe from "../view/Subscribe";
|
import ResultPage from "../view/ResultPage";
|
||||||
|
|
||||||
export interface IRouteMenuItem {
|
export interface IRouteMenuItem {
|
||||||
path: string;
|
path: string;
|
||||||
|
@ -26,6 +25,12 @@ export const commonRouters: IRoute[] = [
|
||||||
element: <Course />,
|
element: <Course />,
|
||||||
name: "学习",
|
name: "学习",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/result",
|
||||||
|
element: <ResultPage />,
|
||||||
|
name: "Ooops!",
|
||||||
|
invisible: true,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const lazyRouters: IRoute[] = [
|
export const lazyRouters: IRoute[] = [
|
||||||
|
|
|
@ -3,7 +3,7 @@ import "./index.less";
|
||||||
import Guide from "./components/Guide";
|
import Guide from "./components/Guide";
|
||||||
import { useMount } from "../../hook";
|
import { useMount } from "../../hook";
|
||||||
import Player from "./components/DPlayer";
|
import Player from "./components/DPlayer";
|
||||||
import { useParams } from "react-router-dom";
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
import { getCourseDetailById } from "../../api";
|
import { getCourseDetailById } from "../../api";
|
||||||
import { ms2Time } from "./util";
|
import { ms2Time } from "./util";
|
||||||
import Result from "../../components/Result";
|
import Result from "../../components/Result";
|
||||||
|
@ -34,6 +34,7 @@ const defaultState = {
|
||||||
function CourseDetail() {
|
function CourseDetail() {
|
||||||
const { id: course_id = "" } = useParams();
|
const { id: course_id = "" } = useParams();
|
||||||
const [state, setState] = useState<IState>(defaultState);
|
const [state, setState] = useState<IState>(defaultState);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const chapters2toc = (chapterList: IChapter[]) => {
|
const chapters2toc = (chapterList: IChapter[]) => {
|
||||||
return chapterList.map((item) => {
|
return chapterList.map((item) => {
|
||||||
|
@ -93,7 +94,9 @@ function CourseDetail() {
|
||||||
],
|
],
|
||||||
view: <Guide mdText={data?.guide.guide_value} />,
|
view: <Guide mdText={data?.guide.guide_value} />,
|
||||||
});
|
});
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
|
navigate("/result");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -109,51 +112,43 @@ function CourseDetail() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="course-detail">
|
<div className="course-detail">
|
||||||
{state.toc.length > 0 ? (
|
<aside className="table-of-content">
|
||||||
<>
|
<h3>{state.course.course_title}</h3>
|
||||||
<aside className="table-of-content">
|
<div style={{ color: "var(--color-text-3)", fontSize: 13 }}>
|
||||||
<h3>{state.course.course_title}</h3>
|
<span>{state.course.course_createtime}</span>
|
||||||
<div style={{ color: "var(--color-text-3)", fontSize: 13 }}>
|
</div>
|
||||||
<span>{state.course.course_createtime}</span>
|
<div className="toc">
|
||||||
</div>
|
{state.toc.map((i: any) => {
|
||||||
<div className="toc">
|
if (i.level === 1) {
|
||||||
{state.toc.map((i: any) => {
|
return (
|
||||||
if (i.level === 1) {
|
<div className="level-1" key={i.title}>
|
||||||
return (
|
{i.title}
|
||||||
<div className="level-1" key={i.title}>
|
</div>
|
||||||
{i.title}
|
);
|
||||||
</div>
|
} else if (i.level === 2) {
|
||||||
);
|
return (
|
||||||
} else if (i.level === 2) {
|
<div
|
||||||
return (
|
className={`level-2 ${i.active ? "active" : ""}`}
|
||||||
<div
|
key={i.title}
|
||||||
className={`level-2 ${i.active ? "active" : ""}`}
|
onClick={() => onclickItem(i)}
|
||||||
key={i.title}
|
>
|
||||||
onClick={() => onclickItem(i)}
|
<div className="bs fc">
|
||||||
>
|
{i.icon}
|
||||||
<div className="bs fc">
|
<span style={{ padding: "0 12px 0 6px" }}>{i.title}</span>
|
||||||
{i.icon}
|
</div>
|
||||||
<span style={{ padding: "0 12px 0 6px" }}>
|
<span className="time">{i.time}</span>
|
||||||
{i.title}
|
</div>
|
||||||
</span>
|
);
|
||||||
</div>
|
}
|
||||||
<span className="time">{i.time}</span>
|
})}
|
||||||
</div>
|
</div>
|
||||||
);
|
</aside>
|
||||||
}
|
<div
|
||||||
})}
|
className="content"
|
||||||
</div>
|
style={{ left: state.toc.length > 0 ? 300 : "0" }}
|
||||||
</aside>
|
>
|
||||||
<div
|
{state.view}
|
||||||
className="content"
|
</div>
|
||||||
style={{ left: state.toc.length > 0 ? 300 : "0" }}
|
|
||||||
>
|
|
||||||
{state.view}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<Result code={403} />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
7
apps/web/src/view/ResultPage/index.tsx
Normal file
7
apps/web/src/view/ResultPage/index.tsx
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import Result from "../../components/Result";
|
||||||
|
|
||||||
|
const ResultPage = () => {
|
||||||
|
return <Result code={403} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ResultPage;
|
|
@ -17,6 +17,11 @@
|
||||||
// );
|
// );
|
||||||
background: #e9e8e5;
|
background: #e9e8e5;
|
||||||
|
|
||||||
|
.bg {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
}
|
}
|
||||||
|
@ -40,7 +45,7 @@
|
||||||
width: 35%;
|
width: 35%;
|
||||||
height: 120%;
|
height: 120%;
|
||||||
top: -10%;
|
top: -10%;
|
||||||
background: #fff;
|
background: rgba(255, 255, 255, 0.7);
|
||||||
box-shadow: 0 0.75rem 2rem 0 rgba(0, 0, 0, 0.1);
|
box-shadow: 0 0.75rem 2rem 0 rgba(0, 0, 0, 0.1);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
border: 1px solid rgba(255, 255, 255, 0.125);
|
border: 1px solid rgba(255, 255, 255, 0.125);
|
||||||
|
|
|
@ -5,6 +5,39 @@ import "./index.less";
|
||||||
function Subscribe() {
|
function Subscribe() {
|
||||||
return (
|
return (
|
||||||
<div className="subscribe">
|
<div className="subscribe">
|
||||||
|
<svg
|
||||||
|
className="bg"
|
||||||
|
id="svg"
|
||||||
|
viewBox="0 0 1440 690"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="gradient" x1="0%" y1="50%" x2="100%" y2="50%">
|
||||||
|
<stop offset="5%" stop-color="#F78DA7"></stop>
|
||||||
|
<stop offset="95%" stop-color="#8ED1FC"></stop>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<path
|
||||||
|
d="M 0,700 C 0,700 0,233 0,233 C 70.30622009569379,262.2535885167464 140.61244019138758,291.50717703349284 240,292 C 339.3875598086124,292.49282296650716 467.8564593301435,264.22488038277504 565,272 C 662.1435406698565,279.77511961722496 727.9617224880384,323.5933014354068 821,316 C 914.0382775119616,308.4066985645932 1034.2966507177032,249.40191387559807 1142,227 C 1249.7033492822968,204.59808612440193 1344.8516746411483,218.79904306220095 1440,233 C 1440,233 1440,700 1440,700 Z"
|
||||||
|
stroke="none"
|
||||||
|
stroke-width="0"
|
||||||
|
fill="url(#gradient)"
|
||||||
|
fill-opacity="0.53"
|
||||||
|
></path>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="gradient" x1="0%" y1="50%" x2="100%" y2="50%">
|
||||||
|
<stop offset="5%" stop-color="#F78DA7"></stop>
|
||||||
|
<stop offset="95%" stop-color="#8ED1FC"></stop>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<path
|
||||||
|
d="M 0,700 C 0,700 0,466 0,466 C 100.29665071770336,416.0478468899521 200.59330143540672,366.09569377990425 301,394 C 401.4066985645933,421.90430622009575 501.92344497607667,527.665071770335 588,536 C 674.0765550239233,544.334928229665 745.7129186602871,455.244019138756 839,417 C 932.2870813397129,378.755980861244 1047.2248803827752,391.35885167464113 1151,408 C 1254.7751196172248,424.64114832535887 1347.3875598086124,445.32057416267946 1440,466 C 1440,466 1440,700 1440,700 Z"
|
||||||
|
stroke="none"
|
||||||
|
stroke-width="0"
|
||||||
|
fill="url(#gradient)"
|
||||||
|
fill-opacity="1"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<h2>订阅</h2>
|
<h2>订阅</h2>
|
||||||
<h4>订阅后,全站免费,无任何其他附加收费</h4>
|
<h4>订阅后,全站免费,无任何其他附加收费</h4>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user