parent
63ad76379f
commit
a263a36692
@ -0,0 +1,39 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
// 获取验证码
|
||||||
|
export function sendSmsCode(params) {
|
||||||
|
return request({
|
||||||
|
url: '/uaa/sms/sendSms',
|
||||||
|
method: 'get',
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 登录
|
||||||
|
export async function login(data) {
|
||||||
|
return request({
|
||||||
|
url: '/uaa/sso/appManageLogin',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 获取用户信息
|
||||||
|
export function getUserInfo() {
|
||||||
|
return request({
|
||||||
|
url: '/uc/user/v1/info/token',
|
||||||
|
method: 'get',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 获取权限列表
|
||||||
|
export function getPermission() {
|
||||||
|
return request({
|
||||||
|
url: '/u-admin/uc/ucPermission/listUserMenu',
|
||||||
|
method: 'get',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 退出登录
|
||||||
|
export function logout() {
|
||||||
|
return request({
|
||||||
|
url: '/uaa/sso/v1/logout',
|
||||||
|
method: 'get',
|
||||||
|
});
|
||||||
|
}
|
After Width: | Height: | Size: 323 KiB |
@ -0,0 +1,4 @@
|
|||||||
|
export default {
|
||||||
|
baseURL: import.meta.env.VITE_BASE_URL,
|
||||||
|
requestTimeout: import.meta.env.VITE_REQUEST_TIMEOUT,
|
||||||
|
};
|
@ -0,0 +1,6 @@
|
|||||||
|
import { ElMessage } from 'element-plus/es/components/message/index';
|
||||||
|
import 'element-plus/es/components/message/style/css';
|
||||||
|
export default (app) => {
|
||||||
|
app.use(ElMessage);
|
||||||
|
};
|
||||||
|
export { ElMessage };
|
@ -0,0 +1,6 @@
|
|||||||
|
export default (app) => {
|
||||||
|
Object.entries(import.meta.globEager('./*.js')).forEach((entry) => {
|
||||||
|
entry[1].default?.(app);
|
||||||
|
console.info('[plugins] loaded ' + entry[0].split('/').pop().split('.').reverse().slice(1).reverse().join());
|
||||||
|
});
|
||||||
|
};
|
@ -0,0 +1,79 @@
|
|||||||
|
import { getUserInfo, getPermission } from '@/api/auth';
|
||||||
|
import { ElMessage } from '@/plugins/element-plus';
|
||||||
|
const sms = () => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve(true);
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const login = () => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve({
|
||||||
|
token: 'eyJhbGciOiJSUzI1NiJ9.eyJ1aWQiOjEzMjI1LCJwaG9uZSI6IjEzMjAyMDkwNjAxIiwibG9naW5UeXBlIjo1LCJ1c2VyTm8iOiIxMzIyNSIsIm5pY2tuYW1lIjoi5b-D5LmL5omA5ZCRIiwiZGVwdElkIjpudWxsLCJleHAiOjE2Nzg5NzI5NjksInVzZXJuYW1lIjoiTUNBLTMzYTkifQ.bDgxrGWUYW1iGLQidoj3q4lBXTlI0zKMBslIjN5LuvyLE4O8LPfFFYh33nAlevKuey_tqYQSWn0Cvm81Ywuksn70lGyy5-BEBbLUQCXaFKaWXujc2FzWFIvPHzAXfF16aUzyKkCppR5tfLDQz5cimLHAQBw24Ar69UCMiYJjN8E',
|
||||||
|
});
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
import router from '@/router';
|
||||||
|
const state = () => ({
|
||||||
|
userInfo: null,
|
||||||
|
permission: [],
|
||||||
|
});
|
||||||
|
const getters = {};
|
||||||
|
const mutations = {
|
||||||
|
setUserInfo: (state, data) => (state.userInfo = data),
|
||||||
|
setPermission: (state, data) => (state.permission = data),
|
||||||
|
};
|
||||||
|
const actions = {
|
||||||
|
sms: async ({ commit }, data) => {
|
||||||
|
let res = await sms(data);
|
||||||
|
if (res) {
|
||||||
|
ElMessage.success('验证码已发送');
|
||||||
|
commit('local/sendMessage', {}, { root: true });
|
||||||
|
} else {
|
||||||
|
ElMessage.error('发送验证码失败');
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
login: async ({ commit }, data) => {
|
||||||
|
let res = await login(data);
|
||||||
|
if (res) {
|
||||||
|
ElMessage.success('登陆成功');
|
||||||
|
commit('local/setToken', res.token, { root: true });
|
||||||
|
router.push('/');
|
||||||
|
} else {
|
||||||
|
ElMessage.error('登陆失败');
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
logout: ({ commit }) => {
|
||||||
|
commit('local/setToken', null, { root: true });
|
||||||
|
router.push({ name: 'Login' });
|
||||||
|
},
|
||||||
|
getPermission: async ({ commit }) => {
|
||||||
|
let res = await getPermission();
|
||||||
|
if (res) {
|
||||||
|
commit('setPermission', res);
|
||||||
|
} else {
|
||||||
|
ElMessage.error('加载权限信息失败');
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
getUserInfo: async ({ commit }) => {
|
||||||
|
let res = await getUserInfo();
|
||||||
|
if (res) {
|
||||||
|
commit('setUserInfo', res);
|
||||||
|
} else {
|
||||||
|
ElMessage.error('加载用户信息失败');
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
export default {
|
||||||
|
state,
|
||||||
|
getters,
|
||||||
|
mutations,
|
||||||
|
actions,
|
||||||
|
};
|
@ -0,0 +1,16 @@
|
|||||||
|
const state = () => ({
|
||||||
|
lastSendMessageTime: 0,
|
||||||
|
token: null,
|
||||||
|
});
|
||||||
|
const getters = {};
|
||||||
|
const mutations = {
|
||||||
|
sendMessage: (state) => (state.lastSendMessageTime = new Date().getTime()),
|
||||||
|
setToken: (state, data) => (state.token = data),
|
||||||
|
};
|
||||||
|
const actions = {};
|
||||||
|
export default {
|
||||||
|
state,
|
||||||
|
getters,
|
||||||
|
mutations,
|
||||||
|
actions,
|
||||||
|
};
|
@ -0,0 +1,75 @@
|
|||||||
|
.loading-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 90vh;
|
||||||
|
min-height: 90vh;
|
||||||
|
h1 {
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
.dot-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 98px;
|
||||||
|
.dot {
|
||||||
|
position: relative;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: inline-block;
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
font-size: 64px;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
animation: rotate 1.2s infinite linear;
|
||||||
|
i {
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
background-color: #1890ff;
|
||||||
|
border-radius: 100%;
|
||||||
|
opacity: 0.3;
|
||||||
|
transform: scale(0.75);
|
||||||
|
transform-origin: 50% 50%;
|
||||||
|
animation: spin 1s infinite linear alternate;
|
||||||
|
&:nth-child(1) {
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
&:nth-child(2) {
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
-webkit-animation-delay: 0.4s;
|
||||||
|
animation-delay: 0.4s;
|
||||||
|
}
|
||||||
|
&:nth-child(3) {
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
-webkit-animation-delay: 0.8s;
|
||||||
|
animation-delay: 0.8s;
|
||||||
|
}
|
||||||
|
&:nth-child(4) {
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
-webkit-animation-delay: 1.2s;
|
||||||
|
animation-delay: 1.2s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rotate {
|
||||||
|
to {
|
||||||
|
-webkit-transform: rotate(405deg);
|
||||||
|
transform: rotate(405deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
import config from '@/configs';
|
||||||
|
import store from '@/store';
|
||||||
|
import qs from 'qs';
|
||||||
|
import { ElMessage } from '@/plugins/element-plus';
|
||||||
|
|
||||||
|
const handleResponse = async ({ config, headers, data, status }) => {
|
||||||
|
if (
|
||||||
|
['application/octet-stream', 'application/zip'].indexOf(headers['content-type']) !== -1 ||
|
||||||
|
config['down'] === 'file'
|
||||||
|
) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
let code = data.code || status;
|
||||||
|
console.info('[api]', code, config.method, config.url, data.data);
|
||||||
|
if (code !== 200) {
|
||||||
|
ElMessage.error(data.msg || '服务器异常');
|
||||||
|
switch (code) {
|
||||||
|
case 500:
|
||||||
|
case 501:
|
||||||
|
break;
|
||||||
|
case 524:
|
||||||
|
case 525:
|
||||||
|
case 50008:
|
||||||
|
case 50012:
|
||||||
|
case 50014:
|
||||||
|
store.dispatch('auth/logout');
|
||||||
|
break;
|
||||||
|
case 404:
|
||||||
|
case 9999:
|
||||||
|
console.warn('接口9999', config);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data?.data;
|
||||||
|
};
|
||||||
|
|
||||||
|
const instance = axios.create({
|
||||||
|
baseURL: config.baseURL,
|
||||||
|
timeout: config.requestTimeout,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json;charset=UTF-8',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.interceptors.request.use(
|
||||||
|
(config) => {
|
||||||
|
const token = store.state.local.token;
|
||||||
|
if (token) {
|
||||||
|
config.headers['Authorization'] = `Bearer ${token}`;
|
||||||
|
}
|
||||||
|
if (config.data && config.headers['Content-Type'] === 'application/x-www-form-urlencoded;charset=UTF-8') {
|
||||||
|
config.data = qs.stringify(config.data);
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
instance.interceptors.response.use(
|
||||||
|
(response) => handleResponse(response),
|
||||||
|
(error) => {
|
||||||
|
if (!error.response) {
|
||||||
|
ElMessage.error('服务器无响应');
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return handleResponse(error.response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export default instance;
|
@ -0,0 +1,131 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mask">
|
||||||
|
<div class="box">
|
||||||
|
<div class="title">登录</div>
|
||||||
|
<el-form ref="refsForm" class="content" :model="form" :rules="rules" size="large">
|
||||||
|
<el-form-item prop="phone">
|
||||||
|
<el-input v-model="form.phone" class="ghost" placeholder="请输入手机号码" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item prop="password">
|
||||||
|
<el-input v-model="form.password" type="password" class="ghost" placeholder="请输入登录密码" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item prop="verifyCode">
|
||||||
|
<div class="flex">
|
||||||
|
<el-input v-model="form.verifyCode" class="ghost" placeholder="请输入验证码" />
|
||||||
|
<el-button class="ghost" :disabled="waitTime > 0" @click="handleSms" :loading="loading">
|
||||||
|
{{ waitTime ? waitTime + 'S' : '发送验证码' }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
<el-button class="block" @click="handleLogin" :loading="loading">立即登录</el-button>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const { proxy } = getCurrentInstance();
|
||||||
|
const store = useStore();
|
||||||
|
|
||||||
|
const refsForm = ref(null);
|
||||||
|
const loading = ref(false);
|
||||||
|
const form = reactive({
|
||||||
|
phone: '',
|
||||||
|
password: '',
|
||||||
|
verifyCode: '',
|
||||||
|
});
|
||||||
|
const lastTime = computed(() => store.state.local.lastSendMessageTime);
|
||||||
|
const waitTime = ref(60);
|
||||||
|
const sendStep = ref(60);
|
||||||
|
const rules = reactive({
|
||||||
|
phone: [{ required: true, message: '请输入手机号码' }],
|
||||||
|
password: [{ required: true, message: '请输入登录密码' }],
|
||||||
|
verifyCode: [{ required: true, message: '请输入验证码' }],
|
||||||
|
});
|
||||||
|
|
||||||
|
waitTime.value = Math.max(0, unref(sendStep) - Math.ceil((new Date().getTime() - unref(lastTime)) / 1000));
|
||||||
|
setInterval(() => {
|
||||||
|
waitTime.value = Math.max(0, unref(sendStep) - Math.ceil((new Date().getTime() - unref(lastTime)) / 1000));
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
const handleSms = async () => {
|
||||||
|
if (form.phone) {
|
||||||
|
loading.value = true;
|
||||||
|
await store.dispatch('auth/sms', { phone: form.phone, type: 1 });
|
||||||
|
loading.value = false;
|
||||||
|
} else {
|
||||||
|
proxy.$message.warning('请输入手机号码');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleLogin = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
await unref(refsForm).validate();
|
||||||
|
await store.dispatch('auth/login', form);
|
||||||
|
} catch (e) {
|
||||||
|
console.info('取消登录', e);
|
||||||
|
}
|
||||||
|
loading.value = false;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.mask {
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
background: #000 url('~/global/login-bgp.png') center center / 100% 100% no-repeat;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
color: @color-white;
|
||||||
|
.box {
|
||||||
|
width: 420px;
|
||||||
|
padding: 30px;
|
||||||
|
background: #1a2229;
|
||||||
|
border-radius: 10px;
|
||||||
|
.title {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-size: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
.flex {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
+ .flex {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
.el-button {
|
||||||
|
width: 30%;
|
||||||
|
margin-left: 10px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:deep(.el-input) {
|
||||||
|
input {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:deep(.ghost) {
|
||||||
|
background: none;
|
||||||
|
* {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.block {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: normal;
|
||||||
|
color: #ffffff;
|
||||||
|
width: 100%;
|
||||||
|
height: 40px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 40px;
|
||||||
|
background: linear-gradient(0deg, #fb3a4e, #ff6272);
|
||||||
|
border-radius: 4px;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in new issue