feat: finish login page

This commit is contained in:
hanachan
2025-04-27 23:12:35 +08:00
committed by Junyan Qin
parent af8f07218a
commit 7bfe8b3f5b
4 changed files with 123 additions and 45 deletions

View File

@@ -46,8 +46,8 @@ export interface LLMModel {
extra_args: object;
api_keys: string[];
abilities: string[];
created_at: string;
updated_at: string;
// created_at: string;
// updated_at: string;
}
export interface ApiRespPipelines {

View File

@@ -62,7 +62,7 @@ class HttpClient {
// 同步获取Session
private getSessionSync() {
// NOT IMPLEMENT
return "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoicm9ja2NoaW5xQGdtYWlsLmNvbSIsImlzcyI6IkxhbmdCb3QtY29tbXVuaXR5IiwiZXhwIjoyMzUwNDk1NTQ3fQ.d6r0lNGud1OecOLMM-ADDDwiABmek3hkMIFH7ZBkaX4"
return localStorage.getItem("token")
}
// 拦截器配置
@@ -323,7 +323,7 @@ class HttpClient {
}
// ============ User API ============
public checkIfInited(): Promise<object> {
public checkIfInited(): Promise<{initialized: boolean}> {
return this.get('/api/v1/user/init')
}
@@ -340,4 +340,4 @@ class HttpClient {
}
}
export const httpClient = new HttpClient()
export const httpClient = new HttpClient("https://version-4.langbot.dev")

View File

@@ -9,7 +9,7 @@
.login {
display: flex;
width: 80%;
width: 30%;
height: 80vh;
background-color: white;
border-radius: 16px;
@@ -26,14 +26,6 @@
padding: 2rem;
}
.right {
flex: 1.5;
background-color: #f9f9f9;
position: relative;
overflow: hidden;
border-top-right-radius: 16px;
border-bottom-right-radius: 16px;
}
.loginForm {
width: 100%;
@@ -76,6 +68,10 @@
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
.forgetPassword {
margin-right: 1rem;
}
}
/* 修改Logo样式调整位置确保正确对齐 */

View File

@@ -1,12 +1,62 @@
'use client';
import { Button, Input, Form, Checkbox, Divider } from 'antd';
import { GoogleOutlined, AppleOutlined, LockOutlined, UserOutlined } from '@ant-design/icons';
import {GoogleOutlined, AppleOutlined, LockOutlined, UserOutlined, QqCircleFilled, QqOutlined} from '@ant-design/icons';
import styles from './login.module.css';
import { useState } from 'react';
import {useEffect, useState} from 'react';
import {httpClient} from "@/app/infra/http/HttpClient";
import '@ant-design/v5-patch-for-react-19';
import {useRouter} from "next/navigation";
export default function Home() {
const [form] = Form.useForm();
const router = useRouter();
const [form] = Form.useForm<LoginField>();
const [rememberMe, setRememberMe] = useState(false);
const [isRegisterMode, setIsRegisterMode] = useState(false);
const [isInitialized, setIsInitialized] = useState(false)
useEffect(() => {
getIsInitialized()
}, [])
// 检查是否为首次启动项目,只为首次启动的用户提供注册资格
function getIsInitialized() {
httpClient.checkIfInited().then(res => {
setIsInitialized(res.initialized)
}).catch(err => {
console.log("error at getIsInitialized: ", err)
})
}
function handleFormSubmit(formField: LoginField) {
if (isRegisterMode) {
handleRegister(formField.email, formField.password);
} else {
handleLogin(formField.email, formField.password)
}
}
function handleRegister(username: string, password: string) {
httpClient.initUser(username, password).then(res => {
console.log("init user success: ", res)
}).catch(err => {
console.log("init user error: ", err)
})
}
function handleLogin(username: string, password: string) {
httpClient.authUser(username, password).then(res => {
localStorage.setItem("token", res.token)
console.log("login success: ", res)
router.push("/home")
}).catch(err => {
console.log("login error: ", err)
})
}
return (
// 使用 Ant Design 的组件库,使用 antd 的样式
@@ -18,8 +68,21 @@ export default function Home() {
{/* left 为注册的表单,需要填入的内容有:邮箱,密码 */}
<div className={styles.left}>
<div className={styles.loginForm}>
<h1 className={styles.title}></h1>
<Form form={form} layout="vertical">
{
isRegisterMode &&
<h1 className={styles.title}> LangBot </h1>
}
{
!isRegisterMode &&
<h1 className={styles.title}> LangBot</h1>
}
<Form
form={form}
layout="vertical"
onFinish={(values) => {
handleFormSubmit(values)
}}
>
<Form.Item
name="email"
rules={[
@@ -54,13 +117,46 @@ export default function Home() {
>
30
</Checkbox>
<a href="#">?</a>
<span>
<a href="#" className={`${styles.forgetPassword}`}>?</a>
{
!isRegisterMode &&
<a href=""
onClick={(event) => {
setIsRegisterMode(true)
event.preventDefault()
}}
></a>
}
{
isRegisterMode &&
<a href=""
onClick={(event) => {
setIsRegisterMode(false)
event.preventDefault()
}}
></a>
}
</span>
</div>
<Button type="primary" size="large" className={styles.loginButton} block>
<Button
type="primary"
size="large"
className={styles.loginButton}
block
htmlType="submit"
disabled={isRegisterMode && isInitialized}
>
{
isRegisterMode ? (
isInitialized ? "暂不提供注册" : "注册"
) : "登录"
}
</Button>
<Divider className={styles.divider}></Divider>
<div className={styles.socialLogin}>
@@ -68,6 +164,7 @@ export default function Home() {
className={styles.socialButton}
icon={<GoogleOutlined />}
size="large"
disabled={true}
>
使
</Button>
@@ -76,37 +173,22 @@ export default function Home() {
<div className={styles.socialLogin}>
<Button
className={styles.socialButton}
icon={<AppleOutlined />}
icon={<QqOutlined />}
size="large"
disabled={true}
>
使
使QQ账号登
</Button>
</div>
</Form>
</div>
</div>
{/* right 为左侧布局,显示的是应用截图,测试阶段使用 picsum.photos 代替 */}
<div className={styles.right}>
<img
src="https://picsum.photos/800/1000"
alt="应用预览"
style={{
width: '100%',
height: '100%',
objectFit: 'cover',
objectPosition: 'left center'
}}
/>
{/* 在右上角添加logo */}
<div className={styles.logoContainer}>
<img
src="https://picsum.photos/100/100"
alt="Logo"
className={styles.logo}
/>
</div>
</div>
</div>
</div>
);
}
interface LoginField {
email: string;
password: string;
}