🚩后羿 - TenSunS Release v1.0.0

pull/79/head
starsliao 2023-07-30 22:14:25 +08:00
parent 7e1bc59d01
commit 0acf3e9aa9
16 changed files with 444 additions and 557 deletions

View File

@ -10,7 +10,7 @@
[![OSCS Status](https://www.oscs1024.com/platform/badge/starsliao/ConsulManager.svg?size=small)](https://www.murphysec.com/dr/Zoyt5g0huRavAtItj2)
</div>
![tensuns-arch](https://github.com/starsliao/ConsulManager/blob/main/tensuns-arch.png)
![tensuns-arch](https://github.com/starsliao/ConsulManager/blob/main/screenshot/tensuns-arch.png)
## 🏷目录
* [🚀概述](#概述)

View File

@ -11,7 +11,6 @@ from huaweicloudsdkdcs.v2.region.dcs_region import DcsRegion
from huaweicloudsdkrds.v3 import *
from huaweicloudsdkrds.v3.region.rds_region import RdsRegion
import sys,datetime,hashlib,traceback
from units import consul_kv
from units.cloud import sync_ecs
from units.cloud import sync_rds
from units.cloud import sync_redis

View File

@ -17,30 +17,56 @@ api = Api(blueprint)
parser = reqparse.RequestParser()
parser.add_argument('username',type=str)
parser.add_argument('password',type=str)
parser.add_argument('title',type=str)
parser.add_argument('ldap',type=str)
parser.add_argument('file',type=FileStorage, location="files", help="File is wrong.")
class Logo(Resource):
@token_auth.auth.login_required
def post(self, logo_opt):
if logo_opt == 'biglogo':
if logo_opt == 'nologo':
consul_kv.put_kv('ConsulManager/img/biglogo','R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7')
consul_kv.put_kv('ConsulManager/img/isbig',True)
return {"code": 20000, "data": "设置成功!"}
elif logo_opt == 'title':
title = parser.parse_args().get("title")
consul_kv.put_kv('ConsulManager/img/logintitle',title)
return {"code": 20000, "data": "设置成功!"}
elif logo_opt == 'rebig':
consul_kv.del_key('ConsulManager/img/biglogo')
consul_kv.put_kv('ConsulManager/img/isbig',True)
return {"code": 20000, "data": "设置成功!"}
elif logo_opt == 'resmall':
consul_kv.del_key('ConsulManager/img/smallogo')
consul_kv.put_kv('ConsulManager/img/isbig',False)
return {"code": 20000, "data": "设置成功!"}
elif logo_opt == 'rebgimg':
consul_kv.del_key('ConsulManager/img/bgimg')
return {"code": 20000, "data": "设置成功!"}
elif logo_opt == 'retitle':
consul_kv.del_key('ConsulManager/img/logintitle')
return {"code": 20000, "data": "设置成功!"}
elif logo_opt == 'biglogo':
consul_kv_path = 'ConsulManager/img/biglogo'
isbig = True
consul_kv.put_kv('ConsulManager/img/isbig',True)
elif logo_opt == 'smallogo':
consul_kv_path = 'ConsulManager/img/smallogo'
isbig = False
consul_kv.put_kv('ConsulManager/img/isbig',False)
elif logo_opt == 'bgimg':
consul_kv_path = 'ConsulManager/img/bgimg'
img = parser.parse_args().get("file")
try:
b64img = base64.b64encode(img.read()).decode('utf-8')
consul_kv.put_kv(consul_kv_path,b64img)
consul_kv.put_kv(f'ConsulManager/img/isbig',isbig)
return {"code": 20000, "data": f"导入成功!"}
return {"code": 20000, "data": "导入成功!"}
except Exception as e:
logger.error(f"【logo】导入失败,{e}\n{traceback.format_exc()}")
return {"code": 50000, "data": f"导入失败!"}
return {"code": 50000, "data": "导入失败!"}
def get(self, logo_opt):
if logo_opt == 'logo':
isbig = consul_kv.get_value(f'ConsulManager/img/isbig')
isbig = consul_kv.get_value('ConsulManager/img/isbig')
if isbig == {}:
isbig = True
if isbig:
@ -52,6 +78,19 @@ class Logo(Resource):
return {"code": 20000, "isbig": isbig, "data": 'data:image/png;base64,' + b64logo}
else:
return {"code": 20000, "isbig": isbig, "data": 'default'}
elif logo_opt == 'title':
title = consul_kv.get_value('ConsulManager/img/logintitle')
if title:
return {"code": 20000, "data": title}
else:
return {"code": 20000, "data": 'default'}
elif logo_opt == 'bgimg':
bgimg = consul_kv.get_value('ConsulManager/img/bgimg')
if bgimg:
return {"code": 20000, "data": 'data:image/png;base64,' + bgimg}
else:
return {"code": 20000, "data": 'default'}
class User(Resource):
@token_auth.auth.login_required
def get(self, user_opt):

View File

Before

Width:  |  Height:  |  Size: 377 KiB

After

Width:  |  Height:  |  Size: 377 KiB

View File

@ -9,7 +9,7 @@
"build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview",
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
"lint": "eslint --ext .js,.vue src",
"lint": "eslint --fix --ext .js,.vue src",
"test:unit": "jest --clearCache && vue-cli-service test:unit",
"test:ci": "npm run lint && npm run test:unit"
},

View File

@ -7,3 +7,57 @@ export function logo() {
})
}
export function postnologo() {
return request({
url: '/api/login/nologo',
method: 'post'
})
}
export function rebig() {
return request({
url: '/api/login/rebig',
method: 'post'
})
}
export function resmall() {
return request({
url: '/api/login/resmall',
method: 'post'
})
}
export function rebgimg() {
return request({
url: '/api/login/rebgimg',
method: 'post'
})
}
export function retitle() {
return request({
url: '/api/login/retitle',
method: 'post'
})
}
export function getbgimg() {
return request({
url: '/api/login/bgimg',
method: 'get'
})
}
export function getitle() {
return request({
url: '/api/login/title',
method: 'get'
})
}
export function postitle(title) {
return request({
url: '/api/login/title',
method: 'post',
data: { title }
})
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

After

Width:  |  Height:  |  Size: 114 KiB

View File

@ -46,7 +46,7 @@ Object.keys(filters).forEach(key => {
})
Vue.config.productionTip = false
Vue.prototype.VER = 'v0.12.8'
Vue.prototype.VER = 'v1.0.0'
new Vue({
el: '#app',

View File

@ -275,15 +275,15 @@ export const constantRoutes = [
{
path: '/settings',
component: Layout,
redirect: '/settings/ldap',
redirect: '/settings/logo',
name: '系统设置',
meta: { title: '系统设置', icon: 'el-icon-setting' },
children: [
{
path: 'logo',
name: '修改Logo',
name: '自定义登录页',
component: () => import('@/views/ldap/logo'),
meta: { title: '修改Logo', icon: 'el-icon-lock' }
meta: { title: '自定义登录页', icon: 'el-icon-ice-cream' }
},
{
path: 'ldap',

View File

@ -1,6 +1,6 @@
module.exports = {
title: 'Consul Manager',
title: '后羿 - TenSunS',
/**
* @type {boolean} true | false

View File

@ -1,12 +1,27 @@
<template>
<div class="dashboard-container">
<el-alert type="success" center close-text="">
<el-link type="success" href="https://github.com/starsliao/ConsulManager#%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5" target="_blank">🥇最佳实践ConsulManager应用场景与使用帮助</el-link>
<el-link type="success" href="https://github.com/starsliao/TenSunS#%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5" target="_blank">🏆TenSunS应用场景与使用帮助</el-link>
</el-alert><br>
<el-badge :value="1" class="mark">
<el-link :underline="false" type="primary" href="https://github.com/starsliao/ConsulManager" target="_blank" class="dashboard-text">🚀StarsL.cn</el-link>
<el-link :underline="false" type="primary" href="https://github.com/starsliao/TenSunS" target="_blank" class="dashboard-text">🚀StarsL.cn</el-link>
</el-badge>
<el-timeline>
<el-timeline-item timestamp="2023/07/31" placement="top">
<el-card>
<h4>v1.0.0</h4>
<p>🚩ConsulManager更名<strong>后羿TenSunS</strong>,发布v1.0.0</p>
<p>🥇更新License为:WTFPL,全部权利授予使用者,无任何限制与要求</p>
<p>🌟新增自定义登录页,可在系统设置中修改横幅/LOGO/名称/壁纸,支持多种展示风格</p>
<p>🚀新增基于docker/K8S的一键部署脚本,Consul独立部署脚本,安装脚本统一放置install目录</p>
<p>💠新增架构图,便于使用者了解TenSunS整体架构</p>
<p>🎉新增使用登记,分享您的使用经验与实践</p>
<p><el-button type="primary" size="mini" icon="el-icon-star-off" circle />支持阿里/华为/腾讯云采集ECS外网IP功能</p>
<p><el-button type="success" size="mini" icon="el-icon-star-off" circle />支持华为云ECS采集到期日指标</p>
<p><el-button type="warning" size="mini" icon="el-icon-star-off" circle />优化云ECS资源推送到JumpServer3.x资产管理</p>
<p><el-button type="info" size="mini" icon="el-icon-star-off" circle />优化自建资源/站点监控查询分页</p>
</el-card>
</el-timeline-item>
<el-timeline-item timestamp="2023/07/26" placement="top">
<el-card>
<h4>v0.12.8</h4>

View File

@ -1,51 +1,157 @@
<template>
<div>
<el-upload
class="avatar-uploader"
action="/api/login/biglogo"
:headers="myHeaders"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
>
<img v-if="imageUrl" :src="imageUrl" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon" />
</el-upload>
<el-upload
class="avatar-uploader"
action="/api/login/smallogo"
:headers="myHeaders"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
>
<img v-if="imageUrl" :src="imageUrl" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon" />
</el-upload>
<el-alert type="success" center close-text="">
图片大小不能超过512KB,建议使用<el-link type="primary" href="https://tinypng.com/" target="_blank">TinyPNG</el-link>线
</el-alert>
<el-row>
<el-col :span="8" align='center'><div class="grid-content bg-purple">
<el-alert
title="更换背景壁纸(自动拉伸)"
center
:closable="false"
type="info"
effect="dark"
/>
<el-upload
class="avatar-uploader"
action="/api/login/bgimg"
:headers="myHeaders"
:show-file-list="false"
:on-success="handleAvatarSuccess1"
:before-upload="beforeAvatarUpload"
>
<img v-if="imageUrl1" :src="imageUrl1" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon" />
</el-upload>
<br><el-button type="primary" @click="setrebgimg"></el-button>
</div></el-col>
<el-col :span="8" align='center'><div class="grid-content bg-purple-light">
<el-alert
title="使用横幅风格(自动缩放720*330,并隐藏名称)"
center
:closable="false"
type="warning"
effect="dark"
/>
<el-upload
class="avatar-uploader"
action="/api/login/biglogo"
:headers="myHeaders"
:show-file-list="false"
:on-success="handleAvatarSuccess2"
:before-upload="beforeAvatarUpload"
>
<img v-if="imageUrl2" :src="imageUrl2" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon" />
</el-upload>
<br><el-button type="primary" @click="setrebig"></el-button>
</div></el-col>
<el-col :span="8" align='center'><div class="grid-content bg-purple-light">
<el-alert
title="使用LOGO+名称风格(自动缩放100*100,并显示名称)"
center
:closable="false"
type="success"
effect="dark"
/>
<el-upload
class="avatar-uploader"
action="/api/login/smallogo"
:headers="myHeaders"
:show-file-list="false"
:on-success="handleAvatarSuccess3"
:before-upload="beforeAvatarUpload"
>
<img v-if="imageUrl3" :src="imageUrl3" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon" />
</el-upload>
<br><el-button type="primary" @click="setresmall">LOGO</el-button>
</div></el-col>
</el-row><br>
<el-divider><i class="el-icon-s-promotion" /></el-divider>
<el-form :inline="true" :model="formtitle" class="demo-form-inline">
&nbsp;&nbsp;<el-form-item label="登录页名称">
<el-input v-model="formtitle.title" placeholder="请输入" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="setitle"></el-button>
</el-form-item>
<el-form-item>
&nbsp;&nbsp;&nbsp;&nbsp;<el-button type="info" icon="el-icon-refresh-left" @click="setretitle"></el-button>
</el-form-item>
<el-form-item>
&nbsp;&nbsp;&nbsp;&nbsp;<el-button type="warning" icon="el-icon-magic-stick" @click="setnologo"></el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import { postitle, postnologo, rebig, resmall, rebgimg, retitle } from '@/api/login'
export default {
data() {
return {
myHeaders: { Authorization: this.$store.getters.token },
imageUrl: ''
imageUrl1: '',
imageUrl2: '',
imageUrl3: '',
formtitle: { title: '' }
}
},
methods: {
handleAvatarSuccess(res, file) {
this.imageUrl = URL.createObjectURL(file.raw)
setrebig() {
rebig().then(response => {
this.$message.success(response.data)
})
},
setresmall() {
resmall().then(response => {
this.$message.success(response.data)
})
},
setrebgimg() {
rebgimg().then(response => {
this.$message.success(response.data)
})
},
setretitle() {
retitle().then(response => {
this.$message.success(response.data)
})
},
setnologo() {
postnologo().then(response => {
this.$message.success(response.data)
})
},
setitle() {
postitle(this.formtitle.title).then(response => {
this.$message.success(response.data)
})
},
handleAvatarSuccess1(res, file) {
this.imageUrl1 = URL.createObjectURL(file.raw)
this.$message.success('LOGO设置成功!')
},
handleAvatarSuccess2(res, file) {
this.imageUrl2 = URL.createObjectURL(file.raw)
this.$message.success('LOGO设置成功!')
},
handleAvatarSuccess3(res, file) {
this.imageUrl3 = URL.createObjectURL(file.raw)
this.$message.success('LOGO设置成功!')
},
beforeAvatarUpload(file) {
const isJPG = file.type === 'image/jpeg' || file.type === 'image/png'
const isLt2M = file.size / 1024 / 1024 < 2
const isLt2M = file.size / 1024 < 512
if (!isJPG) {
this.$message.error('上传LOGO图片只能是 JPG/PNG 格式!')
}
if (!isLt2M) {
this.$message.error('上传LOGO图片大小不能超过 2MB!')
this.$message.error('上传LOGO图片大小不能超过 512KB!')
}
return isJPG && isLt2M
}

View File

@ -0,0 +1,152 @@
<template>
<div>
<el-upload
class="avatar-uploader"
action="/api/login/bgimg"
:headers="myHeaders"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
>
<img v-if="imageUrl" :src="imageUrl" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon" />
</el-upload>
<el-upload
class="avatar-uploader"
action="/api/login/biglogo"
:headers="myHeaders"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
>
<img v-if="imageUrl" :src="imageUrl" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon" />
</el-upload>
<el-upload
class="avatar-uploader"
action="/api/login/smallogo"
:headers="myHeaders"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
>
<img v-if="imageUrl" :src="imageUrl" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon" />
</el-upload>
<el-form :inline="true" :model="formtitle" class="demo-form-inline">
<el-form-item label="登录页名称">
<el-input v-model="formtitle.title" placeholder="请输入" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="setitle"></el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="setretitle"></el-button>
</el-form-item>
<br>
<el-form-item>
<el-button type="primary" @click="setnologo"></el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="setrebig"></el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="setresmall">Logo</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="setrebgimg"></el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import { postitle, postnologo, rebig, resmall, rebgimg, retitle } from '@/api/login'
export default {
data() {
return {
myHeaders: { Authorization: this.$store.getters.token },
imageUrl: '',
formtitle: { title: '' }
}
},
methods: {
setrebig() {
rebig().then(response => {
this.$message.success(response.data)
})
},
setresmall() {
resmall().then(response => {
this.$message.success(response.data)
})
},
setrebgimg() {
rebgimg().then(response => {
this.$message.success(response.data)
})
},
setretitle() {
retitle().then(response => {
this.$message.success(response.data)
})
},
setnologo() {
postnologo().then(response => {
this.$message.success(response.data)
})
},
setitle() {
postitle(this.formtitle.title).then(response => {
this.$message.success(response.data)
})
},
handleAvatarSuccess(res, file) {
this.imageUrl = URL.createObjectURL(file.raw)
this.$message.success('LOGO设置成功!')
},
beforeAvatarUpload(file) {
const isJPG = file.type === 'image/jpeg' || file.type === 'image/png'
const isLt2M = file.size / 1024 < 512
if (!isJPG) {
this.$message.error('上传LOGO图片只能是 JPG/PNG 格式!')
}
if (!isLt2M) {
this.$message.error('上传LOGO图片大小不能超过 512KB!')
}
return isJPG && isLt2M
}
}
}
</script>
<style>
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #409EFF;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
}
.avatar {
width: 178px;
height: 178px;
display: block;
}
</style>

View File

@ -1,15 +1,15 @@
<template>
<div class="login-container">
<div class="login-container" :style="{ 'background-image': 'url(' + loginbgimg + ')' }">
<div v-if="isbig" class="title-container" style="text-align:center">
<br><br>
<img :src="loginlogo" width="720" height="330">
<img :src="loginlogo" width="720" :height=height>
<br><br>
</div>
<div v-else class="title-container" style="text-align:center; padding: 160px 70px 0;">
<img :src="loginlogo" width="100" height="100"><br><br><br><br>
<h3 style="font-size:45px" class="title">Consul Manager</h3><br>
<h3 style="font-size:45px" class="title">{{ logintitle }}</h3><br>
</div>
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on" label-position="left" style="padding: 10px 70px 0;">
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on" label-position="left" style="padding: 10px 100px 0;">
<el-form-item prop="username">
<span class="svg-container">
<svg-icon icon-class="user" />
@ -57,9 +57,11 @@
</template>
<script>
import { logo } from '@/api/login'
import { logo, getbgimg, getitle } from '@/api/login'
import smallogo from '@/assets/login_images/SLH.png'
import biglogo from '@/assets/login_images/tensuns.png'
import bgimg from '@/assets/login_images/bg.png'
export default {
name: 'Login',
data() {
@ -90,7 +92,10 @@ export default {
loading: false,
passwordType: 'password',
loginlogo: '',
loginbgimg: '',
logintitle: 'T e n S u n S',
isbig: true,
height: 330,
redirect: undefined
}
},
@ -103,7 +108,9 @@ export default {
}
},
created() {
this.fetchtitle()
this.getlogo()
this.getbg()
},
methods: {
getlogo() {
@ -117,11 +124,33 @@ export default {
this.isbig = false
}
} else {
if (response.data === 'data:image/png;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7') {
this.height = 450
}
this.loginlogo = response.data
this.isbig = response.isbig
}
})
},
fetchtitle() {
getitle().then(response => {
if (response.data !== 'default') {
this.logintitle = response.data
}
})
},
getbg() {
getbgimg().then(response => {
if (response.data === 'default') {
this.loginbgimg = bgimg
} else {
this.loginbgimg = response.data
}
})
},
showPwd() {
if (this.passwordType === 'password') {
this.passwordType = ''
@ -215,7 +244,7 @@ $light_gray:#eee;
// overflow: hidden;
width: 100%;
height: 100%;
background-image: url("../../assets/login_images/bg.png");
//background-image: url("../../assets/login_images/bg.png");
background-size: cover;
background-position: center;
position: relative;

View File

@ -1,268 +0,0 @@
<template>
<div class="login-container">
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on" label-position="left">
<div class="title-container" style="text-align:center">
<img :src="loginlogo" width="100" height="100"><br><br><br>
<h3 style="font-size:45px" class="title">后羿运维平台</h3><br><br>
</div>
<el-form-item prop="username">
<span class="svg-container">
<svg-icon icon-class="user" />
</span>
<el-input
ref="username"
v-model="loginForm.username"
placeholder="Username"
name="username"
type="text"
tabindex="1"
auto-complete="on"
/>
</el-form-item>
<el-form-item prop="password">
<span class="svg-container">
<svg-icon icon-class="password" />
</span>
<el-input
:key="passwordType"
ref="password"
v-model="loginForm.password"
:type="passwordType"
placeholder="Password"
name="password"
tabindex="2"
auto-complete="on"
@keyup.enter.native="handleLogin"
/>
<span class="show-pwd" @click="showPwd">
<svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
</span>
</el-form-item>
<!-- <el-checkbox v-model="loginForm.Ldapchecked" label="启动ldap验证" border class="ldap" /> -->
<el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin"> </el-button>
</el-form>
<div align="center" class="title-container">
<span style="font-size:12px" class="title">{{ VER }}</span>
</div>
<div class="footer">
<p style="width:100%"><center><el-link href="https://StarsL.cn" :underline="false" target="_blank">Powered by StarsL.cn</el-link></center></p>
</div>
</div>
</template>
<script>
import { logo } from '@/api/login'
import logosl from '@/assets/login_images/SLH.png'
export default {
name: 'Login',
data() {
const validateUsername = (rule, value, callback) => {
if (!value) {
callback(new Error('Please enter the correct user name'))
} else {
callback()
}
}
const validatePassword = (rule, value, callback) => {
if (value.length < 6) {
callback(new Error('The password can not be less than 6 digits'))
} else {
callback()
}
}
return {
loginForm: {
username: 'admin',
password: '',
Ldapchecked: false // ldap
},
loginRules: {
username: [{ required: true, trigger: 'blur', validator: validateUsername }],
password: [{ required: true, trigger: 'blur', validator: validatePassword }]
},
loading: false,
passwordType: 'password',
loginlogo: '',
redirect: undefined
}
},
watch: {
$route: {
handler: function(route) {
this.redirect = route.query && route.query.redirect
},
immediate: true
}
},
created() {
this.getlogo()
},
methods: {
getlogo() {
logo().then(response => {
if (response.data === 'default') {
this.loginlogo = logosl
} else {
this.loginlogo = response.data
}
})
},
showPwd() {
if (this.passwordType === 'password') {
this.passwordType = ''
} else {
this.passwordType = 'password'
}
this.$nextTick(() => {
this.$refs.password.focus()
})
},
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true
this.$store.dispatch('user/login', this.loginForm).then(() => {
this.$router.push({ path: this.redirect || '/' })
this.loading = false
}).catch(() => {
this.loading = false
})
} else {
console.log('error submit!!')
return false
}
})
}
}
}
</script>
<style lang="scss">
/* 修复input 背景不协调 和光标变色 */
/* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */
$bg:#283443;
$light_gray:#fff;
$cursor: #fff;
@supports (-webkit-mask: none) and (not (cater-color: $cursor)) {
.login-container .el-input input {
color: $cursor;
}
}
/* reset element-ui css */
.login-container {
.el-input {
display: inline-block;
height: 47px;
width: 85%;
input {
background: transparent;
border: 0px;
-webkit-appearance: none;
border-radius: 0px;
padding: 12px 5px 12px 15px;
color: $light_gray;
height: 47px;
caret-color: $cursor;
&:-webkit-autofill {
box-shadow: 0 0 0px 1000px $bg inset !important;
-webkit-text-fill-color: $cursor !important;
}
}
}
.el-form-item {
border: 2px solid rgba(255, 255, 255, 0.3);
background: rgba(0, 0, 0, 0.1);
border-radius: 5px;
color: #454545;
}
}
</style>
<style lang="scss" scoped>
$bg:#2d3a4b;
$dark_gray:#889aa4;
$light_gray:#eee;
.ldap{
margin-bottom: 9px;
}
.login-container {
// min-height: 100%;
// width: 100%;
// background-color: $bg;
// overflow: hidden;
width: 100%;
height: 100%;
background-image: url("../../assets/login_images/bg.png");
background-size: cover;
background-position: center;
position: relative;
.login-form {
position: relative;
width: 460px;
max-width: 100%;
padding: 160px 35px 0;
margin: 0 auto;
overflow: hidden;
}
.tips {
font-size: 14px;
color: #fff;
margin-bottom: 10px;
span {
&:first-of-type {
margin-right: 16px;
}
}
}
.svg-container {
padding: 6px 5px 6px 15px;
color: $dark_gray;
vertical-align: middle;
width: 30px;
display: inline-block;
}
.title-container {
position: relative;
.title {
font-size: 26px;
color: $light_gray;
margin: 0px auto 20px auto;
text-align: center;
font-weight: bold;
}
}
.footer {
p {
position:absolute;
bottom:0px;
padding:0px;
margin:0px;
}
}
.show-pwd {
position: absolute;
right: 10px;
top: 7px;
font-size: 16px;
color: $dark_gray;
cursor: pointer;
user-select: none;
}
}
</style>

View File

@ -1,239 +0,0 @@
<template>
<div class="login-container">
<div class="title-container" style="text-align:center">
<img src="../../assets/login_images/tensuns.png" width="720" height="330">
</div>
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on" label-position="left" style="padding: 10px 70px 0;">
<el-form-item prop="username">
<span class="svg-container">
<svg-icon icon-class="user" />
</span>
<el-input
ref="username"
v-model="loginForm.username"
placeholder="Username"
name="username"
type="text"
tabindex="1"
auto-complete="on"
/>
</el-form-item>
<el-form-item prop="password">
<span class="svg-container">
<svg-icon icon-class="password" />
</span>
<el-input
:key="passwordType"
ref="password"
v-model="loginForm.password"
:type="passwordType"
placeholder="Password"
name="password"
tabindex="2"
auto-complete="on"
@keyup.enter.native="handleLogin"
/>
<span class="show-pwd" @click="showPwd">
<svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
</span>
</el-form-item>
<el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">登 录</el-button>
</el-form>
<div align="center" class="title-container">
<span style="font-size:12px" class="title">{{ VER }}</span>
</div>
</div>
</template>
<script>
import { validUsername } from '@/utils/validate'
export default {
name: 'Login',
data() {
const validateUsername = (rule, value, callback) => {
if (!validUsername(value)) {
callback(new Error('Please enter the correct user name'))
} else {
callback()
}
}
const validatePassword = (rule, value, callback) => {
if (value.length < 6) {
callback(new Error('The password can not be less than 6 digits'))
} else {
callback()
}
}
return {
loginForm: {
username: 'admin',
password: ''
},
loginRules: {
username: [{ required: true, trigger: 'blur', validator: validateUsername }],
password: [{ required: true, trigger: 'blur', validator: validatePassword }]
},
loading: false,
passwordType: 'password',
redirect: undefined
}
},
watch: {
$route: {
handler: function(route) {
this.redirect = route.query && route.query.redirect
},
immediate: true
}
},
methods: {
showPwd() {
if (this.passwordType === 'password') {
this.passwordType = ''
} else {
this.passwordType = 'password'
}
this.$nextTick(() => {
this.$refs.password.focus()
})
},
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true
this.$store.dispatch('user/login', this.loginForm).then(() => {
this.$router.push({ path: this.redirect || '/' })
this.loading = false
}).catch(() => {
this.loading = false
})
} else {
console.log('error submit!!')
return false
}
})
}
}
}
</script>
<style lang="scss">
/* 修复input 背景不协调 和光标变色 */
/* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */
$bg:#283443;
$light_gray:#fff;
$cursor: #fff;
@supports (-webkit-mask: none) and (not (cater-color: $cursor)) {
.login-container .el-input input {
color: $cursor;
}
}
/* reset element-ui css */
.login-container {
.el-input {
display: inline-block;
height: 47px;
width: 85%;
input {
background: transparent;
border: 0px;
-webkit-appearance: none;
border-radius: 0px;
padding: 12px 5px 12px 15px;
color: $light_gray;
height: 47px;
caret-color: $cursor;
&:-webkit-autofill {
box-shadow: 0 0 0px 1000px $bg inset !important;
-webkit-text-fill-color: $cursor !important;
}
}
}
.el-form-item {
border: 2px solid rgba(255, 255, 255, 0.3);
background: rgba(0, 0, 0, 0.1);
border-radius: 5px;
color: #454545;
}
}
</style>
<style lang="scss" scoped>
$bg:#2d3a4b;
$dark_gray:#889aa4;
$light_gray:#eee;
.login-container {
// min-height: 100%;
// width: 100%;
// background-color: $bg;
// overflow: hidden;
width: 100%;
height: 100%;
background-image: url("../../assets/login_images/bg.png");
background-size: cover;
background-position: center;
position: relative;
.login-form {
position: relative;
width: 460px;
max-width: 100%;
padding: 160px 35px 0;
margin: 0 auto;
overflow: hidden;
}
.tips {
font-size: 14px;
color: #fff;
margin-bottom: 10px;
span {
&:first-of-type {
margin-right: 16px;
}
}
}
.svg-container {
padding: 6px 5px 6px 15px;
color: $dark_gray;
vertical-align: middle;
width: 30px;
display: inline-block;
}
.title-container {
position: relative;
.title {
font-size: 26px;
color: $light_gray;
margin: 0px auto 20px auto;
text-align: center;
font-weight: bold;
}
}
.show-pwd {
position: absolute;
right: 10px;
top: 7px;
font-size: 16px;
color: $dark_gray;
cursor: pointer;
user-select: none;
}
}
</style>