✨ qr login page /reset password page
This commit is contained in:
8
components.d.ts
vendored
8
components.d.ts
vendored
@@ -19,6 +19,7 @@ declare module 'vue' {
|
|||||||
AFormItem: typeof import('ant-design-vue/es')['FormItem']
|
AFormItem: typeof import('ant-design-vue/es')['FormItem']
|
||||||
AInput: typeof import('ant-design-vue/es')['Input']
|
AInput: typeof import('ant-design-vue/es')['Input']
|
||||||
AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
|
AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
|
||||||
|
AQrcode: typeof import('ant-design-vue/es')['QRCode']
|
||||||
ASelect: typeof import('ant-design-vue/es')['Select']
|
ASelect: typeof import('ant-design-vue/es')['Select']
|
||||||
ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
|
ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
|
||||||
ATabPane: typeof import('ant-design-vue/es')['TabPane']
|
ATabPane: typeof import('ant-design-vue/es')['TabPane']
|
||||||
@@ -27,7 +28,14 @@ declare module 'vue' {
|
|||||||
ATooltip: typeof import('ant-design-vue/es')['Tooltip']
|
ATooltip: typeof import('ant-design-vue/es')['Tooltip']
|
||||||
BoxDog: typeof import('./src/components/BoxDog/BoxDog.vue')['default']
|
BoxDog: typeof import('./src/components/BoxDog/BoxDog.vue')['default']
|
||||||
DynamicTitle: typeof import('./src/components/DynamicTitle/DynamicTitle.vue')['default']
|
DynamicTitle: typeof import('./src/components/DynamicTitle/DynamicTitle.vue')['default']
|
||||||
|
FoegetPage: typeof import('./src/views/Forget/FoegetPage.vue')['default']
|
||||||
|
ForgetPage: typeof import('./src/views/Forget/ForgetPage.vue')['default']
|
||||||
|
LockOutlined: typeof import('@ant-design/icons-vue')['LockOutlined']
|
||||||
|
LoginFooter: typeof import('./src/views/Login/LoginFooter.vue')['default']
|
||||||
LoginPage: typeof import('./src/views/Login/LoginPage.vue')['default']
|
LoginPage: typeof import('./src/views/Login/LoginPage.vue')['default']
|
||||||
|
QRLogin: typeof import('./src/views/QRLogin/QRLogin.vue')['default']
|
||||||
|
QRLoginFooter: typeof import('./src/views/QRLogin/QRLoginFooter.vue')['default']
|
||||||
|
RegisterFooter: typeof import('./src/views/Register/RegisterFooter.vue')['default']
|
||||||
RegisterPage: typeof import('./src/views/Register/RegisterPage.vue')['default']
|
RegisterPage: typeof import('./src/views/Register/RegisterPage.vue')['default']
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 55 KiB |
@@ -21,7 +21,6 @@ body {
|
|||||||
background: transparent;
|
background: transparent;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
z-index: 999;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
|
@@ -20,7 +20,15 @@ export default {
|
|||||||
login: "login",
|
login: "login",
|
||||||
register: "register",
|
register: "register",
|
||||||
reSendCaptcha: " re-send",
|
reSendCaptcha: " re-send",
|
||||||
passwordRule: "The password must be 6~18 characters and must contain letters, numbers and special symbols!"
|
passwordRule: "The password must be 6~18 characters and must contain letters, numbers and special symbols!",
|
||||||
|
phoneLoginAndRegister: "phone login/register",
|
||||||
|
open: "Please open",
|
||||||
|
scan: "scan the code to login",
|
||||||
|
wechat: "wechat",
|
||||||
|
repassword: "confirm password",
|
||||||
|
repasswordValidate: "please enter the confirmation password",
|
||||||
|
forgetPassword: "forget password",
|
||||||
|
resetPassword: "reset password",
|
||||||
},
|
},
|
||||||
error: {
|
error: {
|
||||||
networkError: 'Network error, please try again later',
|
networkError: 'Network error, please try again later',
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
// zh.ts
|
// zh.ts
|
||||||
export default {
|
export default {
|
||||||
login: {
|
login: {
|
||||||
title: '五味子云存储',
|
title: '五味子云相册',
|
||||||
accountLogin: '账号登录',
|
accountLogin: '账号登录',
|
||||||
account: '账号',
|
account: '账号',
|
||||||
accountValidate: '请输入手机号/账号/邮箱',
|
accountValidate: '请输入手机号/账号/邮箱',
|
||||||
@@ -9,7 +9,7 @@ export default {
|
|||||||
passwordValidate: "请输入密码",
|
passwordValidate: "请输入密码",
|
||||||
autoLogin: "自动登录",
|
autoLogin: "自动登录",
|
||||||
forgotPassword: "忘记密码",
|
forgotPassword: "忘记密码",
|
||||||
loginAndRegister: "登录",
|
loginAndRegister: "登录/注册",
|
||||||
qrLogin: "扫码登录",
|
qrLogin: "扫码登录",
|
||||||
phoneLogin: "短信登录",
|
phoneLogin: "短信登录",
|
||||||
phone: "手机号",
|
phone: "手机号",
|
||||||
@@ -20,7 +20,15 @@ export default {
|
|||||||
login: "登录",
|
login: "登录",
|
||||||
register: "注册",
|
register: "注册",
|
||||||
reSendCaptcha: "重新发送",
|
reSendCaptcha: "重新发送",
|
||||||
passwordRule: "密码要6~18位字符,且必须包含字母、数字和特殊符号!"
|
passwordRule: "密码要6~18位字符,且必须包含字母、数字和特殊符号!",
|
||||||
|
phoneLoginAndRegister: "短信注册/登录",
|
||||||
|
open: "请打开",
|
||||||
|
scan: "扫码登录",
|
||||||
|
wechat: "微信",
|
||||||
|
repassword: "确认密码",
|
||||||
|
repasswordValidate: "请输入确认密码",
|
||||||
|
forgetPassword: "忘记密码",
|
||||||
|
resetPassword: "重置密码",
|
||||||
},
|
},
|
||||||
error: {
|
error: {
|
||||||
networkError: '网络连接失败!',
|
networkError: '网络连接失败!',
|
||||||
|
11
src/router/modules/qrlogin.ts
Normal file
11
src/router/modules/qrlogin.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export default [
|
||||||
|
{
|
||||||
|
path: '/qrlogin',
|
||||||
|
name: 'qrlogin',
|
||||||
|
component: () => import('@/views/QRLogin/QRLogin.vue'),
|
||||||
|
meta: {
|
||||||
|
requiresAuth: false,
|
||||||
|
title: '扫码登录'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
@@ -1,11 +0,0 @@
|
|||||||
export default [
|
|
||||||
{
|
|
||||||
path: '/register',
|
|
||||||
name: 'register',
|
|
||||||
component: () => import('@/views/Register/RegisterPage.vue'),
|
|
||||||
meta: {
|
|
||||||
requiresAuth: false,
|
|
||||||
title: '注册页'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
11
src/router/modules/resetpass.ts
Normal file
11
src/router/modules/resetpass.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export default [
|
||||||
|
{
|
||||||
|
path: '/resetpass',
|
||||||
|
name: 'resetpass',
|
||||||
|
component: () => import('@/views/Forget/ForgetPage.vue'),
|
||||||
|
meta: {
|
||||||
|
requiresAuth: false,
|
||||||
|
title: '重置密码'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
@@ -7,12 +7,14 @@ import test2 from "@/router/modules/testI18n.ts";
|
|||||||
import useStore from "@/store";
|
import useStore from "@/store";
|
||||||
import {message} from "ant-design-vue";
|
import {message} from "ant-design-vue";
|
||||||
import {close, start} from '@/utils/nprogress/nprogress.ts';
|
import {close, start} from '@/utils/nprogress/nprogress.ts';
|
||||||
import register from "@/router/modules/register.ts";
|
import qrlogin from "@/router/modules/qrlogin.ts";
|
||||||
|
import resetpass from "@/router/modules/resetpass.ts";
|
||||||
|
|
||||||
|
|
||||||
const routes: Array<RouteRecordRaw> = [
|
const routes: Array<RouteRecordRaw> = [
|
||||||
...login,
|
...login,
|
||||||
...register,
|
...qrlogin,
|
||||||
|
...resetpass,
|
||||||
...test,
|
...test,
|
||||||
...test2,
|
...test2,
|
||||||
];
|
];
|
||||||
|
8
src/types/user.d.ts
vendored
8
src/types/user.d.ts
vendored
@@ -8,7 +8,15 @@ export interface AccountLogin {
|
|||||||
account?: string
|
account?: string
|
||||||
password?: string;
|
password?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PhoneLogin {
|
export interface PhoneLogin {
|
||||||
phone?: string
|
phone?: string
|
||||||
captcha?: string;
|
captcha?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ResetPassword {
|
||||||
|
phone?: string
|
||||||
|
captcha?: string;
|
||||||
|
password?: string;
|
||||||
|
repassword?: string;
|
||||||
|
}
|
||||||
|
209
src/views/Forget/ForgetPage.vue
Normal file
209
src/views/Forget/ForgetPage.vue
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
<template>
|
||||||
|
<div class="forget-main">
|
||||||
|
<div class="forget-left">
|
||||||
|
<BoxDog/>
|
||||||
|
</div>
|
||||||
|
<div class="forget-right">
|
||||||
|
<span class="forget-right-title">{{ t("login.title") }}</span>
|
||||||
|
<ACard class="forget-card" bordered :hoverable="false">
|
||||||
|
<AFlex :vertical="true">
|
||||||
|
<span class="forget-card-title">{{ t("login.forgetPassword") }}</span>
|
||||||
|
<AForm
|
||||||
|
ref="resetPasswordRef"
|
||||||
|
:model="ResetPasswordForm"
|
||||||
|
:rules="rules"
|
||||||
|
>
|
||||||
|
<AFormItem name="phone">
|
||||||
|
<span class="forget-card-span">{{ t("login.phone") }}</span>
|
||||||
|
<AInput v-model:value="ResetPasswordForm.phone" :placeholder=phoneValidate size="large" allow-clear>
|
||||||
|
<template #prefix>
|
||||||
|
<TabletOutlined/>
|
||||||
|
</template>
|
||||||
|
</AInput>
|
||||||
|
</AFormItem>
|
||||||
|
<AFormItem name="captcha">
|
||||||
|
<AFlex :vertical="true">
|
||||||
|
<span class="forget-card-span">{{ t("login.phoneCaptcha") }}</span>
|
||||||
|
<AFlex :vertical="false" align="center" justify="center">
|
||||||
|
<AInput v-model:value="ResetPasswordForm.captcha" :placeholder=captchaValidate size="large" allow-clear>
|
||||||
|
<template #prefix>
|
||||||
|
<SafetyOutlined/>
|
||||||
|
</template>
|
||||||
|
</AInput>
|
||||||
|
<AButton v-if="!state.showCountDown" @click="sendCaptcha" size="large" style="margin-left: 10px">{{
|
||||||
|
t("login.sendCaptcha")
|
||||||
|
}}
|
||||||
|
</AButton>
|
||||||
|
<AButton v-if="state.showCountDown" disabled size="large" style="margin-left: 10px">{{
|
||||||
|
state.countDownTime
|
||||||
|
}}s{{ t("login.reSendCaptcha") }}
|
||||||
|
</AButton>
|
||||||
|
</AFlex>
|
||||||
|
</AFlex>
|
||||||
|
</AFormItem>
|
||||||
|
<AFormItem name="password">
|
||||||
|
<span class="forget-card-span">{{ t("login.password") }}</span>
|
||||||
|
<AInput v-model:value="ResetPasswordForm.password" :placeholder=passwordValidate size="large" allow-clear>
|
||||||
|
<template #prefix>
|
||||||
|
<LockOutlined/>
|
||||||
|
</template>
|
||||||
|
</AInput>
|
||||||
|
</AFormItem>
|
||||||
|
<AFormItem name="repassword">
|
||||||
|
<span class="forget-card-span">{{ t("login.repassword") }}</span>
|
||||||
|
<AInput v-model:value="ResetPasswordForm.repassword" :placeholder=repasswordValidate size="large" allow-clear>
|
||||||
|
<template #prefix>
|
||||||
|
<LockOutlined/>
|
||||||
|
</template>
|
||||||
|
</AInput>
|
||||||
|
</AFormItem>
|
||||||
|
<AFormItem>
|
||||||
|
<AButton @click="resetPasswordSubmit" style="width: 100%;" type="primary" size="large">{{
|
||||||
|
t("login.resetPassword")
|
||||||
|
}}</AButton>
|
||||||
|
</AFormItem>
|
||||||
|
</AForm>
|
||||||
|
</AFlex>
|
||||||
|
<ATooltip placement="left">
|
||||||
|
<template #title>
|
||||||
|
<span>{{ t("login.phoneLogin") }}</span>
|
||||||
|
</template>
|
||||||
|
<div @click="()=>{
|
||||||
|
router.push('/login');
|
||||||
|
}" class="forget-right-qrcode"/>
|
||||||
|
</ATooltip>
|
||||||
|
</ACard>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {useI18n} from "vue-i18n";
|
||||||
|
import BoxDog from "@/components/BoxDog/BoxDog.vue";
|
||||||
|
import {useRouter} from "vue-router";
|
||||||
|
import {onMounted, reactive, ref, UnwrapRef} from "vue";
|
||||||
|
import {ResetPassword} from "@/types/user";
|
||||||
|
import {Rule} from "ant-design-vue/lib/form";
|
||||||
|
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const {t} = useI18n();
|
||||||
|
const resetPasswordRef = ref()
|
||||||
|
const ResetPasswordForm: UnwrapRef<ResetPassword> = reactive({
|
||||||
|
phone: '',
|
||||||
|
captcha: '',
|
||||||
|
password: '',
|
||||||
|
repassword: '',
|
||||||
|
});
|
||||||
|
// 表单验证提示
|
||||||
|
const passwordValidate = ref<string>(t('login.passwordValidate'));
|
||||||
|
const phoneValidate = ref<string>(t('login.phoneValidate'));
|
||||||
|
const captchaValidate = ref<string>(t('login.captchaValidate'));
|
||||||
|
const repasswordValidate = ref<string>(t('login.repasswordValidate'));
|
||||||
|
|
||||||
|
// 表单验证规则
|
||||||
|
const rules: Record<string, Rule[]> = {
|
||||||
|
password: [
|
||||||
|
{
|
||||||
|
required: true, message: t('login.passwordValidate'), trigger: 'change'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{6,18}$/,
|
||||||
|
message: t('login.passwordRule'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
repassword: [
|
||||||
|
{
|
||||||
|
required: true, message: t('login.repasswordValidate'), trigger: 'change'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{6,18}$/,
|
||||||
|
message: t('login.passwordRule'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
phone: [
|
||||||
|
{required: true, message: t('login.phoneValidate'), trigger: 'change'},
|
||||||
|
{pattern: /^1[2-9]\d{9}$/, message: t('login.phoneValidate')}
|
||||||
|
],
|
||||||
|
captcha: [
|
||||||
|
{
|
||||||
|
required: true, message: t('login.captchaValidate'), trigger: 'change'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
countDownTime: 60,
|
||||||
|
showCountDown: false,
|
||||||
|
});
|
||||||
|
/**
|
||||||
|
* 验证码发送倒计时
|
||||||
|
*/
|
||||||
|
const countDown = () => {
|
||||||
|
const startTime = localStorage.getItem('startTimeSendCaptcha');
|
||||||
|
const nowTime = new Date().getTime();
|
||||||
|
let surplus: number = 60;
|
||||||
|
let timer: any;
|
||||||
|
if (startTime) {
|
||||||
|
surplus = 60 - Math.floor((nowTime - Number(startTime)) / 1000);
|
||||||
|
surplus = surplus <= 0 ? 0 : surplus;
|
||||||
|
} else {
|
||||||
|
localStorage.setItem('startTimeSendCaptcha', String(nowTime));
|
||||||
|
}
|
||||||
|
|
||||||
|
state.countDownTime = surplus;
|
||||||
|
|
||||||
|
if (timer) {
|
||||||
|
clearInterval(timer);
|
||||||
|
}
|
||||||
|
timer = setInterval(() => {
|
||||||
|
if (state.countDownTime <= 0) {
|
||||||
|
localStorage.removeItem('startTimeSendCaptcha');
|
||||||
|
clearInterval(timer);
|
||||||
|
state.countDownTime = 60;
|
||||||
|
state.showCountDown = false;
|
||||||
|
} else {
|
||||||
|
state.countDownTime--;
|
||||||
|
state.showCountDown = true;
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
onMounted(() => {
|
||||||
|
const sendEndTime = localStorage.getItem('startTimeSendCaptcha');
|
||||||
|
if (sendEndTime) {
|
||||||
|
state.showCountDown = true;
|
||||||
|
countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送验证码
|
||||||
|
*/
|
||||||
|
async function sendCaptcha() {
|
||||||
|
resetPasswordRef.value
|
||||||
|
.validateFields("phone")
|
||||||
|
.then(() => {
|
||||||
|
countDown();
|
||||||
|
console.log('values');
|
||||||
|
})
|
||||||
|
.catch((error: any) => {
|
||||||
|
console.log('error', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置密码表单提交
|
||||||
|
*/
|
||||||
|
async function resetPasswordSubmit() {
|
||||||
|
resetPasswordRef.value
|
||||||
|
.validate()
|
||||||
|
.then(() => {
|
||||||
|
console.log('values', ResetPasswordForm);
|
||||||
|
})
|
||||||
|
.catch((error: any) => {
|
||||||
|
console.log('error', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style src="./index.scss" scoped>
|
||||||
|
@import "@/assets/styles/global.scss";
|
||||||
|
</style>
|
90
src/views/Forget/index.scss
Normal file
90
src/views/Forget/index.scss
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
.forget-main {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
//background-color: rgb(238, 255, 238);
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
/* 加载背景图 */
|
||||||
|
background-image: url("@/assets/images/background.png");
|
||||||
|
/* 背景图垂直、水平均居中 */
|
||||||
|
background-position: center center;
|
||||||
|
/* 背景图不平铺 */
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
/* 当内容高度大于图片高度时,背景图像的位置相对于viewport固定 */
|
||||||
|
background-attachment: fixed;
|
||||||
|
/* 让背景图基于容器大小伸缩 */
|
||||||
|
background-size: cover;
|
||||||
|
|
||||||
|
.forget-left {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forget-right {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 50%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.forget-right-title {
|
||||||
|
font-size: 32px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forget-card-span {
|
||||||
|
color: #999ba1;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forget-card-return {
|
||||||
|
color: #999ba1;
|
||||||
|
font-size: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forget-card-return:hover {
|
||||||
|
color: #08a327;
|
||||||
|
font-size: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.forget-card {
|
||||||
|
width: 440px;
|
||||||
|
height: 490px;
|
||||||
|
border-radius: 15px;
|
||||||
|
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, .08);
|
||||||
|
|
||||||
|
.forget-card-title {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #222;
|
||||||
|
line-height: 26px;
|
||||||
|
margin-bottom: 24px
|
||||||
|
}
|
||||||
|
|
||||||
|
.forget-right-qrcode {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
background-position: 50%;
|
||||||
|
background-size: cover;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
width: 72px;
|
||||||
|
height: 72px;
|
||||||
|
background-image: url(data:image/png;base64,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);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forget-right-qrcode:hover {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forget-form-bottom-button {
|
||||||
|
color: #999ba1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
25
src/views/Login/LoginFooter.vue
Normal file
25
src/views/Login/LoginFooter.vue
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<ADivider/>
|
||||||
|
<AFlex :vertical="false" align="center" justify="space-around">
|
||||||
|
<AButton @click="()=>{
|
||||||
|
router.push('/qrlogin')
|
||||||
|
}" class="login-form-bottom-button" :icon="h(QrcodeOutlined)">{{ t("login.qrLogin") }}
|
||||||
|
</AButton>
|
||||||
|
<AButton class="login-form-bottom-button" :icon="h(QqOutlined)"></AButton>
|
||||||
|
<AButton class="login-form-bottom-button" :icon="h(GithubOutlined)"></AButton>
|
||||||
|
</AFlex>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {GithubOutlined, QqOutlined, QrcodeOutlined} from "@ant-design/icons-vue";
|
||||||
|
import {useI18n} from "vue-i18n";
|
||||||
|
import {h} from "vue";
|
||||||
|
import {useRouter} from 'vue-router'
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const {t} = useI18n();
|
||||||
|
</script>
|
||||||
|
<style src="./index.scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
@@ -20,7 +20,7 @@
|
|||||||
name="phone">
|
name="phone">
|
||||||
<span class="login-card-span">{{ t("login.phone") }}</span>
|
<span class="login-card-span">{{ t("login.phone") }}</span>
|
||||||
<AInput v-model:value="phoneLoginForm.phone" class="login-form-input" size="large"
|
<AInput v-model:value="phoneLoginForm.phone" class="login-form-input" size="large"
|
||||||
:placeholder=phoneValidate
|
:placeholder=phoneValidate allow-clear
|
||||||
>
|
>
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<TabletOutlined/>
|
<TabletOutlined/>
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
<AFlex :vertical="true">
|
<AFlex :vertical="true">
|
||||||
<span class="login-card-span">{{ t("login.phoneCaptcha") }}</span>
|
<span class="login-card-span">{{ t("login.phoneCaptcha") }}</span>
|
||||||
<AFlex :vertical="false" align="center" justify="center">
|
<AFlex :vertical="false" align="center" justify="center">
|
||||||
<AInput v-model:value="phoneLoginForm.captcha" size="large" :placeholder=captchaValidate>
|
<AInput v-model:value="phoneLoginForm.captcha" size="large" :placeholder=captchaValidate allow-clear>
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<SafetyOutlined/>
|
<SafetyOutlined/>
|
||||||
</template>
|
</template>
|
||||||
@@ -53,22 +53,16 @@
|
|||||||
<AFormItem>
|
<AFormItem>
|
||||||
<AFlex :vertical="false" justify="space-between">
|
<AFlex :vertical="false" justify="space-between">
|
||||||
<ACheckbox>{{ t("login.autoLogin") }}</ACheckbox>
|
<ACheckbox>{{ t("login.autoLogin") }}</ACheckbox>
|
||||||
<a>{{ t("login.forgotPassword") }}</a>
|
|
||||||
</AFlex>
|
</AFlex>
|
||||||
|
|
||||||
</AFormItem>
|
</AFormItem>
|
||||||
<AFormItem>
|
<AFormItem>
|
||||||
<AButton @click="phoneLoginSubmit" type="primary" size="large" class="login-form-button">
|
<AButton @click="phoneLoginSubmit" type="primary" size="large" class="login-form-button">
|
||||||
{{ t("login.login") }}
|
{{ t("login.loginAndRegister") }}
|
||||||
</AButton>
|
</AButton>
|
||||||
</AFormItem>
|
</AFormItem>
|
||||||
</AForm>
|
</AForm>
|
||||||
<ADivider/>
|
<LoginFooter/>
|
||||||
<AFlex :vertical="false" align="center" justify="space-around">
|
|
||||||
<AButton class="login-form-bottom-button" :icon="h(QrcodeOutlined)">{{ t("login.qrLogin") }}</AButton>
|
|
||||||
<AButton class="login-form-bottom-button" :icon="h(QqOutlined)"></AButton>
|
|
||||||
<AButton class="login-form-bottom-button" :icon="h(GithubOutlined)"></AButton>
|
|
||||||
</AFlex>
|
|
||||||
</ATabPane>
|
</ATabPane>
|
||||||
<!-- 账号登录 -->
|
<!-- 账号登录 -->
|
||||||
<ATabPane key="accountLogin">
|
<ATabPane key="accountLogin">
|
||||||
@@ -83,7 +77,7 @@
|
|||||||
name="account">
|
name="account">
|
||||||
<span class="login-card-span">{{ t("login.account") }}</span>
|
<span class="login-card-span">{{ t("login.account") }}</span>
|
||||||
<AInput v-model:value="accountLoginForm.account" class="login-form-input" size="large"
|
<AInput v-model:value="accountLoginForm.account" class="login-form-input" size="large"
|
||||||
:placeholder=accountValidate>
|
:placeholder=accountValidate allow-clear>
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<user-outlined/>
|
<user-outlined/>
|
||||||
</template>
|
</template>
|
||||||
@@ -95,7 +89,7 @@
|
|||||||
<AFlex :vertical="true">
|
<AFlex :vertical="true">
|
||||||
<span class="login-card-span">{{ t("login.password") }}</span>
|
<span class="login-card-span">{{ t("login.password") }}</span>
|
||||||
<AInputPassword v-model:value="accountLoginForm.password" class="login-form-input" size="large"
|
<AInputPassword v-model:value="accountLoginForm.password" class="login-form-input" size="large"
|
||||||
:placeholder=passwordValidate>
|
:placeholder=passwordValidate allow-clear>
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<SafetyOutlined/>
|
<SafetyOutlined/>
|
||||||
</template>
|
</template>
|
||||||
@@ -105,32 +99,30 @@
|
|||||||
<AFormItem>
|
<AFormItem>
|
||||||
<AFlex :vertical="false" justify="space-between">
|
<AFlex :vertical="false" justify="space-between">
|
||||||
<ACheckbox>{{ t("login.autoLogin") }}</ACheckbox>
|
<ACheckbox>{{ t("login.autoLogin") }}</ACheckbox>
|
||||||
<a>{{ t("login.forgotPassword") }}</a>
|
<a @click="()=>{
|
||||||
|
router.push('/resetpass')
|
||||||
|
}">{{ t("login.forgotPassword") }}</a>
|
||||||
</AFlex>
|
</AFlex>
|
||||||
|
|
||||||
</AFormItem>
|
</AFormItem>
|
||||||
<AFormItem>
|
<AFormItem>
|
||||||
<AButton @click="accountLoginSubmit" type="primary" size="large" class="login-form-button">
|
<AButton @click="accountLoginSubmit" type="primary" size="large" class="login-form-button">
|
||||||
{{
|
{{
|
||||||
t("login.loginAndRegister")
|
t("login.login")
|
||||||
}}
|
}}
|
||||||
</AButton>
|
</AButton>
|
||||||
</AFormItem>
|
</AFormItem>
|
||||||
</AForm>
|
</AForm>
|
||||||
<ADivider/>
|
<LoginFooter/>
|
||||||
<AFlex :vertical="false" align="center" justify="space-around">
|
|
||||||
<AButton class="login-form-bottom-button" :icon="h(QrcodeOutlined)">{{ t("login.qrLogin") }}</AButton>
|
|
||||||
<AButton class="login-form-bottom-button" :icon="h(QqOutlined)"></AButton>
|
|
||||||
<AButton class="login-form-bottom-button" :icon="h(GithubOutlined)"></AButton>
|
|
||||||
</AFlex>
|
|
||||||
</ATabPane>
|
</ATabPane>
|
||||||
|
|
||||||
</ATabs>
|
</ATabs>
|
||||||
<ATooltip placement="left">
|
<ATooltip placement="left">
|
||||||
<template #title>
|
<template #title>
|
||||||
<span>{{ t("login.qrLogin") }}</span>
|
<span>{{ t("login.qrLogin") }}</span>
|
||||||
</template>
|
</template>
|
||||||
<div class="login-right-qrcode"/>
|
<div @click="()=>{
|
||||||
|
router.push('/qrlogin');
|
||||||
|
}" class="login-right-qrcode"/>
|
||||||
</ATooltip>
|
</ATooltip>
|
||||||
</ACard>
|
</ACard>
|
||||||
</div>
|
</div>
|
||||||
@@ -138,14 +130,16 @@
|
|||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {Rule} from "ant-design-vue/lib/form";
|
import {Rule} from "ant-design-vue/lib/form";
|
||||||
import {h, onMounted, reactive, ref, UnwrapRef} from "vue";
|
import {onMounted, reactive, ref, UnwrapRef} from "vue";
|
||||||
import {AccountLogin, PhoneLogin} from "@/types/user";
|
import {AccountLogin, PhoneLogin} from "@/types/user";
|
||||||
import {GithubOutlined, QqOutlined, QrcodeOutlined} from "@ant-design/icons-vue";
|
|
||||||
import {useI18n} from "vue-i18n";
|
import {useI18n} from "vue-i18n";
|
||||||
import BoxDog from "@/components/BoxDog/BoxDog.vue";
|
import BoxDog from "@/components/BoxDog/BoxDog.vue";
|
||||||
|
import LoginFooter from "@/views/Login/LoginFooter.vue";
|
||||||
|
import {useRouter} from "vue-router";
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
const {t} = useI18n();
|
const {t} = useI18n();
|
||||||
const accountLoginFormRef = ref();
|
const accountLoginFormRef = ref<any>();
|
||||||
const phoneLoginFormRef = ref<any>();
|
const phoneLoginFormRef = ref<any>();
|
||||||
// 账号登录表单数据
|
// 账号登录表单数据
|
||||||
const accountLoginForm: UnwrapRef<AccountLogin> = reactive({
|
const accountLoginForm: UnwrapRef<AccountLogin> = reactive({
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
/* 加载背景图 */
|
/* 加载背景图 */
|
||||||
background-image: url("@/assets/images/login-back.png");
|
background-image: url("@/assets/images/background.png");
|
||||||
/* 背景图垂直、水平均居中 */
|
/* 背景图垂直、水平均居中 */
|
||||||
background-position: center center;
|
background-position: center center;
|
||||||
/* 背景图不平铺 */
|
/* 背景图不平铺 */
|
||||||
@@ -82,10 +82,6 @@
|
|||||||
.login-form-bottom-button {
|
.login-form-bottom-button {
|
||||||
color: #999ba1;
|
color: #999ba1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-form-bottom-button:hover {
|
|
||||||
color: rgba(15, 15, 16, 0.3);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
51
src/views/QRLogin/QRLogin.vue
Normal file
51
src/views/QRLogin/QRLogin.vue
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<template>
|
||||||
|
<div class="qrlogin-main">
|
||||||
|
<div class="qrlogin-left">
|
||||||
|
<BoxDog/>
|
||||||
|
</div>
|
||||||
|
<div class="qrlogin-right">
|
||||||
|
<span class="qrlogin-right-title">{{ t("login.title") }}</span>
|
||||||
|
<ACard class="qrlogin-card" bordered :hoverable="false">
|
||||||
|
<AFlex :vertical="true" align="center">
|
||||||
|
<span class="qrlogin-card-item-span">{{ t("login.qrLogin") }}</span>
|
||||||
|
<span class="qrlogin-card-item-info">
|
||||||
|
{{ t("login.open") }}
|
||||||
|
<span class="qrlogin-card-wechat">{{ t("login.wechat") }}</span>
|
||||||
|
{{ t("login.scan") }}
|
||||||
|
</span>
|
||||||
|
<AQrcode
|
||||||
|
class="qrlogin-card-qr"
|
||||||
|
:size="230"
|
||||||
|
:error-level="'H'"
|
||||||
|
value="https://www.antdv.com"
|
||||||
|
icon="https://www.antdv.com/assets/logo.1ef800a8.svg"
|
||||||
|
/>
|
||||||
|
<ACheckbox class="qrlogin-card-auto-login">{{ t("login.autoLogin") }}</ACheckbox>
|
||||||
|
</AFlex>
|
||||||
|
<QRLoginFooter/>
|
||||||
|
<ATooltip placement="left">
|
||||||
|
<template #title>
|
||||||
|
<span>{{ t("login.phoneLogin") }}</span>
|
||||||
|
</template>
|
||||||
|
<div @click="()=>{
|
||||||
|
router.push('/login')
|
||||||
|
}" class="qrlogin-right-qrcode"/>
|
||||||
|
</ATooltip>
|
||||||
|
</ACard>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {useI18n} from "vue-i18n";
|
||||||
|
import BoxDog from "@/components/BoxDog/BoxDog.vue";
|
||||||
|
import QRLoginFooter from "@/views/QRLogin/QRLoginFooter.vue";
|
||||||
|
import {useRouter} from 'vue-router'
|
||||||
|
|
||||||
|
const {t} = useI18n();
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style src="./index.scss" scoped>
|
||||||
|
@import "@/assets/styles/global.scss";
|
||||||
|
</style>
|
25
src/views/QRLogin/QRLoginFooter.vue
Normal file
25
src/views/QRLogin/QRLoginFooter.vue
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<ADivider/>
|
||||||
|
<AFlex :vertical="false" align="center" justify="space-around">
|
||||||
|
<AButton @click="()=>{
|
||||||
|
router.push('/login')
|
||||||
|
}" class="qrlogin-form-bottom-button" :icon="h(TabletOutlined)">{{ t("login.phoneLoginAndRegister") }}
|
||||||
|
</AButton>
|
||||||
|
<AButton class="qrlogin-form-bottom-button" :icon="h(QqOutlined)"></AButton>
|
||||||
|
<AButton class="qrlogin-form-bottom-button" :icon="h(GithubOutlined)"></AButton>
|
||||||
|
</AFlex>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {GithubOutlined, QqOutlined, TabletOutlined} from "@ant-design/icons-vue";
|
||||||
|
import {useI18n} from "vue-i18n";
|
||||||
|
import {h} from "vue";
|
||||||
|
import {useRouter} from 'vue-router'
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const {t} = useI18n();
|
||||||
|
</script>
|
||||||
|
<style src="./index.scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
98
src/views/QRLogin/index.scss
Normal file
98
src/views/QRLogin/index.scss
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
.qrlogin-main {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
//background-color: rgb(238, 255, 238);
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
/* 加载背景图 */
|
||||||
|
background-image: url("@/assets/images/background.png");
|
||||||
|
/* 背景图垂直、水平均居中 */
|
||||||
|
background-position: center center;
|
||||||
|
/* 背景图不平铺 */
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
/* 当内容高度大于图片高度时,背景图像的位置相对于viewport固定 */
|
||||||
|
background-attachment: fixed;
|
||||||
|
/* 让背景图基于容器大小伸缩 */
|
||||||
|
background-size: cover;
|
||||||
|
|
||||||
|
.qrlogin-left {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qrlogin-right {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 50%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.qrlogin-right-title {
|
||||||
|
font-size: 32px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.qrlogin-card {
|
||||||
|
width: 440px;
|
||||||
|
height: 490px;
|
||||||
|
border-radius: 15px;
|
||||||
|
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, .08);
|
||||||
|
|
||||||
|
.qrlogin-card-item-span {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #222;
|
||||||
|
line-height: 26px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qrlogin-card-item-info {
|
||||||
|
margin-top: 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #999;
|
||||||
|
line-height: 18px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
|
||||||
|
.qrlogin-card-wechat {
|
||||||
|
color: #7acc35;
|
||||||
|
margin-left: 4px;
|
||||||
|
margin-right: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.qrlogin-card-qr {
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qrlogin-card-auto-login {
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.qrlogin-right-qrcode {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
background-position: 50%;
|
||||||
|
background-size: cover;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
width: 72px;
|
||||||
|
height: 72px;
|
||||||
|
background-image: url(data:image/png;base64,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);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qrlogin-right-qrcode:hover {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qrlogin-form-bottom-button {
|
||||||
|
color: #999ba1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -1,17 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import {defineComponent} from 'vue';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "RegisterPage"
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style src="./index.scss" scoped>
|
|
||||||
|
|
||||||
</style>
|
|
Reference in New Issue
Block a user