Browse Source
Merge remote-tracking branch 'origin/main'
Merge remote-tracking branch 'origin/main'
# Conflicts: # src/pages/use/login/index.tsxmain
lk
2 months ago
7 changed files with 446 additions and 242 deletions
-
1package.json
-
163src/components/captcha/SlideCapt.tsx
-
2src/components/captcha/index.ts
-
18src/components/captcha/style.ts
-
6src/components/captcha/types.ts
-
445src/pages/use/login/index.tsx
-
53src/service/system.ts
@ -0,0 +1,163 @@ |
|||
import React, { forwardRef, memo, useCallback, useEffect, useState, useImperativeHandle } from 'react' |
|||
import { Popover, message } from 'antd' |
|||
import GoCaptcha from 'go-captcha-react' |
|||
import { SlideCaptchaCheckData } from './types.ts' |
|||
import { SlideData, SlidePoint } from 'go-captcha-react/dist/components/Slide/meta/data' |
|||
import { SlideConfig } from 'go-captcha-react/dist/components/Slide/meta/config' |
|||
import { Props } from 'go-captcha-react/dist/components/Button' |
|||
import { useStyle } from './style.ts' |
|||
|
|||
export interface SlideCaptProps { |
|||
api: { |
|||
getCaptcha: () => Promise<any>, |
|||
checkCaptcha: (params: SlideCaptchaCheckData) => Promise<any>, |
|||
}, |
|||
config?: SlideConfig |
|||
value?: string |
|||
onChange?: (value?: string) => void |
|||
} |
|||
|
|||
export type SlideCaptRef = { |
|||
reset: () => void |
|||
} |
|||
|
|||
|
|||
const SlideCapt = forwardRef<SlideCaptRef | undefined, SlideCaptProps>(( |
|||
{ |
|||
config, |
|||
api, |
|||
value, |
|||
onChange, |
|||
}: SlideCaptProps, ref) => { |
|||
|
|||
const { styles } = useStyle() |
|||
const [ open, setOpen ] = useState(false) |
|||
const [ state, setState ] = useState<Props>({}) |
|||
const [ data, setData ] = useState<SlideData>() |
|||
const [ innerKey, setKey ] = useState(value) |
|||
|
|||
const fetchCaptcha = useCallback(() => { |
|||
|
|||
return api.getCaptcha().then(res => { |
|||
if (res.code === 0) { |
|||
const data = res.data |
|||
setKey(data['captcha_key'] || '') |
|||
setData({ |
|||
image: data['image_base64'] || '', |
|||
thumb: data['tile_base64'] || '', |
|||
thumbX: data['tile_x'] || 0, |
|||
thumbY: data['tile_y'] || 0, |
|||
thumbWidth: data['tile_width'] || 0, |
|||
thumbHeight: data['tile_height'] || 0, |
|||
}) |
|||
} |
|||
|
|||
}) |
|||
|
|||
|
|||
}, [ api.getCaptcha, setData ]) |
|||
|
|||
const refresh = useCallback(() => { |
|||
fetchCaptcha() |
|||
}, [ fetchCaptcha ]) |
|||
|
|||
const confirm = useCallback((point: SlidePoint, clear: (fn?: any) => void) => { |
|||
|
|||
api.checkCaptcha({ |
|||
point: [ point.x, point.y ].join(','), |
|||
key: innerKey! |
|||
}).then(res => { |
|||
// console.log(res)
|
|||
if (res.code === 0 && res.data.is_ok) { |
|||
message.success(`验证成功`) |
|||
|
|||
//验证成功,onChange通知出去,外部需要key做为校验
|
|||
onChange?.(innerKey) |
|||
|
|||
setState(prevState => ({ |
|||
...prevState, type: 'success', title: '校验成功', |
|||
})) |
|||
setOpen(false) |
|||
} else { |
|||
message.error('验证失败') |
|||
setState(prevState => ({ |
|||
...prevState, type: 'error', title: '点击进行校验', |
|||
})) |
|||
} |
|||
setTimeout(() => { |
|||
clear() |
|||
fetchCaptcha() |
|||
}, 1000) |
|||
|
|||
}).catch(() => { |
|||
setTimeout(() => { |
|||
clear() |
|||
fetchCaptcha() |
|||
}, 1000) |
|||
}) |
|||
|
|||
}, [ api.checkCaptcha, setData, state, setState, setOpen, innerKey, onChange, fetchCaptcha ]) |
|||
|
|||
useImperativeHandle(ref, () => { |
|||
return { |
|||
reset() { |
|||
setState(prevState => ({ |
|||
...prevState, type: 'default', title: '点击进行校验', |
|||
})) |
|||
setKey(undefined) |
|||
onChange?.(undefined) |
|||
refresh() |
|||
} |
|||
} |
|||
}, [ fetchCaptcha, setState, setKey ]) |
|||
|
|||
useEffect(() => { |
|||
|
|||
if (open) { |
|||
fetchCaptcha() |
|||
} |
|||
|
|||
}, [ open ]) |
|||
|
|||
return ( |
|||
<div className={styles.container}> |
|||
<Popover |
|||
content={ |
|||
<GoCaptcha.Slide |
|||
config={{ |
|||
width: 300, |
|||
height: 217, |
|||
showTheme: false, |
|||
verticalPadding: 5, |
|||
horizontalPadding: 5, |
|||
...config, |
|||
}} |
|||
style={{ color: 'red' }} |
|||
data={data!} |
|||
events={{ |
|||
refresh, |
|||
confirm, |
|||
close: () => { |
|||
setOpen(false) |
|||
} |
|||
}} |
|||
/> |
|||
} |
|||
open={open} |
|||
onOpenChange={setOpen} |
|||
forceRender={true} |
|||
trigger="click"> |
|||
<GoCaptcha.Button |
|||
title={'点击进行校验'} |
|||
{...state} |
|||
clickEvent={ |
|||
() => { |
|||
setOpen(true) |
|||
} |
|||
}/> |
|||
</Popover> |
|||
</div> |
|||
) |
|||
}) |
|||
|
|||
export default memo(SlideCapt) |
@ -0,0 +1,2 @@ |
|||
|
|||
export * from './SlideCapt.tsx' |
@ -0,0 +1,18 @@ |
|||
|
|||
import { createStyles } from '@/theme' |
|||
|
|||
export const useStyle = createStyles(({ token, css, cx, prefixCls }, props: any) => { |
|||
const prefix = `${prefixCls}-${token?.proPrefix}-captcha-component` |
|||
|
|||
const container = css`
|
|||
|
|||
> div{ |
|||
width: 100% !important; |
|||
} |
|||
|
|||
`
|
|||
|
|||
return { |
|||
container: cx(prefix, props?.className, container), |
|||
} |
|||
}) |
@ -0,0 +1,6 @@ |
|||
|
|||
|
|||
export interface SlideCaptchaCheckData { |
|||
point: string |
|||
key: string |
|||
} |
@ -1,254 +1,261 @@ |
|||
import { Layout, Tabs, Input, Button, Typography, Row, Col, Form } from "antd"; |
|||
import { UserOutlined, LockOutlined } from "@ant-design/icons"; |
|||
import { createFileRoute, useNavigate } from "@tanstack/react-router"; |
|||
import { useAtomValue } from "jotai"; |
|||
import { emailLoginAtom, telegramLoginAtom, upLoginAtom } from "@/store/system/user.ts"; |
|||
import React, { memo, useEffect, useLayoutEffect, useState } from "react"; |
|||
import systemServ from "@/service/system.ts"; |
|||
import { t } from "i18next"; |
|||
const { Title, Text, Link } = Typography; |
|||
const { TabPane } = Tabs; |
|||
|
|||
const i18nPrefix = "login"; |
|||
import { Layout, Tabs, Input, Button, Typography, Row, Col, Form } from 'antd' |
|||
import { QrcodeOutlined, UserOutlined, LockOutlined } from '@ant-design/icons' |
|||
import SelectLang from '@/components/select-lang' |
|||
import { createFileRoute, useNavigate } from '@tanstack/react-router' |
|||
import { useAtom, useAtomValue } from 'jotai' |
|||
import { useTranslation } from '@/i18n.ts' |
|||
import { |
|||
emailCodeAtom, |
|||
emailLoginAtom, |
|||
telegramCodeAtom, |
|||
telegramLoginAtom, |
|||
upLoginAtom, |
|||
} from '@/store/system/user.ts' |
|||
import React, { memo, useEffect, useLayoutEffect, useRef, useState } from 'react' |
|||
import systemServ from '@/service/system.ts' |
|||
import SlideCapt, { SlideCaptRef } from '@/components/captcha/SlideCapt.tsx' |
|||
|
|||
const { Title, Text, Link } = Typography |
|||
const { TabPane } = Tabs |
|||
|
|||
const Login = memo(() => { |
|||
const languageSet = { |
|||
邮箱密码登录: t(`${i18nPrefix}.emailPasswordLogin`, "邮箱密码登录"), |
|||
向量检索服务免费试用: t(`${i18nPrefix}.vectorRetrievalServiceFreeTrial`, "向量检索服务免费试用"), |
|||
免费试用向量检索服务玩转大模型生成式检索: t( |
|||
`${i18nPrefix}.freeTrialVectorRetrievalService`, |
|||
"免费试用向量检索服务,玩转大模型生成式检索", |
|||
), |
|||
查看详情: t(`${i18nPrefix}.viewDetails`, "查看详情 >"), |
|||
请输入邮箱: t(`${i18nPrefix}.pleaseEnterEmail`, "请输入邮箱"), |
|||
请输入登录密码: t(`${i18nPrefix}.pleaseEnterPassword`, "请输入登录密码"), |
|||
登录: t(`${i18nPrefix}.login`, "登录"), |
|||
邮箱验证登录: t(`${i18nPrefix}.emailVerificationLogin`, "邮箱验证登录"), |
|||
获得验证码: t(`${i18nPrefix}.getVerificationCode`, "获得验证码"), |
|||
请输入验证码: t(`${i18nPrefix}.pleaseEnterVerificationCode`, "请输入验证码"), |
|||
飞机验证登录: t(`${i18nPrefix}.telegramVerificationLogin`, "飞机验证登录"), |
|||
获得飞机验证码: t(`${i18nPrefix}.getTelegramVerificationCode`, "获得飞机验证码"), |
|||
请输入飞机验证码: t(`${i18nPrefix}.pleaseEnterTelegramVerificationCode`, "请输入飞机验证码"), |
|||
注册: t(`${i18nPrefix}.register`, "注册"), |
|||
忘记密码: t(`${i18nPrefix}.forgotPassword`, "忘记密码"), |
|||
}; |
|||
|
|||
const navigate = useNavigate(); |
|||
const [upform] = Form.useForm(); |
|||
const [emailform] = Form.useForm(); |
|||
const [telegramform] = Form.useForm(); |
|||
const { mutate: upLoginFun } = useAtomValue(upLoginAtom); |
|||
const [emailCodeData, setEmailCodeData] = useState({}); |
|||
const { mutate: emailLoginMutate } = useAtomValue(emailLoginAtom); |
|||
const { mutate: telegramLoginMutate } = useAtomValue(telegramLoginAtom); |
|||
const navigate = useNavigate() |
|||
const [ upform ] = Form.useForm() |
|||
const [ emailform ] = Form.useForm() |
|||
const [ telegramform ] = Form.useForm() |
|||
const { mutate: upLoginFun } = useAtomValue(upLoginAtom) |
|||
const [ emailCodeData, setEmailCodeData ] = useState({}) |
|||
const { mutate: emailLoginMutate } = useAtomValue(emailLoginAtom) |
|||
const { mutate: telegramLoginMutate } = useAtomValue(telegramLoginAtom) |
|||
|
|||
const slideCaptRef = useRef<SlideCaptRef>() |
|||
|
|||
const uphandleSubmit = (values: any) => { |
|||
console.log(values); |
|||
upLoginFun(values); |
|||
}; |
|||
console.log(values) |
|||
upLoginFun(values) |
|||
} |
|||
|
|||
const getEmailCode = async () => { |
|||
const email = emailform.getFieldValue("email"); |
|||
const result = await systemServ.emailCode({ is_register: false, email }); |
|||
setEmailCodeData(result); |
|||
}; |
|||
const email = emailform.getFieldValue('email') |
|||
const result = await systemServ.emailCode({ is_register: false, email }) |
|||
setEmailCodeData(result) |
|||
} |
|||
const emailhandleSubmit = (values: any) => { |
|||
emailLoginMutate(values); |
|||
}; |
|||
emailLoginMutate(values) |
|||
} |
|||
|
|||
const getTelegramCode = async () => { |
|||
const telegram = telegramform.getFieldValue("telegram"); |
|||
const result = await systemServ.telegramCode({ telegram }); |
|||
setEmailCodeData(result); |
|||
}; |
|||
const telegram = telegramform.getFieldValue('telegram') |
|||
const result = await systemServ.telegramCode({ telegram }) |
|||
setEmailCodeData(result) |
|||
} |
|||
const telegramhandleSubmit = (values: any) => { |
|||
telegramLoginMutate(values); |
|||
}; |
|||
telegramLoginMutate(values) |
|||
} |
|||
|
|||
const [countdown, setCountdown] = useState<number>(() => { |
|||
const savedCountdown = localStorage.getItem("countdown"); |
|||
return savedCountdown !== null ? Number(savedCountdown) : 0; |
|||
}); |
|||
const [ countdown, setCountdown ] = useState<number>(() => { |
|||
const savedCountdown = localStorage.getItem('countdown') |
|||
return savedCountdown !== null ? Number(savedCountdown) : 0 |
|||
}) |
|||
|
|||
const [isButtonDisabled, setIsButtonDisabled] = useState<boolean>(() => { |
|||
const savedIsButtonDisabled = localStorage.getItem("isButtonDisabled"); |
|||
return savedIsButtonDisabled !== null ? JSON.parse(savedIsButtonDisabled) : false; |
|||
}); |
|||
const [ isButtonDisabled, setIsButtonDisabled ] = useState<boolean>(() => { |
|||
const savedIsButtonDisabled = localStorage.getItem('isButtonDisabled') |
|||
return savedIsButtonDisabled !== null ? JSON.parse(savedIsButtonDisabled) : false |
|||
}) |
|||
|
|||
useEffect(() => { |
|||
localStorage.setItem("isButtonDisabled", JSON.stringify(isButtonDisabled)); |
|||
}, [isButtonDisabled]); |
|||
localStorage.setItem('isButtonDisabled', JSON.stringify(isButtonDisabled)) |
|||
}, [ isButtonDisabled ]) |
|||
|
|||
useEffect(() => { |
|||
if ((emailCodeData as any)?.code === 0) { |
|||
setCountdown(10); |
|||
setIsButtonDisabled(true); |
|||
setCountdown(10) |
|||
setIsButtonDisabled(true) |
|||
} |
|||
}, [emailCodeData]); |
|||
}, [ emailCodeData ]) |
|||
|
|||
useEffect(() => { |
|||
let timer: number; |
|||
let timer: number |
|||
if (countdown > 0) { |
|||
timer = setTimeout(() => setCountdown(countdown - 1), 1000); |
|||
timer = setTimeout(() => setCountdown(countdown - 1), 1000) |
|||
} else { |
|||
setIsButtonDisabled(false); |
|||
setIsButtonDisabled(false) |
|||
} |
|||
localStorage.setItem("countdown", String(countdown)); |
|||
return () => clearTimeout(timer); |
|||
}, [countdown]); |
|||
localStorage.setItem('countdown', String(countdown)) |
|||
return () => clearTimeout(timer) |
|||
}, [ countdown ]) |
|||
|
|||
useLayoutEffect(() => { |
|||
document.body.className = "login"; |
|||
document.body.className = 'login' |
|||
return () => { |
|||
document.body.className = document.body.className.replace("login", ""); |
|||
}; |
|||
}, []); |
|||
document.body.className = document.body.className.replace('login', '') |
|||
} |
|||
}, []) |
|||
|
|||
return ( |
|||
<Layout |
|||
style={{ |
|||
height: "100vh", |
|||
background: "url('https://placehold.co/1920x1080') no-repeat center center", |
|||
backgroundSize: "cover", |
|||
}} |
|||
> |
|||
<Row justify="center" align="middle" style={{ height: "100%" }}> |
|||
<Col> |
|||
<Row> |
|||
<Col span={12} style={{ padding: "20px" }}> |
|||
<Title level={3}>{languageSet.向量检索服务免费试用}</Title> |
|||
<Text>{languageSet.免费试用向量检索服务玩转大模型生成式检索}</Text> |
|||
<br /> |
|||
<Link href="#">{languageSet.查看详情}</Link> |
|||
</Col> |
|||
<Col |
|||
span={12} |
|||
style={{ |
|||
padding: "20px", |
|||
background: "#fff", |
|||
borderRadius: "8px", |
|||
position: "relative", |
|||
width: "500px", |
|||
height: "400px", |
|||
}} |
|||
> |
|||
<Tabs defaultActiveKey="1" style={{ marginTop: "50px" }}> |
|||
<TabPane tab={languageSet.邮箱密码登录} key="1"> |
|||
<Form form={upform} onFinish={uphandleSubmit}> |
|||
<Form.Item name="username" rules={[{ required: true, message: languageSet.请输入邮箱 }]}> |
|||
<Input size="large" placeholder={languageSet.请输入邮箱} prefix={<UserOutlined />} /> |
|||
</Form.Item> |
|||
<Form.Item name="password" rules={[{ required: true, message: languageSet.请输入登录密码 }]}> |
|||
<Input.Password |
|||
size="large" |
|||
placeholder={languageSet.请输入登录密码} |
|||
prefix={<LockOutlined />} |
|||
autoComplete="off" |
|||
/> |
|||
</Form.Item> |
|||
<Button type="primary" htmlType="submit" style={{ width: "100%" }}> |
|||
{languageSet.登录} |
|||
</Button> |
|||
</Form> |
|||
</TabPane> |
|||
<TabPane tab={languageSet.邮箱验证登录} key="2"> |
|||
<Form form={emailform} onFinish={emailhandleSubmit}> |
|||
<Form.Item name="email" rules={[{ required: true, message: languageSet.请输入邮箱 }]}> |
|||
<Input |
|||
size="large" |
|||
placeholder={languageSet.请输入邮箱} |
|||
prefix={<UserOutlined />} |
|||
addonAfter={ |
|||
<Button onClick={getEmailCode} disabled={isButtonDisabled}> |
|||
{isButtonDisabled ? `${countdown}秒后重试` : languageSet.获得验证码} |
|||
<Layout |
|||
style={{ |
|||
height: '100vh', |
|||
background: 'url(\'https://placehold.co/1920x1080\') no-repeat center center', |
|||
backgroundSize: 'cover', |
|||
}} |
|||
> |
|||
<Row justify="center" align="middle" style={{ height: '100%' }}> |
|||
<Col> |
|||
<Row> |
|||
<Col span={12} style={{ padding: '20px' }}> |
|||
<Title level={3}>向量检索服务免费试用</Title> |
|||
<Text>免费试用向量检索服务,玩转大模型生成式检索</Text> |
|||
<br/> |
|||
<Link href="#">查看详情 ></Link> |
|||
</Col> |
|||
<Col |
|||
span={12} |
|||
style={{ |
|||
padding: '20px', |
|||
background: '#fff', |
|||
borderRadius: '8px', |
|||
position: 'relative', |
|||
width: '500px', |
|||
height: '400px', |
|||
}} |
|||
> |
|||
<Tabs defaultActiveKey="1" |
|||
onChange={(key) => { |
|||
if (key === '1') { |
|||
slideCaptRef.current?.reset() |
|||
} |
|||
}} |
|||
style={{ marginTop: '50px' }}> |
|||
<TabPane tab="邮箱密码登录" key="1"> |
|||
<Form form={upform} onFinish={uphandleSubmit}> |
|||
<Form.Item name="username" rules={[ { required: true, message: '请输入邮箱' } ]}> |
|||
<Input size="large" placeholder="请输入邮箱" prefix={<UserOutlined/>}/> |
|||
</Form.Item> |
|||
<Form.Item name="password" rules={[ { required: true, message: '请输入登录密码' } ]}> |
|||
<Input.Password |
|||
size="large" |
|||
placeholder="请输入登录密码" |
|||
prefix={<LockOutlined/>} |
|||
autoComplete="off" |
|||
/> |
|||
</Form.Item> |
|||
<Form.Item name={'captchaKey'} |
|||
rules={[ { required: true, message: '点击进行校验' } ]}> |
|||
|
|||
<SlideCapt |
|||
ref={slideCaptRef} |
|||
api={{ |
|||
getCaptcha: systemServ.captcha, |
|||
checkCaptcha: systemServ.captchaCheck |
|||
}}/> |
|||
</Form.Item> |
|||
{/*<Form.Item name="code" rules={[{ required: true, message: "请输入验证码" }]}>*/} |
|||
{/* <Input.Password size="large" placeholder="验证码" prefix={<LockOutlined />} />*/} |
|||
{/*</Form.Item>*/} |
|||
<Button type="primary" htmlType="submit" style={{ width: '100%' }}> |
|||
登录 |
|||
</Button> |
|||
</Form> |
|||
</TabPane> |
|||
<TabPane tab="邮箱验证登录" key="2"> |
|||
<Form form={emailform} onFinish={emailhandleSubmit}> |
|||
<Form.Item name="email" rules={[ { required: true, message: '请输入邮箱' } ]}> |
|||
<Input |
|||
size="large" |
|||
placeholder="请输入邮箱" |
|||
prefix={<UserOutlined/>} |
|||
addonAfter={ |
|||
<Button onClick={getEmailCode} disabled={isButtonDisabled}> |
|||
{isButtonDisabled ? `${countdown}秒后重试` : '获得验证码'} |
|||
</Button> |
|||
} |
|||
/> |
|||
</Form.Item> |
|||
<Form.Item name="code" rules={[ { required: true, message: '请输入验证码' } ]}> |
|||
<Input.Password |
|||
size="large" |
|||
placeholder="请输入验证码" |
|||
prefix={<LockOutlined/>} |
|||
autoComplete="off" |
|||
/> |
|||
</Form.Item> |
|||
<Button type="primary" htmlType="submit" style={{ width: '100%' }}> |
|||
登录 |
|||
</Button> |
|||
} |
|||
/> |
|||
</Form.Item> |
|||
<Form.Item name="code" rules={[{ required: true, message: languageSet.请输入验证码 }]}> |
|||
<Input.Password |
|||
size="large" |
|||
placeholder={languageSet.请输入验证码} |
|||
prefix={<LockOutlined />} |
|||
autoComplete="off" |
|||
/> |
|||
</Form.Item> |
|||
<Button type="primary" htmlType="submit" style={{ width: "100%" }}> |
|||
{languageSet.登录} |
|||
</Button> |
|||
</Form> |
|||
</TabPane> |
|||
<TabPane tab={languageSet.飞机验证登录} key="3"> |
|||
<Form form={telegramform} onFinish={telegramhandleSubmit}> |
|||
<Form.Item name="telegram" rules={[{ required: true, message: languageSet.请输入邮箱 }]}> |
|||
<Input |
|||
size="large" |
|||
placeholder={languageSet.请输入邮箱} |
|||
prefix={<UserOutlined />} |
|||
addonAfter={ |
|||
<Button onClick={getTelegramCode} disabled={isButtonDisabled}> |
|||
{isButtonDisabled ? `${countdown}秒后重试` : languageSet.获得飞机验证码} |
|||
</Form> |
|||
</TabPane> |
|||
<TabPane tab="飞机验证登录" key="3"> |
|||
<Form form={telegramform} onFinish={telegramhandleSubmit}> |
|||
<Form.Item name="telegram" rules={[ { required: true, message: '请输入邮箱' } ]}> |
|||
<Input |
|||
size="large" |
|||
placeholder="请输入邮箱" |
|||
prefix={<UserOutlined/>} |
|||
addonAfter={ |
|||
<Button onClick={getTelegramCode} disabled={isButtonDisabled}> |
|||
{isButtonDisabled ? `${countdown}秒后重试` : '获得飞机验证码'} |
|||
</Button> |
|||
} |
|||
/> |
|||
</Form.Item> |
|||
<Form.Item name="code" rules={[ { required: true, message: '请输入飞机验证码' } ]}> |
|||
<Input.Password |
|||
size="large" |
|||
placeholder="请输入飞机验证码" |
|||
prefix={<LockOutlined/>} |
|||
autoComplete="off" |
|||
/> |
|||
</Form.Item> |
|||
<Button type="primary" htmlType="submit" style={{ width: '100%' }}> |
|||
登录 |
|||
</Button> |
|||
} |
|||
/> |
|||
</Form.Item> |
|||
<Form.Item name="code" rules={[{ required: true, message: languageSet.请输入飞机验证码 }]}> |
|||
<Input.Password |
|||
size="large" |
|||
placeholder={languageSet.请输入飞机验证码} |
|||
prefix={<LockOutlined />} |
|||
autoComplete="off" |
|||
/> |
|||
</Form.Item> |
|||
<Button type="primary" htmlType="submit" style={{ width: "100%" }}> |
|||
{languageSet.登录} |
|||
</Button> |
|||
</Form> |
|||
</TabPane> |
|||
</Tabs> |
|||
<div |
|||
style={{ |
|||
position: "absolute", |
|||
top: 0, |
|||
right: 0, |
|||
width: 0, |
|||
height: 0, |
|||
borderLeft: "80px solid transparent", |
|||
borderTop: "80px solid #ff9800", |
|||
textAlign: "center", |
|||
}} |
|||
> |
|||
</Form> |
|||
</TabPane> |
|||
</Tabs> |
|||
<div |
|||
style={{ |
|||
position: 'absolute', |
|||
top: 0, |
|||
right: 0, |
|||
width: 0, |
|||
height: 0, |
|||
borderLeft: '80px solid transparent', |
|||
borderTop: '80px solid #ff9800', |
|||
textAlign: 'center', |
|||
}} |
|||
> |
|||
<span |
|||
style={{ |
|||
position: "absolute", |
|||
top: "-70px", |
|||
right: "0px", |
|||
color: "#fff", |
|||
fontSize: "16px", |
|||
transform: "rotate(0deg)", |
|||
textAlign: "center", |
|||
width: "60px", |
|||
display: "block", |
|||
cursor: "pointer", // 设置手型光标
|
|||
}} |
|||
onClick={() => navigate({ to: "/register" })} |
|||
style={{ |
|||
position: 'absolute', |
|||
top: '-70px', |
|||
right: '0px', |
|||
color: '#fff', |
|||
fontSize: '16px', |
|||
transform: 'rotate(0deg)', |
|||
textAlign: 'center', |
|||
width: '60px', |
|||
display: 'block', |
|||
cursor: 'pointer', // 设置手型光标
|
|||
}} |
|||
onClick={() => navigate({ to: '/register' })} |
|||
> |
|||
{languageSet.注册} |
|||
注册 |
|||
</span> |
|||
</div> |
|||
<Row justify="space-between" style={{ marginTop: "10px" }}> |
|||
<Link onClick={() => navigate({ to: "/pwdRetrieve" })}>{languageSet.忘记密码}</Link> |
|||
</Row> |
|||
</Col> |
|||
</Row> |
|||
</Col> |
|||
</Row> |
|||
</Layout> |
|||
); |
|||
}); |
|||
|
|||
export const Route = createFileRoute("/login")({ |
|||
</div> |
|||
<Row justify="space-between" style={{ marginTop: '10px' }}> |
|||
<Link onClick={() => navigate({ to: '/pwdRetrieve' })}>忘记密码</Link> |
|||
</Row> |
|||
</Col> |
|||
</Row> |
|||
</Col> |
|||
</Row> |
|||
</Layout> |
|||
) |
|||
}) |
|||
|
|||
export const Route = createFileRoute('/login')({ |
|||
component: Login, |
|||
}); |
|||
}) |
|||
|
|||
export default Login; |
|||
export default Login |
@ -1,72 +1,79 @@ |
|||
import { IPageResult } from "@/global"; |
|||
import request from "../request.ts"; |
|||
import { createCURD } from "@/service/base.ts"; |
|||
import { System } from "@/types"; |
|||
import { IPageResult } from '@/global' |
|||
import request from '../request.ts' |
|||
import { createCURD } from '@/service/base.ts' |
|||
import { System } from '@/types' |
|||
|
|||
const systemServ = { |
|||
dept: { |
|||
...createCURD<any, System.IDepartment>("/sys/dept"), |
|||
...createCURD<any, System.IDepartment>('/sys/dept'), |
|||
tree: () => { |
|||
return request.get<{ tree: System.IDepartment }>("/sys/dept/tree"); |
|||
return request.get<{ tree: System.IDepartment }>('/sys/dept/tree') |
|||
}, |
|||
}, |
|||
menus: { |
|||
...createCURD<any, System.IMenu>("/sys/menu"), |
|||
...createCURD<any, System.IMenu>('/sys/menu'), |
|||
}, |
|||
uplogin: (data: any) => { |
|||
return request.post<System.LoginResponse>("/sys/login", data); |
|||
return request.post<System.LoginResponse>('/sys/login', data) |
|||
}, |
|||
emailCode: (data: any) => { |
|||
return request.post<System.LoginResponse>("/sys/email", data); |
|||
return request.post<System.LoginResponse>('/sys/email', data) |
|||
}, |
|||
|
|||
emailLogin: (data: any) => { |
|||
return request.post<System.LoginResponse>("/sys/email/login", data); |
|||
return request.post<System.LoginResponse>('/sys/email/login', data) |
|||
}, |
|||
emailRegister: (data: any) => { |
|||
return request.post<System.LoginResponse>("/sys/email/reg", data); |
|||
return request.post<System.LoginResponse>('/sys/email/reg', data) |
|||
}, |
|||
|
|||
|
|||
telegramCode: (data: any) => { |
|||
return request.post<System.LoginResponse>("/sys/telegram", data); |
|||
return request.post<System.LoginResponse>('/sys/telegram', data) |
|||
}, |
|||
|
|||
telegramLogin: (data: any) => { |
|||
return request.post<System.LoginResponse>("/sys/login/telegram", data); |
|||
return request.post<System.LoginResponse>('/sys/login/telegram', data) |
|||
}, |
|||
pwdRetrieve: (data: any) => { |
|||
return request.post<System.LoginResponse>("/sys/email/pws", data); |
|||
return request.post<System.LoginResponse>('/sys/email/pws', data) |
|||
}, |
|||
|
|||
//验证码
|
|||
captcha: () => { |
|||
return request.get('/sys/captcha') |
|||
}, |
|||
|
|||
captchaCheck: (data: any) => { |
|||
return request.post('/sys/captcha/check', data) |
|||
}, |
|||
|
|||
logout: () => { |
|||
//
|
|||
}, |
|||
user: { |
|||
...createCURD<any, System.IUser>("/sys/user"), |
|||
...createCURD<any, System.IUser>('/sys/user'), |
|||
current: () => { |
|||
return request.get<System.IUserInfo>("/sys/user/info"); |
|||
return request.get<System.IUserInfo>('/sys/user/info') |
|||
}, |
|||
menus: () => { |
|||
return request.get<IPageResult<System.IMenu[]>>("/sys/user/menus"); |
|||
return request.get<IPageResult<System.IMenu[]>>('/sys/user/menus') |
|||
}, |
|||
resetPassword: (id: number) => { |
|||
return request.post<any>(`/sys/user/reset/password`, { id }); |
|||
return request.post<any>(`/sys/user/reset/password`, { id }) |
|||
}, |
|||
}, |
|||
role: { |
|||
...createCURD<any, System.IRole>("/sys/role"), |
|||
...createCURD<any, System.IRole>('/sys/role'), |
|||
}, |
|||
logs: { |
|||
login: { |
|||
...createCURD<any, ILoginLog>("/sys/log/login"), |
|||
...createCURD<any, ILoginLog>('/sys/log/login'), |
|||
clear: (params: { start: string; end: string }) => { |
|||
return request.post<any>("/sys/log/login/clear", params); |
|||
return request.post<any>('/sys/log/login/clear', params) |
|||
}, |
|||
}, |
|||
}, |
|||
}; |
|||
} |
|||
|
|||
export default systemServ; |
|||
export default systemServ |
Write
Preview
Loading…
Cancel
Save
Reference in new issue