登录页修改
Some checks failed
Build And Deploy v3-admin-vite / build-and-deploy (push) Has been cancelled
Some checks failed
Build And Deploy v3-admin-vite / build-and-deploy (push) Has been cancelled
This commit is contained in:
parent
fec3098825
commit
e12f4cc9e9
2
.env
2
.env
@ -1,7 +1,7 @@
|
||||
# 所有环境的环境变量(命名必须以 VITE_ 开头)
|
||||
|
||||
## 项目标题
|
||||
VITE_APP_TITLE = V3 Admin Vite
|
||||
VITE_APP_TITLE = 数据运营管理平台
|
||||
|
||||
## 路由模式 hash 或 html5
|
||||
VITE_ROUTER_HISTORY = hash
|
||||
|
@ -3,7 +3,9 @@
|
||||
## 后端接口地址(如果解决跨域问题采用反向代理就只需写相对路径)
|
||||
## VITE_BASE_URL = /api/v1
|
||||
|
||||
VITE_BASE_URL = http://localhost:8000
|
||||
# VITE_BASE_URL = http://124.71.209.231:8000
|
||||
VITE_BASE_URL = null
|
||||
|
||||
|
||||
## 开发环境域名和静态资源公共路径(一般 / 或 ./ 都可以)
|
||||
VITE_PUBLIC_PATH = /
|
||||
|
@ -1,6 +1,6 @@
|
||||
<div align="center">
|
||||
<img alt="logo" width="120" height="120" src="./src/common/assets/images/layouts/logo.png">
|
||||
<h1>V3 Admin Vite</h1>
|
||||
<h1>V3 Admin Vit1e</h1>
|
||||
</div>
|
||||
|
||||
[](https://github.com/un-pany/v3-admin-vite/releases)
|
||||
|
@ -13,8 +13,8 @@ initTheme()
|
||||
// 初始化灰色模式和色弱模式
|
||||
initGreyAndColorWeakness()
|
||||
// 初始化通知
|
||||
initStarNotification()
|
||||
initStoreNotification()
|
||||
// initStarNotification()
|
||||
// initStoreNotification()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -2,7 +2,24 @@ export interface LoginRequestData {
|
||||
/** admin 或 editor */
|
||||
username: string
|
||||
/** 密码 */
|
||||
password: string
|
||||
password: string,
|
||||
//手机号
|
||||
phone: string,
|
||||
//手机验证码
|
||||
mobileCode: string
|
||||
}
|
||||
|
||||
export interface forgetRequestData {
|
||||
/** admin 或 editor */
|
||||
username: string
|
||||
/** 密码 */
|
||||
password: string,
|
||||
//确认密码
|
||||
confirmPassword: string,
|
||||
//手机号
|
||||
phone: string,
|
||||
//手机验证码
|
||||
mobileCode: string
|
||||
}
|
||||
|
||||
export type CaptchaResponseData = ApiResponseData<string>
|
||||
|
@ -1,67 +1,181 @@
|
||||
<script lang="ts" setup>
|
||||
import type { FormInstance, FormRules } from "element-plus"
|
||||
import type { LoginRequestData } from "./apis/type"
|
||||
import { useSettingsStore } from "@/pinia/stores/settings"
|
||||
import { useUserStore } from "@/pinia/stores/user"
|
||||
import ThemeSwitch from "@@/components/ThemeSwitch/index.vue"
|
||||
import { Lock, User } from "@element-plus/icons-vue"
|
||||
import { loginApi } from "./apis"
|
||||
import Owl from "./components/Owl.vue"
|
||||
import { useFocus } from "./composables/useFocus"
|
||||
import type { FormInstance, FormRules } from "element-plus";
|
||||
import type { LoginRequestData, forgetRequestData } from "./apis/type";
|
||||
import { useSettingsStore } from "@/pinia/stores/settings";
|
||||
import { useUserStore } from "@/pinia/stores/user";
|
||||
import ThemeSwitch from "@@/components/ThemeSwitch/index.vue";
|
||||
import { Lock, User, Iphone, Promotion, Check } from "@element-plus/icons-vue";
|
||||
import { loginApi } from "./apis";
|
||||
import Owl from "./components/Owl.vue";
|
||||
import { useFocus } from "./composables/useFocus";
|
||||
|
||||
const router = useRouter()
|
||||
const router = useRouter();
|
||||
|
||||
const userStore = useUserStore()
|
||||
const userStore = useUserStore();
|
||||
|
||||
const settingsStore = useSettingsStore()
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
const { isFocus, handleBlur, handleFocus } = useFocus()
|
||||
const { isFocus, handleBlur, handleFocus } = useFocus();
|
||||
|
||||
/** 登录表单元素的引用 */
|
||||
const loginFormRef = ref<FormInstance | null>(null)
|
||||
const loginFormRef = ref<FormInstance | null>(null);
|
||||
|
||||
/** 登录按钮 Loading */
|
||||
const loading = ref(false)
|
||||
|
||||
const loading = ref(false);
|
||||
//是否验证码登录
|
||||
let loginMethod = ref(true);
|
||||
//倒计时
|
||||
let countdown = ref(60);
|
||||
//是否开启倒计时
|
||||
let isDisabled = ref(false);
|
||||
//是否忘记密码
|
||||
let isForgetPwd = ref(false);
|
||||
/** 登录表单数据 */
|
||||
const loginFormData: LoginRequestData = reactive({
|
||||
username: "admin",
|
||||
password: "12345678"
|
||||
})
|
||||
username: "",
|
||||
password: "",
|
||||
phone: "",
|
||||
mobileCode: "",
|
||||
});
|
||||
|
||||
/** 忘记密码表单数据 */
|
||||
const forgetFormData: forgetRequestData = reactive({
|
||||
// username: "",
|
||||
/** 密码 */
|
||||
password: "",
|
||||
//确认密码
|
||||
confirmPassword: "",
|
||||
//手机号
|
||||
phone: "",
|
||||
//手机验证码
|
||||
mobileCode: "",
|
||||
});
|
||||
|
||||
/** 登录表单校验规则 */
|
||||
const loginFormRules: FormRules = {
|
||||
username: [
|
||||
{ required: true, message: "请输入用户名", trigger: "blur" }
|
||||
username: [{ required: true, message: "请输入用户名", trigger: "blur" }],
|
||||
password: [
|
||||
{ required: true, message: "请输入密码", trigger: "blur" },
|
||||
{ min: 8, max: 16, message: "长度在 8 到 16 个字符", trigger: "blur" },
|
||||
],
|
||||
mobileCode: [
|
||||
{ required: true, message: "请输入手机验证码", trigger: "blur" },
|
||||
],
|
||||
phone: [
|
||||
{ required: true, message: "请输入手机号", trigger: "blur" },
|
||||
{ min: 4, max: 4, message: "请检查验证码是否正确!", trigger: "blur" },
|
||||
],
|
||||
};
|
||||
//忘记密码表单校验
|
||||
const forgetFormRules: FormRules = {
|
||||
phone: [
|
||||
{ required: true, message: "请输入手机号 ", trigger: "blur" },
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
console.log(value.toString());
|
||||
if (!value) {
|
||||
return callback();
|
||||
}
|
||||
if (
|
||||
value.toString().length != 11 ||
|
||||
!/^1[3-9]\d{9}$/.test(value.toString())
|
||||
) {
|
||||
callback(new Error("请检查手机号是否正确!"));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
password: [
|
||||
{ required: true, message: "请输入密码", trigger: "blur" },
|
||||
{ min: 8, max: 16, message: "长度在 8 到 16 个字符", trigger: "blur" }
|
||||
{ min: 8, max: 16, message: "长度在 8 到 16 个字符", trigger: "blur" },
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (!value) {
|
||||
return callback();
|
||||
}
|
||||
if (
|
||||
!/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]+$/.test(
|
||||
value
|
||||
)
|
||||
) {
|
||||
callback(new Error("密码应该包含数字、大小写字母和特殊符号!"));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
code: [
|
||||
{ required: true, message: "请输入验证码", trigger: "blur" }
|
||||
]
|
||||
}
|
||||
|
||||
mobileCode: [{ required: true, message: "请输入验证码", trigger: "blur" }],
|
||||
confirmPassword: [
|
||||
{ required: true, message: "请输入确认密码", trigger: "blur" },
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (!value) {
|
||||
return callback();
|
||||
}
|
||||
if (value !== forgetFormData.password) {
|
||||
callback(new Error("密码和确认密码请保持一致!"));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
};
|
||||
/** 登录 */
|
||||
function handleLogin() {
|
||||
loginFormRef.value?.validate((valid) => {
|
||||
if (!valid) {
|
||||
ElMessage.error("表单校验不通过")
|
||||
return
|
||||
ElMessage.error("表单校验不通过");
|
||||
return;
|
||||
}
|
||||
loading.value = true
|
||||
loginApi(loginFormData).then(({ data }) => {
|
||||
console.log(data)
|
||||
userStore.setToken(data.token)
|
||||
router.push("/")
|
||||
}).catch(() => {
|
||||
loginFormData.password = ""
|
||||
}).finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
})
|
||||
loading.value = true;
|
||||
loginApi(loginFormData)
|
||||
.then(({ data }) => {
|
||||
console.log(data);
|
||||
userStore.setToken(data.token);
|
||||
router.push("/");
|
||||
})
|
||||
.catch(() => {
|
||||
loginFormData.password = "";
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
//手机验证码登录 true是账号密码登录 false是手机验证码登录
|
||||
function mobileCode(type: boolean) {
|
||||
loginMethod.value = type;
|
||||
}
|
||||
// 获取手机验证码
|
||||
function getMobileCode(num: string) {
|
||||
isDisabled.value = true;
|
||||
}
|
||||
// 更新倒计时显示
|
||||
function updateCountdown() {
|
||||
if (countdown.value === 0) {
|
||||
isDisabled.value = false;
|
||||
} else {
|
||||
countdown.value = countdown.value - 1;
|
||||
isDisabled.value = true;
|
||||
}
|
||||
}
|
||||
//忘记密码
|
||||
function forgetPwd() {
|
||||
isForgetPwd.value = true;
|
||||
}
|
||||
watch(isDisabled, (newVal, oldVal) => {
|
||||
if (newVal) {
|
||||
setInterval(updateCountdown, 1000);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -71,25 +185,28 @@ function handleLogin() {
|
||||
<div class="login-card">
|
||||
<div class="title">
|
||||
<div class="title-left">
|
||||
<img src="@@/assets/images/layouts/img.png">
|
||||
</div>
|
||||
<div class="title-text">
|
||||
数据运营管理平台
|
||||
<img src="@@/assets/images/layouts/img.png" />
|
||||
</div>
|
||||
<div class="title-text">数据运营管理平台</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<el-form ref="loginFormRef" :model="loginFormData" :rules="loginFormRules" @keyup.enter="handleLogin">
|
||||
<el-form-item prop="username">
|
||||
<div class="content" v-if="!isForgetPwd">
|
||||
<el-form
|
||||
ref="loginFormRef"
|
||||
:model="loginFormData"
|
||||
:rules="loginFormRules"
|
||||
@keyup.enter="handleLogin"
|
||||
>
|
||||
<el-form-item prop="username" v-show="loginMethod">
|
||||
<el-input
|
||||
v-model.trim="loginFormData.username"
|
||||
placeholder="用户名或手机号"
|
||||
placeholder="用户名"
|
||||
type="text"
|
||||
tabindex="1"
|
||||
:prefix-icon="User"
|
||||
size="large"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item prop="password">
|
||||
<el-form-item prop="password" v-show="loginMethod">
|
||||
<el-input
|
||||
v-model.trim="loginFormData.password"
|
||||
placeholder="密码"
|
||||
@ -102,6 +219,36 @@ function handleLogin() {
|
||||
@focus="handleFocus"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item prop="phone" v-show="!loginMethod">
|
||||
<el-input
|
||||
v-model.trim="loginFormData.phone"
|
||||
placeholder="手机号"
|
||||
tabindex="3"
|
||||
:prefix-icon="Iphone"
|
||||
size="large"
|
||||
maxlength="11"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item prop="mobileCode" v-show="!loginMethod">
|
||||
<el-input
|
||||
v-model.trim="loginFormData.mobileCode"
|
||||
placeholder="手机验证码"
|
||||
tabindex="4"
|
||||
:prefix-icon="Promotion"
|
||||
size="large"
|
||||
@blur="handleBlur"
|
||||
@focus="handleFocus"
|
||||
maxlength="4"
|
||||
/>
|
||||
<button
|
||||
id="sendCode"
|
||||
@click="getMobileCode(loginFormData.mobileCode)"
|
||||
:disabled="isDisabled"
|
||||
>
|
||||
<span v-if="!isDisabled">获取验证码</span>
|
||||
<span v-if="isDisabled">{{ countdown + " 秒后重试" }}</span>
|
||||
</button>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item prop="code">
|
||||
<el-input
|
||||
v-model.trim="loginFormData.code"
|
||||
@ -130,10 +277,108 @@ function handleLogin() {
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item> -->
|
||||
<el-button :loading="loading" type="primary" size="large" @click.prevent="handleLogin">
|
||||
<el-button
|
||||
:loading="loading"
|
||||
type="primary"
|
||||
size="large"
|
||||
@click.prevent="handleLogin"
|
||||
>
|
||||
登 录
|
||||
</el-button>
|
||||
</el-form>
|
||||
<div class="login-btn">
|
||||
<el-link type="primary" @click="mobileCode(false)" v-if="loginMethod"
|
||||
>手机验证码登录</el-link
|
||||
>
|
||||
<el-link type="primary" @click="mobileCode(true)" v-if="!loginMethod"
|
||||
>用户名密码登录</el-link
|
||||
>
|
||||
<el-link type="primary" @click="forgetPwd()">忘记密码? </el-link>
|
||||
</div>
|
||||
</div>
|
||||
<div class="forget-content" v-if="isForgetPwd">
|
||||
<el-form
|
||||
ref="loginFormRef"
|
||||
:model="forgetFormData"
|
||||
:rules="forgetFormRules"
|
||||
>
|
||||
<!-- <el-form-item prop="username" v-show="loginMethod">
|
||||
<el-input
|
||||
v-model.trim="forgetFormData.username"
|
||||
placeholder="用户名"
|
||||
type="text"
|
||||
tabindex="1"
|
||||
:prefix-icon="User"
|
||||
size="large"
|
||||
/>
|
||||
</el-form-item> -->
|
||||
<el-form-item prop="phone">
|
||||
<el-input
|
||||
v-model.trim="forgetFormData.phone"
|
||||
placeholder="手机号"
|
||||
tabindex="3"
|
||||
:prefix-icon="Iphone"
|
||||
size="large"
|
||||
maxlength="11"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item prop="password">
|
||||
<el-input
|
||||
v-model.trim="forgetFormData.mobileCode"
|
||||
placeholder="手机验证码"
|
||||
tabindex="4"
|
||||
:prefix-icon="Promotion"
|
||||
size="large"
|
||||
@blur="handleBlur"
|
||||
@focus="handleFocus"
|
||||
maxlength="4"
|
||||
/>
|
||||
<button
|
||||
id="sendCode"
|
||||
@click="getMobileCode(forgetFormData.mobileCode)"
|
||||
:disabled="isDisabled"
|
||||
>
|
||||
<span v-if="!isDisabled">获取验证码</span>
|
||||
<span v-if="isDisabled">{{ countdown + " 秒后重试" }}</span>
|
||||
</button>
|
||||
</el-form-item>
|
||||
<el-form-item prop="password">
|
||||
<el-input
|
||||
v-model.trim="forgetFormData.password"
|
||||
placeholder="密码"
|
||||
type="password"
|
||||
tabindex="2"
|
||||
:prefix-icon="Lock"
|
||||
size="large"
|
||||
show-password
|
||||
@blur="handleBlur"
|
||||
@focus="handleFocus"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item prop="confirmPassword">
|
||||
<el-input
|
||||
v-model.trim="forgetFormData.confirmPassword"
|
||||
placeholder="确认密码"
|
||||
type="password"
|
||||
tabindex="2"
|
||||
:prefix-icon="Check"
|
||||
size="large"
|
||||
show-password
|
||||
@blur="handleBlur"
|
||||
@focus="handleFocus"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-button
|
||||
class="forgetLogin"
|
||||
:loading="loading"
|
||||
type="primary"
|
||||
size="large"
|
||||
@click.prevent="handleLogin"
|
||||
>
|
||||
提 交
|
||||
</el-button>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -187,7 +432,26 @@ function handleLogin() {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.forget-content {
|
||||
padding: 20px 50px 50px 50px;
|
||||
.forgetLogin {
|
||||
width: 100%;
|
||||
}
|
||||
:deep(.el-form-item__content) {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
#sendCode {
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
background-color: #fff;
|
||||
width: 50%;
|
||||
margin-left: 15px;
|
||||
border: 1px solid #dbdde2;
|
||||
border-radius: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.content {
|
||||
padding: 20px 50px 50px 50px;
|
||||
:deep(.el-input-group__append) {
|
||||
@ -202,10 +466,29 @@ function handleLogin() {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
.login-btn {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.el-button {
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
}
|
||||
:deep(.el-form-item__content) {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
#sendCode {
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
background-color: #fff;
|
||||
width: 50%;
|
||||
margin-left: 15px;
|
||||
border: 1px solid #dbdde2;
|
||||
border-radius: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
7
types/auto/components.d.ts
vendored
7
types/auto/components.d.ts
vendored
@ -18,7 +18,6 @@ declare module 'vue' {
|
||||
ElCard: typeof import('element-plus/es')['ElCard']
|
||||
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
|
||||
ElContainer: typeof import('element-plus/es')['ElContainer']
|
||||
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
|
||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||
ElDivider: typeof import('element-plus/es')['ElDivider']
|
||||
ElDrawer: typeof import('element-plus/es')['ElDrawer']
|
||||
@ -27,21 +26,19 @@ declare module 'vue' {
|
||||
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
|
||||
ElEmpty: typeof import('element-plus/es')['ElEmpty']
|
||||
ElForm: typeof import('element-plus/es')['ElForm']
|
||||
ElFormbtn: typeof import('element-plus/es')['ElFormbtn']
|
||||
ElFormItem: typeof import('element-plus/es')['ElFormItem']
|
||||
ElHeader: typeof import('element-plus/es')['ElHeader']
|
||||
ElIcon: typeof import('element-plus/es')['ElIcon']
|
||||
ElInput: typeof import('element-plus/es')['ElInput']
|
||||
ElLink: typeof import('element-plus/es')['ElLink']
|
||||
ElMain: typeof import('element-plus/es')['ElMain']
|
||||
ElMenu: typeof import('element-plus/es')['ElMenu']
|
||||
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
|
||||
ElOption: typeof import('element-plus/es')['ElOption']
|
||||
ElPopover: typeof import('element-plus/es')['ElPopover']
|
||||
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
|
||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
|
||||
ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
||||
ElTable: typeof import('element-plus/es')['ElTable']
|
||||
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
|
||||
ElTabPane: typeof import('element-plus/es')['ElTabPane']
|
||||
ElTabs: typeof import('element-plus/es')['ElTabs']
|
||||
ElTag: typeof import('element-plus/es')['ElTag']
|
||||
|
Loading…
x
Reference in New Issue
Block a user