forked from liweijie/education
450 lines
9.7 KiB
Vue
450 lines
9.7 KiB
Vue
<template>
|
||
<div class="login">
|
||
<div class="login-card">
|
||
<aside class="brand-panel">
|
||
<div class="brand-main">
|
||
<div class="brand-mark" aria-hidden="true">教</div>
|
||
<h1 class="brand-title">{{ title }}</h1>
|
||
<p class="brand-tagline">开课计划 · 课表编排 · 成绩管理 · 教学分析</p>
|
||
<div class="brand-illustration" aria-hidden="true">
|
||
<svg-icon icon-class="education" />
|
||
</div>
|
||
</div>
|
||
<p class="brand-footnote">仅限授权单位内部使用</p>
|
||
</aside>
|
||
|
||
<section class="form-panel">
|
||
<div class="form-heading">
|
||
<h2>用户登录</h2>
|
||
<p>请使用内网账号进入系统</p>
|
||
</div>
|
||
|
||
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" label-position="top" @submit.native.prevent>
|
||
<el-form-item label="用户名" prop="username">
|
||
<el-input
|
||
v-model="loginForm.username"
|
||
type="text"
|
||
auto-complete="off"
|
||
placeholder="请输入用户名"
|
||
/>
|
||
</el-form-item>
|
||
<el-form-item label="密码" prop="password">
|
||
<el-input
|
||
v-model="loginForm.password"
|
||
type="password"
|
||
auto-complete="off"
|
||
placeholder="请输入密码"
|
||
show-password
|
||
@keyup.enter.native="handleLogin"
|
||
/>
|
||
</el-form-item>
|
||
<div class="form-extra">
|
||
<el-checkbox v-model="loginForm.rememberMe">记住密码</el-checkbox>
|
||
<router-link v-if="register" class="register-link" to="/register">立即注册</router-link>
|
||
</div>
|
||
<el-form-item class="login-action">
|
||
<el-button
|
||
:loading="loading"
|
||
type="primary"
|
||
class="login-btn"
|
||
native-type="submit"
|
||
@click.native.prevent="handleLogin"
|
||
>
|
||
<span v-if="!loading">登 录</span>
|
||
<span v-else>登 录 中...</span>
|
||
</el-button>
|
||
</el-form-item>
|
||
</el-form>
|
||
|
||
<p class="access-hint">登录后按账号权限进入对应业务,请妥善保管账号与口令。</p>
|
||
<div class="role-tags" aria-label="系统角色">
|
||
<span v-for="role in roles" :key="role.name" class="role-tag" :class="role.tone">{{ role.name }}</span>
|
||
</div>
|
||
<p class="form-footer">{{ footerContent }}</p>
|
||
</section>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import Cookies from "js-cookie"
|
||
import { encrypt, decrypt } from '@/utils/jsencrypt'
|
||
|
||
export default {
|
||
name: "Login",
|
||
data() {
|
||
return {
|
||
title: process.env.VUE_APP_TITLE,
|
||
footerContent: "Copyright © 2018-2026 教学管理信息系统 内部使用",
|
||
roles: [
|
||
{ name: "系统管理员", tone: "admin" },
|
||
{ name: "教务人员", tone: "affairs" },
|
||
{ name: "教研室", tone: "office" },
|
||
{ name: "教员", tone: "teacher" },
|
||
{ name: "学员", tone: "student" }
|
||
],
|
||
loginForm: {
|
||
username: "admin",
|
||
password: "admin123",
|
||
rememberMe: false
|
||
},
|
||
loginRules: {
|
||
username: [
|
||
{ required: true, trigger: "blur", message: "请输入您的账号" }
|
||
],
|
||
password: [
|
||
{ required: true, trigger: "blur", message: "请输入您的密码" }
|
||
]
|
||
},
|
||
loading: false,
|
||
register: false,
|
||
redirect: undefined
|
||
}
|
||
},
|
||
watch: {
|
||
$route: {
|
||
handler: function(route) {
|
||
this.redirect = route.query && route.query.redirect
|
||
},
|
||
immediate: true
|
||
}
|
||
},
|
||
created() {
|
||
this.getCookie()
|
||
},
|
||
methods: {
|
||
getCookie() {
|
||
const username = Cookies.get("username")
|
||
const password = Cookies.get("password")
|
||
const rememberMe = Cookies.get('rememberMe')
|
||
this.loginForm = {
|
||
username: username === undefined ? this.loginForm.username : username,
|
||
password: password === undefined ? this.loginForm.password : decrypt(password),
|
||
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
|
||
}
|
||
},
|
||
handleLogin() {
|
||
this.$refs.loginForm.validate(valid => {
|
||
if (valid) {
|
||
this.loading = true
|
||
if (this.loginForm.rememberMe) {
|
||
Cookies.set("username", this.loginForm.username, { expires: 30 })
|
||
Cookies.set("password", encrypt(this.loginForm.password), { expires: 30 })
|
||
Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 })
|
||
} else {
|
||
Cookies.remove("username")
|
||
Cookies.remove("password")
|
||
Cookies.remove('rememberMe')
|
||
}
|
||
const loginData = {
|
||
username: this.loginForm.username,
|
||
password: this.loginForm.password
|
||
}
|
||
this.$store.dispatch("Login", loginData).then(() => {
|
||
this.$router.push({ path: this.redirect || "/" }).catch(()=>{})
|
||
}).catch(() => {
|
||
this.loading = false
|
||
})
|
||
}
|
||
})
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||
.login {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
min-height: 100%;
|
||
padding: 28px 20px;
|
||
background:
|
||
radial-gradient(circle at 18% 16%, rgba(11, 107, 85, 0.28), transparent 42%),
|
||
radial-gradient(circle at 86% 82%, rgba(198, 155, 60, 0.10), transparent 36%),
|
||
#10241f;
|
||
}
|
||
|
||
.login-card {
|
||
display: flex;
|
||
width: min(1080px, 100%);
|
||
overflow: hidden;
|
||
background: linear-gradient(160deg, #0c7a62 0%, #0b6b55 46%, #084c3f 100%);
|
||
border-radius: 18px;
|
||
box-shadow: 0 22px 56px rgba(8, 36, 30, 0.32);
|
||
}
|
||
|
||
.brand-panel {
|
||
display: flex;
|
||
flex-direction: column;
|
||
position: relative;
|
||
width: 42%;
|
||
padding: 48px 40px 24px;
|
||
color: #ffffff;
|
||
background: transparent;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.brand-main {
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
flex: 1;
|
||
min-height: 0;
|
||
padding-bottom: 12px;
|
||
}
|
||
|
||
.brand-mark {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
position: absolute;
|
||
top: 48px;
|
||
left: 40px;
|
||
width: 48px;
|
||
height: 48px;
|
||
color: #7a5410;
|
||
font-size: 26px;
|
||
font-weight: 700;
|
||
background: #e4c56a;
|
||
border-radius: 10px;
|
||
box-shadow: 0 4px 10px rgba(16, 36, 28, 0.18);
|
||
}
|
||
|
||
.brand-title {
|
||
margin: 0 0 10px;
|
||
font-size: 32px;
|
||
font-weight: 700;
|
||
line-height: 1.25;
|
||
letter-spacing: 1px;
|
||
}
|
||
|
||
.brand-tagline {
|
||
margin: 0;
|
||
color: rgba(255, 255, 255, 0.78);
|
||
font-size: 13px;
|
||
letter-spacing: 0.4px;
|
||
}
|
||
|
||
.brand-illustration {
|
||
width: 116px;
|
||
height: 116px;
|
||
margin-top: 44px;
|
||
color: rgba(255, 255, 255, 0.12);
|
||
font-size: 116px;
|
||
line-height: 1;
|
||
transform: rotate(-6deg);
|
||
}
|
||
|
||
.brand-illustration .svg-icon {
|
||
display: block;
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.brand-footnote {
|
||
margin: 16px 0 0;
|
||
color: rgba(255, 255, 255, 0.52);
|
||
font-size: 12px;
|
||
}
|
||
|
||
.form-panel {
|
||
display: flex;
|
||
flex-direction: column;
|
||
flex: 1;
|
||
padding: 56px 56px 28px;
|
||
background: #ffffff;
|
||
}
|
||
|
||
.form-heading {
|
||
margin-bottom: 32px;
|
||
}
|
||
|
||
.form-heading h2 {
|
||
margin: 0 0 8px;
|
||
color: #172b25;
|
||
font-size: 28px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.5px;
|
||
}
|
||
|
||
.form-heading p {
|
||
margin: 0;
|
||
color: #7a8a85;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.login-form {
|
||
::v-deep .el-form-item {
|
||
margin-bottom: 22px;
|
||
}
|
||
|
||
::v-deep .el-form-item__label {
|
||
float: none;
|
||
display: block;
|
||
padding: 0 0 8px;
|
||
line-height: 1.2;
|
||
color: #172b25;
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
::v-deep .el-form-item__content {
|
||
margin-left: 0 !important;
|
||
line-height: normal;
|
||
}
|
||
|
||
::v-deep .el-input__inner {
|
||
height: 48px;
|
||
padding: 0 16px;
|
||
color: #172b25;
|
||
background: #f3f6f5;
|
||
border: 1px solid transparent;
|
||
border-radius: 10px;
|
||
box-shadow: none;
|
||
}
|
||
|
||
::v-deep .el-input__inner:hover {
|
||
border-color: #c8d8d2;
|
||
}
|
||
|
||
::v-deep .el-input__inner:focus {
|
||
background: #ffffff;
|
||
border-color: #0b6b55;
|
||
box-shadow: 0 0 0 3px rgba(11, 107, 85, 0.10);
|
||
}
|
||
|
||
::v-deep .el-input__suffix {
|
||
right: 10px;
|
||
}
|
||
|
||
::v-deep .el-form-item__error {
|
||
padding-top: 4px;
|
||
}
|
||
}
|
||
|
||
.form-extra {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin: -6px 0 18px;
|
||
|
||
::v-deep .el-checkbox__label {
|
||
color: #52645f;
|
||
font-size: 13px;
|
||
font-weight: 400;
|
||
}
|
||
}
|
||
|
||
.register-link {
|
||
color: #0b6b55;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.login-action {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.login-btn {
|
||
width: 100%;
|
||
height: 48px;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
letter-spacing: 6px;
|
||
border-radius: 10px;
|
||
}
|
||
|
||
.access-hint {
|
||
margin: 18px 0 16px;
|
||
color: #7a8a85;
|
||
font-size: 12px;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.role-tags {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
}
|
||
|
||
.role-tag {
|
||
padding: 4px 10px;
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
line-height: 1.6;
|
||
border-radius: 999px;
|
||
}
|
||
|
||
.role-tag.admin {
|
||
color: #3d6ea8;
|
||
background: #e8f1fb;
|
||
}
|
||
|
||
.role-tag.affairs {
|
||
color: #0b6b55;
|
||
background: #e8f3ef;
|
||
}
|
||
|
||
.role-tag.office {
|
||
color: #b77a17;
|
||
background: #f8f1e4;
|
||
}
|
||
|
||
.role-tag.teacher {
|
||
color: #6b5b93;
|
||
background: #f0eaf6;
|
||
}
|
||
|
||
.role-tag.student {
|
||
color: #9a7424;
|
||
background: #f7f0de;
|
||
}
|
||
|
||
.form-footer {
|
||
margin-top: auto;
|
||
padding-top: 28px;
|
||
color: #9aa7a3;
|
||
font-size: 12px;
|
||
text-align: center;
|
||
}
|
||
|
||
@media (max-width: 900px) {
|
||
.login {
|
||
align-items: flex-start;
|
||
padding: 16px;
|
||
}
|
||
|
||
.login-card {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.brand-panel {
|
||
width: 100%;
|
||
padding: 28px 24px 20px;
|
||
}
|
||
|
||
.brand-mark {
|
||
position: static;
|
||
margin-bottom: 22px;
|
||
}
|
||
|
||
.brand-title {
|
||
font-size: 26px;
|
||
}
|
||
|
||
.brand-illustration {
|
||
display: none;
|
||
}
|
||
|
||
.form-panel {
|
||
padding: 32px 24px 20px;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 640px) {
|
||
.form-heading h2 {
|
||
font-size: 24px;
|
||
}
|
||
}
|
||
</style>
|