From 24b8b4c91d7a7f84c2ea669034dd35d548c32bc9 Mon Sep 17 00:00:00 2001 From: mozzie Date: Mon, 13 Mar 2023 16:52:27 +0800 Subject: [PATCH] feat: index --- apps/server/package.json | 3 +- apps/server/src/controller/api.controller.ts | 17 ----- apps/server/src/controller/home.controller.ts | 33 --------- apps/server/src/controller/user.controller.ts | 39 +++++++++++ apps/server/src/dto/user.dto.ts | 14 ++-- apps/server/src/entity/user.entity.ts | 32 ++++++++- apps/server/src/service/user.service.ts | 28 +++++--- apps/web/package.json | 6 +- apps/web/src/api/dto.ts | 4 ++ apps/web/src/api/index.ts | 4 ++ apps/web/src/components/Footer/index.less | 4 ++ apps/web/src/components/Footer/index.tsx | 12 ++++ apps/web/src/components/Nav/index.less | 4 +- apps/web/src/components/Nav/index.tsx | 68 ++++++++++++------- apps/web/src/router/Guard.tsx | 17 ++++- apps/web/src/view/Course/index.tsx | 2 + .../CourseDetail/components/Guide/index.tsx | 9 ++- pnpm-lock.yaml | 33 +++++++++ 18 files changed, 225 insertions(+), 104 deletions(-) delete mode 100644 apps/server/src/controller/api.controller.ts delete mode 100644 apps/server/src/controller/home.controller.ts create mode 100644 apps/server/src/controller/user.controller.ts create mode 100644 apps/web/src/api/dto.ts create mode 100644 apps/web/src/components/Footer/index.less create mode 100644 apps/web/src/components/Footer/index.tsx diff --git a/apps/server/package.json b/apps/server/package.json index 3bd8e22..7ce1a0b 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -25,7 +25,8 @@ "dotenv": "16.0.3", "jsonwebtoken": "9.0.0", "tencentcloud-sdk-nodejs": "4.0.552", - "vod-node-sdk": "1.1.0" + "vod-node-sdk": "1.1.0", + "chinese-random-name": "2.0.0" }, "devDependencies": { "@midwayjs/cli": "^2.0.0", diff --git a/apps/server/src/controller/api.controller.ts b/apps/server/src/controller/api.controller.ts deleted file mode 100644 index 5063c5f..0000000 --- a/apps/server/src/controller/api.controller.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Inject, Controller, Post, Body } from '@midwayjs/core'; -import { Context } from '@midwayjs/koa'; -import { Validate } from '@midwayjs/validate'; -import { UserDTO } from '../dto/user.dto'; -@Controller('/') -export class APIController { - @Inject() - ctx: Context; - - @Post('/get_user') - @Validate({ - errorStatus: 422, - }) - async getUser(@Body() user: UserDTO) { - return { success: true, message: 'OK', data: user }; - } -} diff --git a/apps/server/src/controller/home.controller.ts b/apps/server/src/controller/home.controller.ts deleted file mode 100644 index 31c0512..0000000 --- a/apps/server/src/controller/home.controller.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Controller, Get, Inject } from '@midwayjs/core'; -import { InjectEntityModel } from '@midwayjs/typeorm'; -import { Context } from '@midwayjs/koa'; -import { Photo } from '../entity/photo.entity'; -import { Repository } from 'typeorm'; - -@Controller('/') -export class HomeController { - @Inject() - ctx: Context; - - @InjectEntityModel(Photo) - photoModel: Repository; - - @Get('/testMysql') - async testMysql() { - // create a entity object - let photo = new Photo(); - photo.name = 'Me and Bears'; - photo.description = 'I am near polar bears'; - photo.filename = 'photo-with-bears.jpg'; - photo.views = 1; - photo.isPublished = true; - - // save entity - const photoResult = await this.photoModel.save(photo); - - // save success - console.log('photo id = ', photoResult.id); - - this.ctx.body = photoResult.id; - } -} diff --git a/apps/server/src/controller/user.controller.ts b/apps/server/src/controller/user.controller.ts new file mode 100644 index 0000000..76a4e68 --- /dev/null +++ b/apps/server/src/controller/user.controller.ts @@ -0,0 +1,39 @@ +import { Body, Context, Controller, Inject, Post } from '@midwayjs/core'; +import { BizCode } from '../biz/code'; +import { UserWebAuthDTO } from '../dto/user.dto'; +import { UserService } from '../service/user.service'; +import { md5 } from '../util/encrypt'; + +@Controller('/user') +export class UserController { + @Inject() + ctx: Context; + + @Inject() + userService: UserService; + + @Post('/web/auth') + async webAuth(@Body() params: UserWebAuthDTO) { + try { + const userExist = await this.userService.select(params); + if (userExist?.id) { + const { user_pass, ...rest } = userExist; + const passValid = userExist.user_pass === md5(params.user_pass); + return passValid + ? { code: BizCode.OK, msg: '欢迎回来', data: { ...rest } } + : { code: BizCode.ERROR, msg: '密码错误' }; + } else { + const createUser = await this.userService.save(params); + const { user_pass, ...rest } = createUser; + return { + code: BizCode.OK, + data: { ...rest }, + msg: '欢迎来到 backset.cn', + }; + } + } catch (error) { + this.ctx.logger.error(error); + return { code: BizCode.ERROR, msg: '[error] web/auth error' }; + } + } +} diff --git a/apps/server/src/dto/user.dto.ts b/apps/server/src/dto/user.dto.ts index 8899560..bbe80c0 100644 --- a/apps/server/src/dto/user.dto.ts +++ b/apps/server/src/dto/user.dto.ts @@ -1,16 +1,10 @@ // src/dto/user.ts import { Rule, RuleType } from '@midwayjs/validate'; -export class UserDTO { - @Rule(RuleType.number().required()) - id: number; +export class UserWebAuthDTO { + @Rule(RuleType.string().required()) + user_login: string; @Rule(RuleType.string().required()) - firstName: string; - - @Rule(RuleType.string().max(10)) - lastName: string; - - @Rule(RuleType.number().max(60)) - age: number; + user_pass: string; } diff --git a/apps/server/src/entity/user.entity.ts b/apps/server/src/entity/user.entity.ts index 359097d..808e9b8 100644 --- a/apps/server/src/entity/user.entity.ts +++ b/apps/server/src/entity/user.entity.ts @@ -1,3 +1,29 @@ -export class User{ - -} \ No newline at end of file +import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm'; +const randomName = require('chinese-random-name'); + +@Entity('user') +export class User { + @PrimaryGeneratedColumn('increment') + id?: number; + + @Column({ unique: true }) + user_login?: string; + + @Column() + user_pass?: string; + + @Column({ unique: true, default: '' }) + user_phone?: string; + + @Column({ default: '', unique: true }) + user_email?: string; + + @Column({ default: Date.now() }) + user_create_time?: string; + + @Column({ default: true }) + user_status?: boolean; + + @Column({ default: randomName.generate() }) + display_name?: string; +} diff --git a/apps/server/src/service/user.service.ts b/apps/server/src/service/user.service.ts index 1dce594..50a1901 100644 --- a/apps/server/src/service/user.service.ts +++ b/apps/server/src/service/user.service.ts @@ -1,14 +1,26 @@ import { Provide } from '@midwayjs/core'; -import { IUserOptions } from '../interface'; +import { InjectEntityModel } from '@midwayjs/typeorm'; +import { Repository } from 'typeorm'; +import { UserWebAuthDTO } from '../dto/user.dto'; +import { User } from '../entity/user.entity'; +import { md5 } from '../util/encrypt'; @Provide() export class UserService { - async getUser(options: IUserOptions) { - return { - uid: options.uid, - username: 'mockedName', - phone: '12345678901', - email: 'xxx.xxx@xxx.com', - }; + @InjectEntityModel(User) + userModel: Repository; + + async select(p: UserWebAuthDTO): Promise { + const { user_login } = p; + const user = await this.userModel.findOne({ + where: [{ user_phone: user_login }, { user_login }], + }); + return user; + } + + async save(user: User) { + user.user_pass = md5(user.user_pass); + const result = await this.userModel.save(user); + return result; } } diff --git a/apps/web/package.json b/apps/web/package.json index c6912fa..ce90506 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -17,7 +17,8 @@ "@ricons/fluent": "0.12.0", "@ricons/utils": "0.1.6", "dplayer": "1.27.1", - "highlight.js": "11.7.0" + "highlight.js": "11.7.0", + "js-cookie": "3.0.1" }, "devDependencies": { "@types/react": "^18.0.27", @@ -27,6 +28,7 @@ "vite-tsconfig-paths": "4.0.5", "typescript": "^4.9.3", "vite": "^4.1.0", - "@types/dplayer": "1.25.2" + "@types/dplayer": "1.25.2", + "@types/js-cookie": "3.0.3" } } \ No newline at end of file diff --git a/apps/web/src/api/dto.ts b/apps/web/src/api/dto.ts new file mode 100644 index 0000000..c293b88 --- /dev/null +++ b/apps/web/src/api/dto.ts @@ -0,0 +1,4 @@ +export interface ILoginRequest { + user_login: string; + user_pass: string; +} diff --git a/apps/web/src/api/index.ts b/apps/web/src/api/index.ts index f3602a2..5148dc8 100644 --- a/apps/web/src/api/index.ts +++ b/apps/web/src/api/index.ts @@ -1,6 +1,10 @@ +import { ILoginRequest } from "./dto"; import R from "./request"; export const getCourseList = () => R.post("/api/course/select/all"); export const getChapterGuideById = (course_id: string) => R.post("/api/course/chapter/select", { course_id }); + +export const userLogin = (p: ILoginRequest) => + R.post("/api/user/web/auth", { ...p }); diff --git a/apps/web/src/components/Footer/index.less b/apps/web/src/components/Footer/index.less new file mode 100644 index 0000000..f1e8674 --- /dev/null +++ b/apps/web/src/components/Footer/index.less @@ -0,0 +1,4 @@ +.main-footer { + padding-bottom: 20px; + text-align: center; +} diff --git a/apps/web/src/components/Footer/index.tsx b/apps/web/src/components/Footer/index.tsx new file mode 100644 index 0000000..2e1ec2a --- /dev/null +++ b/apps/web/src/components/Footer/index.tsx @@ -0,0 +1,12 @@ +import "./index.less"; + +export const Footer = () => { + return ( + + ); +}; diff --git a/apps/web/src/components/Nav/index.less b/apps/web/src/components/Nav/index.less index 829e734..ab6d866 100644 --- a/apps/web/src/components/Nav/index.less +++ b/apps/web/src/components/Nav/index.less @@ -196,7 +196,7 @@ header { } } - .login-pass { + .login-qrcode { position: absolute; top: 20%; left: 0; @@ -245,8 +245,6 @@ header { .form-holder { border-radius: 8px; - background-color: #fff; - border: 1px solid #eee; overflow: hidden; margin-top: 50px; opacity: 1; diff --git a/apps/web/src/components/Nav/index.tsx b/apps/web/src/components/Nav/index.tsx index 83c152b..507594e 100644 --- a/apps/web/src/components/Nav/index.tsx +++ b/apps/web/src/components/Nav/index.tsx @@ -14,16 +14,21 @@ import { const InputSearch = Input.Search; const RadioGroup = Radio.Group; import { useEffect, useRef, useState } from "react"; +import { userLogin } from "../../api"; -type TLoginMethod = "usePass" | "useSms"; +const defaultForm = { + user_login: "", + user_pass: "", +}; + +type TLoginMethod = "useQRCode" | "useSms"; const DURATION = 3; // 验证码倒计时 function Nav() { const navigate = useNavigate(); - const [loginForm] = Form.useForm(); + const [smsLoginForm, setSmsLoginForm] = useState(defaultForm); const [visible, setVisible] = useState(false); - const [confirmLoading, setConfirmLoading] = useState(false); const [loginMethod, setLoginMethod] = useState("useSms"); let [countdown, setCountdown] = useState(DURATION); const timer = useRef(); @@ -35,6 +40,17 @@ function Nav() { }, 500); }; + const onClickSmsLogin = () => { + userLogin(smsLoginForm).then((res: any) => { + const { code, data, msg } = res; + if (code === 10000) { + Message.success(msg); + console.log(data); + } + if (code === 20000) Message.error(msg); + }); + }; + useEffect(() => { if (countdown === 0) { clearInterval(timer.current); @@ -75,7 +91,6 @@ function Nav() { visible={visible} closeIcon={false} footer={null} - confirmLoading={confirmLoading} onCancel={() => setVisible(false)} >
@@ -94,12 +109,24 @@ function Nav() { + setSmsLoginForm((p) => ({ + ...p, + user_login: e.target.value, + })) + } />
+ setSmsLoginForm((p) => ({ + ...p, + user_pass: e.target.value, + })) + } placeholder="验证码" >
- + - {/* 密码 */} + {/* 扫码 */}

setLoginMethod("usePass")} + // onClick={() => setLoginMethod("useQRCode")} + onClick={() => Message.info("开发中... 😀 ")} > - 密码登录 + 扫码登录

-
- - -
- +
开发中……
diff --git a/apps/web/src/router/Guard.tsx b/apps/web/src/router/Guard.tsx index 8792003..d4618de 100644 --- a/apps/web/src/router/Guard.tsx +++ b/apps/web/src/router/Guard.tsx @@ -1,16 +1,31 @@ -import React, { useEffect } from "react"; +import { Button, Result } from "@arco-design/web-react"; +import { useEffect } from "react"; import { useLocation } from "react-router-dom"; +import Cookies from "js-cookie"; interface IGuardProps { children: JSX.Element; } +const needAuthList = ["course/detail"]; + export const Guard = (props: IGuardProps) => { const location = useLocation(); + const sessionExist = !!Cookies.get("_session"); + const needAuth = needAuthList.some((p) => location.pathname.indexOf(p) > -1); useEffect(() => { console.log("location.pathname changed 拦截", location.pathname); + if (location.pathname.indexOf("course/detail/") > -1) { + console.log("进入课程详情页"); + } }, [location.pathname]); + if (needAuth && !sessionExist) + return ( +
+ +
+ ); return props.children; }; diff --git a/apps/web/src/view/Course/index.tsx b/apps/web/src/view/Course/index.tsx index 503cea8..28ddb39 100644 --- a/apps/web/src/view/Course/index.tsx +++ b/apps/web/src/view/Course/index.tsx @@ -12,6 +12,7 @@ import { useNavigate } from "react-router-dom"; import { useMount } from "../../hook"; import { getCourseList } from "../../api"; import { processTime } from "./util"; +import { Footer } from "../../components/Footer"; export default function Index() { const navigate = useNavigate(); @@ -151,6 +152,7 @@ export default function Index() { model={{ top: timeline.top }} /> +