rax-medical/src/views/login/login.vue
2024-05-17 12:06:29 +08:00

540 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="login-page">
<div class="left-content move_4"></div>
<div class="right-content">
<div class="select-hospital-box">
<el-select class="select-hospital" v-model="currentHospital" size="small" @change="selectHospital">
<el-option v-for="item in hospitals" :key="item.id" :label="item.name" :value="item.id"/>
</el-select>
</div>
<img v-show="!isShowRegister" class="logo move_2" src="@/assets/imgs/logo.png">
<div v-if="!isShowRegister" class="login-block move_2">
<div class="login-way">
<span :class="passwordLogin && 'active'" @click="passwordLogin = true">密码登录</span>
<span :class="!passwordLogin && 'active'" @click="passwordLogin = false">验证码登录</span>
</div>
<el-form ref="loginFormRef" :model="loginParams" :rules="loginRules" label-width="0" size="small">
<div class="login-form password-login" v-if="passwordLogin">
<el-form-item prop="account">
<el-input v-model="loginParams.account" placeholder="请输入用户名">
<template #prepend>
<el-icon>
<User/>
</el-icon>
</template>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input v-model="loginParams.password" type="password" show-password placeholder="请输入密码">
<template #prepend>
<el-icon>
<Lock/>
</el-icon>
</template>
</el-input>
</el-form-item>
<el-button :loading="loading" class="login-btn" type="primary" @click="login('password')">登录</el-button>
<span class="register-btn" @click="getCaptchaCode()">注册账号</span>
</div>
<div class="login-form code-login" v-else>
<el-form-item prop="phone">
<el-input v-model="loginParams.phone" placeholder="请输入手机号">
<template #prepend>
<div @click.stop style="display: flex;align-items: center;">
<el-dropdown @command="selectPhoneArea">
<span style="color: #909399;">{{ loginParams.phoneArea }}<el-icon>
<DCaret/>
</el-icon></span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item v-for="item in phoneAreas" :command="item">{{
item
}}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
</el-input>
</el-form-item>
<el-form-item prop="code">
<el-input v-model="loginParams.code" placeholder="请输入6位短信验证码">
<template #append>
<span class="send-btn" @click="sendCode">{{ loginParams.sendText }}</span>
</template>
</el-input>
</el-form-item>
<el-button class="login-btn" type="primary" @click="login('code')">登录</el-button>
</div>
</el-form>
</div>
<div v-else class="register-block move_2">
<div class="header-box">
<span class="title">新用户申请</span>
<el-icon @click="isShowRegister = false">
<Close/>
</el-icon>
</div>
<el-form ref="registerFormRef" :model="registerParams" :rules="registerRules" label-width="100">
<el-form-item label="用户名" prop="username">
<el-input v-model="registerParams.username" placeholder="请输入用户名"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="registerParams.password" type="password" show-password
placeholder="请输入密码"></el-input>
</el-form-item>
<el-form-item label="姓名" prop="name">
<el-input v-model="registerParams.name" placeholder="请输入姓名"></el-input>
</el-form-item>
<el-form-item label="手机号" prop="phone">
<el-input v-model="registerParams.phone" placeholder="请输入手机号"></el-input>
</el-form-item>
<el-form-item label="医院" prop="hospital">
<el-select v-model="registerParams.hospital" style="width: 100%;">
<el-option v-for="item in hospitals" :key="item.id" :label="item.name"
:value="item.id"/>
</el-select>
</el-form-item>
<el-form-item label="性别" prop="sex">
<el-radio-group v-model="registerParams.sex">
<el-radio label="男"/>
<el-radio label="女"/>
</el-radio-group>
</el-form-item>
<el-form-item label="验证码" prop="code">
<el-input v-model="registerParams.code" placeholder="请输入验证码"
style="width: calc(100% - 110px);"></el-input>
<img width="100" height="32" style="margin-left: 10px;" :src="captchaImgUrl"/>
<a class="change_img" @click="refreshImg" href="#">看不清?</a>
</el-form-item>
</el-form>
<div class="footer-box">
<el-button type="primary" @click="register">注 册</el-button>
<span @click="isShowRegister = false">已有账号?</span>
</div>
</div>
</div>
</div>
<SliderVerify v-model:isShowSelf="sliderVConf.isShowSelf" :width="sliderVConf.width" :imgUrl="sliderImgUrl"
:height="sliderVConf.height" @success="sliderSuccess" @close="sliderClose"></SliderVerify>
</template>
<script lang='ts' setup>
import {ElMessage, ElMessageBox, ElNotification} from 'element-plus';
//引入获取当前时间的函数
import {getTime} from '@/utils/time';
import {onMounted, reactive, ref} from 'vue'
import {useRoute, useRouter} from 'vue-router'
import {useUserStore} from '@/stores/user-info-store'
import {getPhoneAreasData} from '@/static-data/core'
import {v4} from "uuid";
import SliderVerify from "@/components/SliderVerify/index.vue";
import * as loginApi from "@/api/login";
import {Session} from "@/utils/storage";
import * as hospitalApi from "@/api/hospital";
//引入用户相关的小仓库
//import useUserStore from "@/stores/user-info-store";
//let useStore = useUserStore();
const router = useRouter()
const hospitals = ref([] as any)
const phoneAreas: any = getPhoneAreasData()
//定义变量控制按钮加载效果
let loading = ref(false);
//自定义校验规则函数
const validatorPhone = (rule: any, value: any, callback: any) => {
var isPhone = /^1[34578]\d{9}$/;
if (value.indexOf('****') >= 0) {
return callback().trim();
}
if (!isPhone.test(value)) {
callback(new Error('请输入合法手机号'));
} else {
callback();
}
}
const loginRules = reactive({
account: [
{required: true, message: '请输入用户名', trigger: 'change'},
{min: 2, max: 18, message: "长度在 6 到 18个字符"},
//{pattern:/^(?![^A-Za-z]+$)(?![^0-9]+$)[0-9A-Za-z_]{4,15}$/, message: '长度在4-15位数字、字母、下划线的组合其中数字和字母必须同时存在'}
],
password: [
{required: true, message: '请输入密码', trigger: 'blur'},
{min: 5, max: 25, message: '长度在 5 到 25个字符'},
{pattern: /^(\w){5,25}$/, message: '长度在5-25之间以字母、数字、下划线'}
],
phone: [
{required: true, validator: validatorPhone, trigger: 'blur'},
],
code: [
{required: true, message: '请输入验证码', trigger: 'blur'},
]
})
const registerRules = reactive({
username: [
{required: true, message: '请输入用户名', trigger: 'change'},
{min: 2, max: 18, message: "长度在 6 到 18个字符"},
//{pattern:/^(?![^A-Za-z]+$)(?![^0-9]+$)[0-9A-Za-z_]{4,15}$/, message: '长度在4-15位数字、字母、下划线的组合其中数字和字母必须同时存在'}
],
password: [
{required: true, message: '请输入密码', trigger: 'blur'},
{min: 5, max: 25, message: '长度在 5 到 25个字符'},
{pattern: /^(\w){5,25}$/, message: '长度在5-25之间以字母、数字、下划线'}
],
name: [
{required: true, message: '请输入真实姓名', trigger: 'blur'},
{pattern: /^[\u4E00-\u9FA5]{2,6}$/, message: '请输入2-6个汉字'}
],
phone: [
{required: true, validator: validatorPhone, trigger: 'change'},
],
hospital: [
{required: true, message: '请选择医院', trigger: 'blur'},
],
code: [
{required: true, message: '请输入验证码', trigger: 'blur'},
]
})
const loginFormRef = ref()
const registerFormRef = ref()
const slideVerifyRef = ref()
const currentHospital = ref("")
const isShowRegister = ref(false)
const passwordLogin = ref(true)
const loginParams = ref({
account: 'admin',
name: '',
password: '123456',
phone: '',
phoneArea: phoneAreas[0],
code: '',
isSendCode: false,
sendTimer: 0,
sendText: '获取短信验证码'
})
const registerParams = ref({
username: '',
password: '',
name: '',
phone: '',
hospital: '',
sex: '',
code: ''
})
const sliderVConf = ref({
isShowSelf: false,
width: 400,
height: 200
})
const captchaImgUrl = ref('')
const sliderImgUrl = ref('')
let randomStr = ""
onMounted(() => {
hospitalApi.getHospitalList().then((res: any) => {
if (res.data) {
hospitals.value = res.data
} else {
hospitals.value.length = 0
}
})
})
const selectHospital = (e: string) => {
}
const register = async () => {
await registerFormRef.value.validate((valid: any, fields: any) => {
if (valid) {
loginApi.register({...registerParams.value, randomStr}).then(data => {
ElMessageBox.confirm(
'注册成功,是否登录?',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'success',
draggable: true
}
).then(() => {
loginParams.value.account = registerFormRef.value.account
loginParams.value.name = registerFormRef.value.name
currentHospital.value = registerFormRef.value.hospital
isShowRegister.value = false;
}).catch(() => {
})
})
} else {
// console.log('error submit!', fields)
}
})
}
const selectPhoneArea = (e: string) => {
loginParams.value.phoneArea = e
}
const sendCode = () => {
if (loginParams.value.isSendCode) return
let num = 60
ElMessage.success('发送成功!')
loginParams.value.isSendCode = true
loginParams.value.sendText = '请' + num + '秒后重新发送'
loginParams.value.sendTimer = setInterval(() => {
num--
if (num > 0) {
loginParams.value.sendText = '请' + num + '秒后重新发送'
} else {
loginParams.value.isSendCode = false
loginParams.value.sendText = '重新获取短信验证码'
clearInterval(loginParams.value.sendTimer)
}
}, 1000);
}
const login = async (type: string) => {
//加载效果:开始加载
if (!currentHospital.value) {
ElMessage.warning('请在右上角选择院区')
return
}
//加载效果:开始加载
loading.value = true;
//保证全部表单正常再发请求
await loginFormRef.value.validate((valid: any, fields: any) => {
if (valid) {
sliderVConf.value.isShowSelf = true;
}
})
}
function getCaptchaCode() {
isShowRegister.value = true
refreshImg()
}
function refreshImg() {
randomStr = v4()
captchaImgUrl.value = '/api/admin/code/textImage?randomStr=' + randomStr
}
function sliderSuccess() {
loginApi.login({
username: loginParams.value.account, // 用户名
password: loginParams.value.password, // 密码
randomStr: v4(),
hospitalId: currentHospital.value
}).then((data: any) => {
sliderVConf.value.isShowSelf = false
if (data.code == 1 || data.error) {
ElMessage.error(data.msg ? data.msg : data.error)
loading.value = false
} else {
// 存储token 信息
ElNotification({
type: 'success',
message: '欢迎回来',
title: `HI,${getTime()}`
});
loginPost(data)
router.removeRoute("root");
router.addRoute({
name: "root",
path: "/",
redirect: "/home"
})
router.replace('/home')
}
})
}
function sliderClose() {
loading.value = false
}
const loginPost = (data: any) => {
Session.set('token', data.access_token);
Session.set('refresh_token', data.refresh_token);
useUserStore().setlogin('account', data.username)
useUserStore().setlogin('name', data.user_info.chineseName || '暂未设置姓名')
useUserStore().setlogin("hospitalId", data.user_info.hospitalId)
}
</script>
<style lang='scss' scoped>
.login-page {
width: 100%;
height: 100%;
display: flex;
background-color: #F8F8F8;
.left-content {
width: 50%;
height: 100%;
background: url(@/assets/imgs/login/login_bck.png) no-repeat;
background-size: cover;
}
.right-content {
position: relative;
width: 50%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.select-hospital-box {
position: absolute;
top: 25px;
right: 25px;
.select-hospital {
width: 12rem;
margin-right: 20px;
}
}
.logo {
height: 70px;
}
.login-block {
width: 65%;
height: 430px;
min-width: 500px;
min-height: 300px;
padding: 50px;
margin-top: 20px;
background: white;
.login-way {
font-size: 18px;
color: #909399;
span {
cursor: pointer;
margin-right: 10px;
}
.active {
color: $main-color;
font-weight: 600;
}
}
.login-form {
:deep(.el-input) {
font-size: 16px;
margin-top: 20px;
.el-input-group__prepend,
.el-input__wrapper,
.el-input-group__append {
box-shadow: none;
border-bottom: 1px solid $border-color;
background-color: transparent;
padding: 10px 20px;
}
.el-input-group__prepend,
.el-input-group__append {
position: relative;
&::after {
content: '';
position: absolute;
width: 1px;
height: 16px;
top: calc(50% - 8px);
right: 0;
background-color: $border-color;
}
}
.el-input-group__append::after {
right: auto;
left: 0;
}
}
.send-btn {
cursor: pointer;
color: $main-color;
font-weight: 600;
}
}
.login-btn {
width: 100%;
margin-top: 40px;
font-size: 20px;
font-weight: 600;
padding: 25px 0 25px 0.3em;
border-radius: 0px;
letter-spacing: 0.3em;
}
.register-btn {
cursor: pointer;
float: right;
color: $main-color;
margin-top: 20px;
}
}
.register-block {
width: 65%;
min-width: 500px;
min-height: 300px;
padding: 50px;
background: white;
.header-box {
display: flex;
justify-content: space-between;
margin-bottom: 30px;
.title {
font-size: 20px;
color: $main-color;
font-weight: 600;
}
.el-icon {
cursor: pointer;
}
}
.footer-box {
padding-left: 100px;
display: flex;
justify-content: space-between;
align-items: center;
.el-button {
font-size: 16px;
padding: 5px 50px;
}
& > span {
cursor: pointer;
font-size: 18px;
color: #909399;
}
}
}
}
}
</style>