mirror of https://github.com/halo-dev/halo-admin
parent
121776da41
commit
2cfe229790
|
@ -2601,6 +2601,34 @@
|
||||||
"webpack-sources": "^1.4.3"
|
"webpack-sources": "^1.4.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"vue-loader-v16": {
|
||||||
|
"version": "npm:vue-loader@16.0.0-beta.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.0.0-beta.5.tgz",
|
||||||
|
"integrity": "sha512-ciWfzNefqWlmzKznCWY9hl+fPP4KlQ0A9MtHbJ/8DpyY+dAM8gDrjufIdxwTgC4szE4EZC3A6ip/BbrqM84GqA==",
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/mini-css-extract-plugin": "^0.9.1",
|
||||||
|
"chalk": "^3.0.0",
|
||||||
|
"hash-sum": "^2.0.0",
|
||||||
|
"loader-utils": "^1.2.3",
|
||||||
|
"merge-source-map": "^1.1.0",
|
||||||
|
"source-map": "^0.6.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"chalk": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
|
||||||
|
"dev": true,
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"ansi-styles": "^4.1.0",
|
||||||
|
"supports-color": "^7.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"wrap-ansi": {
|
"wrap-ansi": {
|
||||||
"version": "6.2.0",
|
"version": "6.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
|
||||||
|
@ -16105,86 +16133,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"vue-loader-v16": {
|
|
||||||
"version": "npm:vue-loader@16.0.0-beta.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.0.0-beta.5.tgz",
|
|
||||||
"integrity": "sha512-ciWfzNefqWlmzKznCWY9hl+fPP4KlQ0A9MtHbJ/8DpyY+dAM8gDrjufIdxwTgC4szE4EZC3A6ip/BbrqM84GqA==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"@types/mini-css-extract-plugin": "^0.9.1",
|
|
||||||
"chalk": "^3.0.0",
|
|
||||||
"hash-sum": "^2.0.0",
|
|
||||||
"loader-utils": "^1.2.3",
|
|
||||||
"merge-source-map": "^1.1.0",
|
|
||||||
"source-map": "^0.6.1"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"ansi-styles": {
|
|
||||||
"version": "4.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
|
|
||||||
"integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"@types/color-name": "^1.1.1",
|
|
||||||
"color-convert": "^2.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"chalk": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"ansi-styles": "^4.1.0",
|
|
||||||
"supports-color": "^7.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"color-convert": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"color-name": "~1.1.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"color-name": {
|
|
||||||
"version": "1.1.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
|
||||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"has-flag": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
|
||||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"source-map": {
|
|
||||||
"version": "0.6.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
|
||||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"supports-color": {
|
|
||||||
"version": "7.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
|
||||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"has-flag": "^4.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"vue-ls": {
|
"vue-ls": {
|
||||||
"version": "3.2.1",
|
"version": "3.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/vue-ls/-/vue-ls-3.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/vue-ls/-/vue-ls-3.2.1.tgz",
|
||||||
|
|
24
package.json
24
package.json
|
@ -1,6 +1,17 @@
|
||||||
{
|
{
|
||||||
"name": "halo-admin",
|
"name": "halo-admin",
|
||||||
"version": "1.4.0-beta.2",
|
"version": "1.4.0-beta.2",
|
||||||
|
"author": "halo-dev",
|
||||||
|
"description": "Halo admin client.",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/halo-dev/halo-admin.git"
|
||||||
|
},
|
||||||
|
"license": "ISC",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/halo-dev/halo-admin/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/halo-dev/halo-admin#readme",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "vue-cli-service serve",
|
"serve": "vue-cli-service serve",
|
||||||
"build": "vue-cli-service build",
|
"build": "vue-cli-service build",
|
||||||
|
@ -137,16 +148,5 @@
|
||||||
"> 1%",
|
"> 1%",
|
||||||
"last 2 versions",
|
"last 2 versions",
|
||||||
"not ie <= 10"
|
"not ie <= 10"
|
||||||
],
|
]
|
||||||
"description": "Halo admin client.",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/halo-dev/halo-admin.git"
|
|
||||||
},
|
|
||||||
"author": "halo-dev",
|
|
||||||
"license": "ISC",
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/halo-dev/halo-admin/issues"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/halo-dev/halo-admin#readme"
|
|
||||||
}
|
}
|
|
@ -150,7 +150,7 @@ export default {
|
||||||
this.queryParam.sort = this.pagination.sort
|
this.queryParam.sort = this.pagination.sort
|
||||||
attachmentApi
|
attachmentApi
|
||||||
.query(this.queryParam)
|
.query(this.queryParam)
|
||||||
.then(response => {
|
.then((response) => {
|
||||||
this.attachments = response.data.data.content
|
this.attachments = response.data.data.content
|
||||||
this.pagination.total = response.data.data.total
|
this.pagination.total = response.data.data.total
|
||||||
})
|
})
|
||||||
|
|
|
@ -47,7 +47,7 @@ export default {
|
||||||
handleAttachmentUpload(pos, $file) {
|
handleAttachmentUpload(pos, $file) {
|
||||||
var formdata = new FormData()
|
var formdata = new FormData()
|
||||||
formdata.append('file', $file)
|
formdata.append('file', $file)
|
||||||
attachmentApi.upload(formdata).then(response => {
|
attachmentApi.upload(formdata).then((response) => {
|
||||||
var responseObject = response.data
|
var responseObject = response.data
|
||||||
var HaloEditor = this.$refs.md
|
var HaloEditor = this.$refs.md
|
||||||
HaloEditor.$img2Url(pos, encodeURI(responseObject.data.path))
|
HaloEditor.$img2Url(pos, encodeURI(responseObject.data.path))
|
||||||
|
|
|
@ -29,27 +29,23 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getStrDom(str, fullLength) {
|
getStrDom(str, fullLength) {
|
||||||
return (
|
return <span>{cutStrByFullLength(str, this.length) + (fullLength > this.length ? '...' : '')}</span>
|
||||||
<span>{ cutStrByFullLength(str, this.length) + (fullLength > this.length ? '...' : '') }</span>
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
getTooltip(fullStr, fullLength) {
|
getTooltip(fullStr, fullLength) {
|
||||||
return (
|
return (
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<template slot="title">{ fullStr }</template>
|
<template slot="title">{fullStr}</template>
|
||||||
{ this.getStrDom(fullStr, fullLength) }
|
{this.getStrDom(fullStr, fullLength)}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
render() {
|
render() {
|
||||||
const { tooltip, length } = this.$props
|
const { tooltip, length } = this.$props
|
||||||
const str = this.$slots.default.map(vNode => vNode.text).join('')
|
const str = this.$slots.default.map((vNode) => vNode.text).join('')
|
||||||
const fullLength = getStrFullLength(str)
|
const fullLength = getStrFullLength(str)
|
||||||
const strDom = tooltip && fullLength > length ? this.getTooltip(str, fullLength) : this.getStrDom(str, fullLength)
|
const strDom = tooltip && fullLength > length ? this.getTooltip(str, fullLength) : this.getStrDom(str, fullLength)
|
||||||
return (
|
return strDom
|
||||||
strDom
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
@import "../index";
|
@import '../index';
|
||||||
|
|
||||||
@footer-toolbar-prefix-cls: ~"@{ant-pro-prefix}-footer-toolbar";
|
@footer-toolbar-prefix-cls: ~'@{ant-pro-prefix}-footer-toolbar';
|
||||||
|
|
||||||
.@{footer-toolbar-prefix-cls} {
|
.@{footer-toolbar-prefix-cls} {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
|
|
||||||
&:after {
|
&:after {
|
||||||
content: "";
|
content: '';
|
||||||
display: block;
|
display: block;
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<a-form-model
|
||||||
|
ref="loginForm"
|
||||||
|
:model="form.model"
|
||||||
|
:rules="form.rules"
|
||||||
|
layout="vertical"
|
||||||
|
@keyup.enter.native="handleLogin"
|
||||||
|
>
|
||||||
|
<a-form-model-item
|
||||||
|
v-if="!form.needAuthCode"
|
||||||
|
class="animated fadeInUp"
|
||||||
|
:style="{'animation-delay': '0.1s'}"
|
||||||
|
prop="username"
|
||||||
|
>
|
||||||
|
<a-input
|
||||||
|
placeholder="用户名/邮箱"
|
||||||
|
v-model="form.model.username"
|
||||||
|
>
|
||||||
|
<a-icon
|
||||||
|
slot="prefix"
|
||||||
|
type="user"
|
||||||
|
style="color: rgba(0,0,0,.25)"
|
||||||
|
/>
|
||||||
|
</a-input>
|
||||||
|
</a-form-model-item>
|
||||||
|
<a-form-model-item
|
||||||
|
v-if="!form.needAuthCode"
|
||||||
|
class="animated fadeInUp"
|
||||||
|
:style="{'animation-delay': '0.2s'}"
|
||||||
|
prop="password"
|
||||||
|
>
|
||||||
|
<a-input
|
||||||
|
v-model="form.model.password"
|
||||||
|
type="password"
|
||||||
|
placeholder="密码"
|
||||||
|
>
|
||||||
|
<a-icon
|
||||||
|
slot="prefix"
|
||||||
|
type="lock"
|
||||||
|
style="color: rgba(0,0,0,.25)"
|
||||||
|
/>
|
||||||
|
</a-input>
|
||||||
|
</a-form-model-item>
|
||||||
|
<a-form-model-item
|
||||||
|
v-if="form.needAuthCode"
|
||||||
|
class="animated fadeInUp"
|
||||||
|
:style="{'animation-delay': '0.1s'}"
|
||||||
|
prop="authcode"
|
||||||
|
>
|
||||||
|
<a-input
|
||||||
|
placeholder="两步验证码"
|
||||||
|
v-model="form.model.authcode"
|
||||||
|
:maxLength="6"
|
||||||
|
>
|
||||||
|
<a-icon
|
||||||
|
slot="prefix"
|
||||||
|
type="safety-certificate"
|
||||||
|
style="color: rgba(0,0,0,.25)"
|
||||||
|
/>
|
||||||
|
</a-input>
|
||||||
|
</a-form-model-item>
|
||||||
|
<a-form-model-item
|
||||||
|
class="animated fadeInUp"
|
||||||
|
:style="{'animation-delay': '0.3s'}"
|
||||||
|
>
|
||||||
|
<a-button
|
||||||
|
:loading="form.logging"
|
||||||
|
type="primary"
|
||||||
|
:block="true"
|
||||||
|
@click="handleLoginClick"
|
||||||
|
>{{ buttonName }}</a-button>
|
||||||
|
</a-form-model-item>
|
||||||
|
</a-form-model>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import adminApi from '@/api/admin'
|
||||||
|
import { mapActions } from 'vuex'
|
||||||
|
export default {
|
||||||
|
name: 'LoginForm',
|
||||||
|
data() {
|
||||||
|
const authcodeValidate = (rule, value, callback) => {
|
||||||
|
if (!value && this.form.needAuthCode) {
|
||||||
|
callback(new Error('* 请输入两步验证码'))
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
form: {
|
||||||
|
model: {
|
||||||
|
authcode: null,
|
||||||
|
password: null,
|
||||||
|
username: null
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
username: [{ required: true, message: '* 用户名/邮箱不能为空', trigger: ['change'] }],
|
||||||
|
password: [{ required: true, message: '* 密码不能为空', trigger: ['change'] }],
|
||||||
|
authcode: [{ validator: authcodeValidate, trigger: ['change'] }]
|
||||||
|
},
|
||||||
|
needAuthCode: false,
|
||||||
|
logging: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
buttonName() {
|
||||||
|
return this.form.needAuthCode ? '验证' : '登录'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(['login', 'refreshUserCache', 'refreshOptionsCache']),
|
||||||
|
handleLoginClick() {
|
||||||
|
const _this = this
|
||||||
|
_this.$refs.loginForm.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
_this.form.logging = true
|
||||||
|
if (_this.form.needAuthCode && _this.form.model.authcode) {
|
||||||
|
_this.handleLogin()
|
||||||
|
} else {
|
||||||
|
adminApi
|
||||||
|
.loginPreCheck(_this.form.model.username, _this.form.model.password)
|
||||||
|
.then((response) => {
|
||||||
|
const data = response.data.data
|
||||||
|
if (data && data.needMFACode) {
|
||||||
|
_this.form.needAuthCode = true
|
||||||
|
_this.form.model.authcode = null
|
||||||
|
} else {
|
||||||
|
_this.handleLogin()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
_this.form.logging = false
|
||||||
|
}, 300)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleLogin() {
|
||||||
|
const _this = this
|
||||||
|
_this.form.logging = true
|
||||||
|
_this.$refs.loginForm.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
_this
|
||||||
|
.login(_this.form.model)
|
||||||
|
.then((response) => {
|
||||||
|
_this.$emit('success')
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
_this.form.logging = false
|
||||||
|
}, 300)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,38 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<a-modal
|
||||||
|
v-model="loginModal"
|
||||||
|
title="重新登录"
|
||||||
|
:footer="null"
|
||||||
|
:width="320"
|
||||||
|
:maskClosable="false"
|
||||||
|
@cancel="handleCancelLogin"
|
||||||
|
>
|
||||||
|
<LoginForm @success="onLoginSucceed" />
|
||||||
|
</a-modal>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import LoginForm from './LoginForm'
|
||||||
|
import { mapGetters, mapActions } from 'vuex'
|
||||||
|
export default {
|
||||||
|
name: 'LoginModal',
|
||||||
|
components: {
|
||||||
|
LoginForm
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters(['loginModal'])
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(['ToggleLoginModal']),
|
||||||
|
onLoginSucceed() {
|
||||||
|
this.$emit('success')
|
||||||
|
},
|
||||||
|
handleCancelLogin() {
|
||||||
|
this.ToggleLoginModal(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
|
@ -6,7 +6,7 @@
|
||||||
v-model="collapsed"
|
v-model="collapsed"
|
||||||
:trigger="null"
|
:trigger="null"
|
||||||
>
|
>
|
||||||
<logo/>
|
<logo />
|
||||||
<s-menu
|
<s-menu
|
||||||
:collapsed="collapsed"
|
:collapsed="collapsed"
|
||||||
:menu="menus"
|
:menu="menus"
|
||||||
|
|
|
@ -103,7 +103,7 @@ export default {
|
||||||
},
|
},
|
||||||
renderMenuItem(menu) {
|
renderMenuItem(menu) {
|
||||||
const target = menu.meta.target || null
|
const target = menu.meta.target || null
|
||||||
const CustomTag = target && 'a' || 'router-link'
|
const CustomTag = (target && 'a') || 'router-link'
|
||||||
const props = { to: { name: menu.name } }
|
const props = { to: { name: menu.name } }
|
||||||
const attrs = { href: menu.path, target: menu.meta.target }
|
const attrs = { href: menu.path, target: menu.meta.target }
|
||||||
return (
|
return (
|
||||||
|
@ -135,10 +135,8 @@ export default {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
const props = {}
|
const props = {}
|
||||||
typeof (icon) === 'object' ? props.component = icon : props.type = icon
|
typeof icon === 'object' ? (props.component = icon) : (props.type = icon)
|
||||||
return (
|
return <Icon {...{ props }} />
|
||||||
<Icon {... { props } }/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
render() {
|
render() {
|
||||||
|
@ -162,6 +160,6 @@ export default {
|
||||||
return this.renderItem(item)
|
return this.renderItem(item)
|
||||||
})
|
})
|
||||||
|
|
||||||
return (<Menu {...dynamicProps}>{menuTree}</Menu>)
|
return <Menu {...dynamicProps}>{menuTree}</Menu>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ export default {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
const props = {}
|
const props = {}
|
||||||
typeof (icon) === 'object' ? props.component = icon : props.type = icon
|
typeof icon === 'object' ? (props.component = icon) : (props.type = icon)
|
||||||
return h(Icon, { props: { ...props } })
|
return h(Icon, { props: { ...props } })
|
||||||
},
|
},
|
||||||
renderMenuItem: function(h, menu, pIndex, index) {
|
renderMenuItem: function(h, menu, pIndex, index) {
|
||||||
|
|
|
@ -3,22 +3,38 @@
|
||||||
<div class="page-header-index-wide">
|
<div class="page-header-index-wide">
|
||||||
<s-breadcrumb />
|
<s-breadcrumb />
|
||||||
<div class="detail">
|
<div class="detail">
|
||||||
<div class="main" v-if="!$route.meta.hiddenHeaderContent">
|
<div
|
||||||
|
class="main"
|
||||||
|
v-if="!$route.meta.hiddenHeaderContent"
|
||||||
|
>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<img v-if="logo" :src="logo" class="logo"/>
|
<img
|
||||||
|
v-if="logo"
|
||||||
|
:src="logo"
|
||||||
|
class="logo"
|
||||||
|
/>
|
||||||
<!-- <h1 v-if="title" class="title">{{ title }}</h1> -->
|
<!-- <h1 v-if="title" class="title">{{ title }}</h1> -->
|
||||||
<div class="action">
|
<div class="action">
|
||||||
<slot name="action"></slot>
|
<slot name="action"></slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div v-if="avatar" class="avatar">
|
<div
|
||||||
|
v-if="avatar"
|
||||||
|
class="avatar"
|
||||||
|
>
|
||||||
<a-avatar :src="avatar" />
|
<a-avatar :src="avatar" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="this.$slots.content" class="headerContent">
|
<div
|
||||||
|
v-if="this.$slots.content"
|
||||||
|
class="headerContent"
|
||||||
|
>
|
||||||
<slot name="content"></slot>
|
<slot name="content"></slot>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="this.$slots.extra" class="extra">
|
<div
|
||||||
|
v-if="this.$slots.extra"
|
||||||
|
class="extra"
|
||||||
|
>
|
||||||
<slot name="extra"></slot>
|
<slot name="extra"></slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<div class="setting-drawer-index-item">
|
<div class="setting-drawer-index-item">
|
||||||
<h3 class="setting-drawer-index-title">{{ title }}</h3>
|
<h3 class="setting-drawer-index-title">{{ title }}</h3>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
<a-divider v-if="divider"/>
|
<a-divider v-if="divider" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -23,16 +23,14 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
.setting-drawer-index-item {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
|
||||||
.setting-drawer-index-item {
|
.setting-drawer-index-title {
|
||||||
margin-bottom: 24px;
|
font-size: 14px;
|
||||||
|
color: rgba(0, 0, 0, 0.85);
|
||||||
.setting-drawer-index-title {
|
line-height: 22px;
|
||||||
font-size: 14px;
|
margin-bottom: 12px;
|
||||||
color: rgba(0, 0, 0, .85);
|
|
||||||
line-height: 22px;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<a-breadcrumb class="breadcrumb">
|
<a-breadcrumb class="breadcrumb">
|
||||||
<a-breadcrumb-item v-for="(item, index) in breadList" :key="item.name">
|
<a-breadcrumb-item
|
||||||
|
v-for="(item, index) in breadList"
|
||||||
|
:key="item.name"
|
||||||
|
>
|
||||||
<router-link
|
<router-link
|
||||||
v-if="item.name != name && index != 1"
|
v-if="item.name != name && index != 1"
|
||||||
:to="{ path: item.path === '' ? '/' : item.path }"
|
:to="{ path: item.path === '' ? '/' : item.path }"
|
||||||
|
@ -27,7 +30,7 @@ export default {
|
||||||
// this.breadList.push({name: 'index', path: '/dashboard/', meta: {title: '首页'}})
|
// this.breadList.push({name: 'index', path: '/dashboard/', meta: {title: '首页'}})
|
||||||
|
|
||||||
this.name = this.$route.name
|
this.name = this.$route.name
|
||||||
this.$route.matched.forEach(item => {
|
this.$route.matched.forEach((item) => {
|
||||||
// item.name !== 'index' && this.breadList.push(item)
|
// item.name !== 'index' && this.breadList.push(item)
|
||||||
this.breadList.push(item)
|
this.breadList.push(item)
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="head-info" :class="center && 'center'">
|
<div
|
||||||
|
class="head-info"
|
||||||
|
:class="center && 'center'"
|
||||||
|
>
|
||||||
<span>{{ title }}</span>
|
<span>{{ title }}</span>
|
||||||
<p>{{ content }}</p>
|
<p>{{ content }}</p>
|
||||||
<em v-if="bordered"/>
|
<em v-if="bordered" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -31,37 +34,37 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.head-info {
|
.head-info {
|
||||||
position: relative;
|
position: relative;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding: 0 32px 0 0;
|
padding: 0 32px 0 0;
|
||||||
min-width: 125px;
|
min-width: 125px;
|
||||||
|
|
||||||
&.center {
|
&.center {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 0 32px;
|
padding: 0 32px;
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
color: rgba(0, 0, 0, .45);
|
|
||||||
display: inline-block;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 22px;
|
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
|
||||||
p {
|
|
||||||
color: rgba(0, 0, 0, .85);
|
|
||||||
font-size: 24px;
|
|
||||||
line-height: 32px;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
em {
|
|
||||||
background-color: #e8e8e8;
|
|
||||||
position: absolute;
|
|
||||||
height: 56px;
|
|
||||||
width: 1px;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: rgba(0, 0, 0, 0.45);
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 22px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
color: rgba(0, 0, 0, 0.85);
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 32px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
em {
|
||||||
|
background-color: #e8e8e8;
|
||||||
|
position: absolute;
|
||||||
|
height: 56px;
|
||||||
|
width: 1px;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -114,13 +114,13 @@ export default {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
converttedPostComments() {
|
converttedPostComments() {
|
||||||
return this.postComments.map(comment => {
|
return this.postComments.map((comment) => {
|
||||||
comment.content = marked(decodeHTML(comment.content))
|
comment.content = marked(decodeHTML(comment.content))
|
||||||
return comment
|
return comment
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
converttedSheetComments() {
|
converttedSheetComments() {
|
||||||
return this.sheetComments.map(comment => {
|
return this.sheetComments.map((comment) => {
|
||||||
comment.content = marked(decodeHTML(comment.content))
|
comment.content = marked(decodeHTML(comment.content))
|
||||||
return comment
|
return comment
|
||||||
})
|
})
|
||||||
|
@ -148,7 +148,7 @@ export default {
|
||||||
}
|
}
|
||||||
commentApi
|
commentApi
|
||||||
.latestComment('posts', 5, 'AUDITING')
|
.latestComment('posts', 5, 'AUDITING')
|
||||||
.then(response => {
|
.then((response) => {
|
||||||
this.postComments = response.data.data
|
this.postComments = response.data.data
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
|
@ -163,7 +163,7 @@ export default {
|
||||||
}
|
}
|
||||||
commentApi
|
commentApi
|
||||||
.latestComment('sheets', 5, 'AUDITING')
|
.latestComment('sheets', 5, 'AUDITING')
|
||||||
.then(response => {
|
.then((response) => {
|
||||||
this.sheetComments = response.data.data
|
this.sheetComments = response.data.data
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
|
|
|
@ -34,7 +34,7 @@ export default {
|
||||||
onLogoClick() {
|
onLogoClick() {
|
||||||
this.clickCount++
|
this.clickCount++
|
||||||
if (this.clickCount === 10) {
|
if (this.clickCount === 10) {
|
||||||
optionApi.save(this.optionsToCreate).then(response => {
|
optionApi.save(this.optionsToCreate).then((response) => {
|
||||||
this.refreshOptionsCache()
|
this.refreshOptionsCache()
|
||||||
this.$message.success(`开发者选项已启用!`)
|
this.$message.success(`开发者选项已启用!`)
|
||||||
this.clickCount = 0
|
this.clickCount = 0
|
||||||
|
|
|
@ -89,7 +89,7 @@ export default {
|
||||||
.then(() => {
|
.then(() => {
|
||||||
window.location.reload()
|
window.location.reload()
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch((err) => {
|
||||||
that.$message.error({
|
that.$message.error({
|
||||||
title: '错误',
|
title: '错误',
|
||||||
description: err.message
|
description: err.message
|
||||||
|
|
|
@ -30,9 +30,7 @@ body {
|
||||||
|
|
||||||
&.mobile,
|
&.mobile,
|
||||||
&.tablet {
|
&.tablet {
|
||||||
|
|
||||||
.ant-layout-content {
|
.ant-layout-content {
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
margin: 24px 0 0;
|
margin: 24px 0 0;
|
||||||
}
|
}
|
||||||
|
@ -53,7 +51,6 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.topmenu {
|
.topmenu {
|
||||||
|
|
||||||
/* 必须为 topmenu 才能启用流式布局 */
|
/* 必须为 topmenu 才能启用流式布局 */
|
||||||
&.content-width-Fluid {
|
&.content-width-Fluid {
|
||||||
.header-index-wide {
|
.header-index-wide {
|
||||||
|
@ -66,10 +63,9 @@ body {
|
||||||
&.mobile {
|
&.mobile {
|
||||||
.sidemenu {
|
.sidemenu {
|
||||||
.ant-header-fixedHeader {
|
.ant-header-fixedHeader {
|
||||||
|
|
||||||
&.ant-header-side-opened,
|
&.ant-header-side-opened,
|
||||||
&.ant-header-side-closed {
|
&.ant-header-side-closed {
|
||||||
width: 100%
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,7 +80,7 @@ body {
|
||||||
line-height: 64px;
|
line-height: 64px;
|
||||||
padding: 0 24px;
|
padding: 0 24px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: color .3s;
|
transition: color 0.3s;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: rgba(0, 0, 0, 0.025);
|
background: rgba(0, 0, 0, 0.025);
|
||||||
|
@ -98,7 +94,7 @@ body {
|
||||||
right: 0;
|
right: 0;
|
||||||
z-index: 9;
|
z-index: 9;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
transition: width .2s;
|
transition: width 0.2s;
|
||||||
|
|
||||||
&.ant-header-side-opened {
|
&.ant-header-side-opened {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -136,7 +132,6 @@ body {
|
||||||
max-width: unset;
|
max-width: unset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidemenu {
|
.sidemenu {
|
||||||
|
@ -146,14 +141,14 @@ body {
|
||||||
right: 0;
|
right: 0;
|
||||||
z-index: 9;
|
z-index: 9;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
transition: width .2s;
|
transition: width 0.2s;
|
||||||
|
|
||||||
&.ant-header-side-opened {
|
&.ant-header-side-opened {
|
||||||
width: calc(100% - 256px)
|
width: calc(100% - 256px);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.ant-header-side-closed {
|
&.ant-header-side-closed {
|
||||||
width: calc(100% - 80px)
|
width: calc(100% - 80px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,13 +157,12 @@ body {
|
||||||
height: 64px;
|
height: 64px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
|
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header,
|
.header,
|
||||||
.top-nav-header-index {
|
.top-nav-header-index {
|
||||||
|
|
||||||
.user-wrapper {
|
.user-wrapper {
|
||||||
float: right;
|
float: right;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -177,7 +171,7 @@ body {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 0 18px;
|
padding: 0 18px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
transition: all .3s;
|
transition: all 0.3s;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
color: rgba(0, 0, 0, 0.65);
|
color: rgba(0, 0, 0, 0.65);
|
||||||
|
|
||||||
|
@ -188,7 +182,7 @@ body {
|
||||||
.avatar {
|
.avatar {
|
||||||
margin: 20px 0 20px 0;
|
margin: 20px 0 20px 0;
|
||||||
color: #1890ff;
|
color: #1890ff;
|
||||||
background: hsla(0, 0%, 100%, .85);
|
background: hsla(0, 0%, 100%, 0.85);
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,7 +195,6 @@ body {
|
||||||
|
|
||||||
&.dark {
|
&.dark {
|
||||||
.user-wrapper {
|
.user-wrapper {
|
||||||
|
|
||||||
.action {
|
.action {
|
||||||
color: rgba(255, 255, 255, 0.85);
|
color: rgba(255, 255, 255, 0.85);
|
||||||
|
|
||||||
|
@ -220,11 +213,8 @@ body {
|
||||||
&.mobile,
|
&.mobile,
|
||||||
&.tablet {
|
&.tablet {
|
||||||
.top-nav-header-index {
|
.top-nav-header-index {
|
||||||
|
|
||||||
.header-index-wide {
|
.header-index-wide {
|
||||||
|
|
||||||
.header-index-left {
|
.header-index-left {
|
||||||
|
|
||||||
.trigger {
|
.trigger {
|
||||||
color: rgba(255, 255, 255, 0.85);
|
color: rgba(255, 255, 255, 0.85);
|
||||||
padding: 0 24px;
|
padding: 0 24px;
|
||||||
|
@ -243,9 +233,7 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
&.light {
|
&.light {
|
||||||
|
|
||||||
.header-index-wide {
|
.header-index-wide {
|
||||||
|
|
||||||
.header-index-left {
|
.header-index-left {
|
||||||
.trigger {
|
.trigger {
|
||||||
color: rgba(0, 0, 0, 0.65);
|
color: rgba(0, 0, 0, 0.65);
|
||||||
|
@ -257,14 +245,11 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
&.tablet {
|
&.tablet {
|
||||||
|
|
||||||
// overflow: hidden; text-overflow:ellipsis; white-space: nowrap;
|
// overflow: hidden; text-overflow:ellipsis; white-space: nowrap;
|
||||||
.top-nav-header-index {
|
.top-nav-header-index {
|
||||||
|
|
||||||
.header-index-wide {
|
.header-index-wide {
|
||||||
|
|
||||||
.header-index-left {
|
.header-index-left {
|
||||||
.logo>a {
|
.logo > a {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
@ -277,13 +262,12 @@ body {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-nav-header-index {
|
.top-nav-header-index {
|
||||||
box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
|
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
|
||||||
position: relative;
|
position: relative;
|
||||||
transition: background .3s, width .2s;
|
transition: background 0.3s, width 0.2s;
|
||||||
|
|
||||||
.header-index-wide {
|
.header-index-wide {
|
||||||
max-width: 1200px;
|
max-width: 1200px;
|
||||||
|
@ -310,7 +294,7 @@ body {
|
||||||
height: 64px;
|
height: 64px;
|
||||||
position: relative;
|
position: relative;
|
||||||
line-height: 64px;
|
line-height: 64px;
|
||||||
transition: all .3s;
|
transition: all 0.3s;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
img,
|
img,
|
||||||
|
@ -373,7 +357,6 @@ body {
|
||||||
height: 64px;
|
height: 64px;
|
||||||
padding: 0 12px 0 0;
|
padding: 0 12px 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.topmenu {
|
.topmenu {
|
||||||
|
@ -404,13 +387,13 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-drawer-body {
|
.ant-drawer-body {
|
||||||
padding: 0
|
padding: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 菜单样式
|
// 菜单样式
|
||||||
.sider {
|
.sider {
|
||||||
box-shadow: 2px 0 6px rgba(0, 21, 41, .35);
|
box-shadow: 2px 0 6px rgba(0, 21, 41, 0.35);
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: @ant-global-sider-zindex;
|
z-index: @ant-global-sider-zindex;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
|
@ -435,7 +418,7 @@ body {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
line-height: 64px;
|
line-height: 64px;
|
||||||
background: #002140;
|
background: #002140;
|
||||||
transition: all .3s;
|
transition: all 0.3s;
|
||||||
|
|
||||||
img,
|
img,
|
||||||
svg,
|
svg,
|
||||||
|
@ -477,7 +460,6 @@ body {
|
||||||
border-right-color: transparent;
|
border-right-color: transparent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 外置的样式控制
|
// 外置的样式控制
|
||||||
|
@ -494,19 +476,16 @@ body {
|
||||||
width: 160px;
|
width: 160px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-dropdown-menu-item>.anticon:first-child,
|
.ant-dropdown-menu-item > .anticon:first-child,
|
||||||
.ant-dropdown-menu-item>a>.anticon:first-child,
|
.ant-dropdown-menu-item > a > .anticon:first-child,
|
||||||
.ant-dropdown-menu-submenu-title>.anticon:first-child .ant-dropdown-menu-submenu-title>a>.anticon:first-child {
|
.ant-dropdown-menu-submenu-title > .anticon:first-child .ant-dropdown-menu-submenu-title > a > .anticon:first-child {
|
||||||
min-width: 12px;
|
min-width: 12px;
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-page-search-wrapper {
|
.table-page-search-wrapper {
|
||||||
|
|
||||||
.ant-form-inline {
|
.ant-form-inline {
|
||||||
|
|
||||||
.ant-form-item {
|
.ant-form-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
@ -518,7 +497,7 @@ body {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
>.ant-form-item-label {
|
> .ant-form-item-label {
|
||||||
line-height: 32px;
|
line-height: 32px;
|
||||||
padding-right: 8px;
|
padding-right: 8px;
|
||||||
width: auto;
|
width: auto;
|
||||||
|
@ -536,15 +515,13 @@ body {
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-table-thead>tr>th {
|
.ant-table-thead > tr > th {
|
||||||
background: #fff !important;
|
background: #fff !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
|
|
||||||
.table-operator {
|
.table-operator {
|
||||||
margin-bottom: 18px;
|
margin-bottom: 18px;
|
||||||
|
|
||||||
|
@ -580,17 +557,17 @@ body {
|
||||||
.card-container {
|
.card-container {
|
||||||
background: #f5f5f5;
|
background: #f5f5f5;
|
||||||
|
|
||||||
&>.ant-tabs-card {
|
& > .ant-tabs-card {
|
||||||
&>.ant-tabs-content {
|
& > .ant-tabs-content {
|
||||||
margin-top: -16px;
|
margin-top: -16px;
|
||||||
|
|
||||||
&>.ant-tabs-tabpane {
|
& > .ant-tabs-tabpane {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&>.ant-tabs-bar {
|
& > .ant-tabs-bar {
|
||||||
border-color: #fff;
|
border-color: #fff;
|
||||||
|
|
||||||
.ant-tabs-tab {
|
.ant-tabs-tab {
|
||||||
|
@ -607,7 +584,6 @@ body {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.ant-comment {
|
.ant-comment {
|
||||||
.ant-comment-actions {
|
.ant-comment-actions {
|
||||||
margin-bottom: 0 !important;
|
margin-bottom: 0 !important;
|
||||||
|
@ -666,7 +642,7 @@ body {
|
||||||
flex-flow: row wrap;
|
flex-flow: row wrap;
|
||||||
|
|
||||||
.ant-pagination-options-size-changer.ant-select {
|
.ant-pagination-options-size-changer.ant-select {
|
||||||
margin: 0
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pagination {
|
.pagination {
|
||||||
|
@ -877,7 +853,6 @@ body {
|
||||||
line-height: initial !important;
|
line-height: initial !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.theme-screenshot {
|
.theme-screenshot {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
|
|
@ -6,6 +6,6 @@ html [type='button'] {
|
||||||
}
|
}
|
||||||
|
|
||||||
// The prefix to use on all css classes from ant-pro.
|
// The prefix to use on all css classes from ant-pro.
|
||||||
@ant-pro-prefix : ant-pro;
|
@ant-pro-prefix: ant-pro;
|
||||||
@ant-global-sider-zindex : 106;
|
@ant-global-sider-zindex: 106;
|
||||||
@ant-global-header-zindex : 105;
|
@ant-global-header-zindex: 105;
|
||||||
|
|
|
@ -1,40 +1,40 @@
|
||||||
@import './animate.less';
|
@import './animate.less';
|
||||||
.container-wrapper {
|
.container-wrapper {
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
top: 45%;
|
top: 45%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
margin: -160px 0 0 -160px;
|
margin: -160px 0 0 -160px;
|
||||||
width: 320px;
|
width: 320px;
|
||||||
padding: 18px 28px 28px 28px;
|
padding: 18px 28px 28px 28px;
|
||||||
box-shadow: -4px 7px 46px 2px rgba(0, 0, 0, 0.1);
|
box-shadow: -4px 7px 46px 2px rgba(0, 0, 0, 0.1);
|
||||||
|
|
||||||
.halo-logo {
|
.halo-logo {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
span {
|
span {
|
||||||
vertical-align: text-bottom;
|
vertical-align: text-bottom;
|
||||||
font-size: 38px;
|
font-size: 38px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #1790fe;
|
color: #1790fe;
|
||||||
background-image: linear-gradient(-20deg, #6e45e2 0%, #88d3ce 100%);
|
background-image: linear-gradient(-20deg, #6e45e2 0%, #88d3ce 100%);
|
||||||
-webkit-text-fill-color: transparent;
|
-webkit-text-fill-color: transparent;
|
||||||
-webkit-background-clip: text;
|
-webkit-background-clip: text;
|
||||||
background-clip: text;
|
background-clip: text;
|
||||||
|
|
||||||
small {
|
small {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
font-size: 35%;
|
font-size: 35%;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.tip {
|
.tip {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin-left: 0.5rem;
|
margin-left: 0.5rem;
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -56,6 +56,8 @@
|
||||||
</a-layout>
|
</a-layout>
|
||||||
|
|
||||||
<setting-drawer ref="drawer"></setting-drawer>
|
<setting-drawer ref="drawer"></setting-drawer>
|
||||||
|
|
||||||
|
<LoginModal @success="onLoginSucceed" />
|
||||||
</a-layout>
|
</a-layout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -71,6 +73,7 @@ import SideMenu from '@/components/Menu/SideMenu'
|
||||||
import GlobalHeader from '@/components/GlobalHeader'
|
import GlobalHeader from '@/components/GlobalHeader'
|
||||||
import GlobalFooter from '@/components/GlobalFooter'
|
import GlobalFooter from '@/components/GlobalFooter'
|
||||||
import SettingDrawer from '@/components/SettingDrawer/SettingDrawer'
|
import SettingDrawer from '@/components/SettingDrawer/SettingDrawer'
|
||||||
|
import LoginModal from '@/components/Login/LoginModal'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'BasicLayout',
|
name: 'BasicLayout',
|
||||||
|
@ -80,7 +83,8 @@ export default {
|
||||||
SideMenu,
|
SideMenu,
|
||||||
GlobalHeader,
|
GlobalHeader,
|
||||||
GlobalFooter,
|
GlobalFooter,
|
||||||
SettingDrawer
|
SettingDrawer,
|
||||||
|
LoginModal
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -92,7 +96,7 @@ export default {
|
||||||
computed: {
|
computed: {
|
||||||
...mapState({
|
...mapState({
|
||||||
// 动态主路由
|
// 动态主路由
|
||||||
mainMenu: state => state.permission.addRouters
|
mainMenu: (state) => state.permission.addRouters
|
||||||
}),
|
}),
|
||||||
contentPaddingLeft() {
|
contentPaddingLeft() {
|
||||||
if (!this.fixSidebar || this.isMobile()) {
|
if (!this.fixSidebar || this.isMobile()) {
|
||||||
|
@ -110,7 +114,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.menus = asyncRouterMap.find(item => item.path === '/').children
|
this.menus = asyncRouterMap.find((item) => item.path === '/').children
|
||||||
// this.menus = this.mainMenu.find((item) => item.path === '/').children
|
// this.menus = this.mainMenu.find((item) => item.path === '/').children
|
||||||
this.collapsed = !this.sidebarOpened
|
this.collapsed = !this.sidebarOpened
|
||||||
},
|
},
|
||||||
|
@ -126,7 +130,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(['setSidebar']),
|
...mapActions(['setSidebar', 'ToggleLoginModal']),
|
||||||
toggle() {
|
toggle() {
|
||||||
this.collapsed = !this.collapsed
|
this.collapsed = !this.collapsed
|
||||||
this.setSidebar(!this.collapsed)
|
this.setSidebar(!this.collapsed)
|
||||||
|
@ -137,7 +141,7 @@ export default {
|
||||||
if (this.sidebarOpened) {
|
if (this.sidebarOpened) {
|
||||||
left = this.isDesktop() ? '256px' : '80px'
|
left = this.isDesktop() ? '256px' : '80px'
|
||||||
} else {
|
} else {
|
||||||
left = (this.isMobile() && '0') || ((this.fixSidebar && '80px') || '0')
|
left = (this.isMobile() && '0') || (this.fixSidebar && '80px') || '0'
|
||||||
}
|
}
|
||||||
return left
|
return left
|
||||||
},
|
},
|
||||||
|
@ -148,6 +152,9 @@ export default {
|
||||||
},
|
},
|
||||||
drawerClose() {
|
drawerClose() {
|
||||||
this.collapsed = false
|
this.collapsed = false
|
||||||
|
},
|
||||||
|
onLoginSucceed() {
|
||||||
|
this.ToggleLoginModal(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ const getters = {
|
||||||
theme: state => state.app.theme,
|
theme: state => state.app.theme,
|
||||||
color: state => state.app.color,
|
color: state => state.app.color,
|
||||||
layoutSetting: state => state.app.layoutSetting,
|
layoutSetting: state => state.app.layoutSetting,
|
||||||
|
loginModal: state => state.app.loginModal,
|
||||||
token: state => state.user.token,
|
token: state => state.user.token,
|
||||||
user: state => state.user.user,
|
user: state => state.user.user,
|
||||||
addRouters: state => state.permission.addRouters,
|
addRouters: state => state.permission.addRouters,
|
||||||
|
|
|
@ -24,7 +24,8 @@ const app = {
|
||||||
autoHideHeader: false,
|
autoHideHeader: false,
|
||||||
color: null,
|
color: null,
|
||||||
apiUrl: null,
|
apiUrl: null,
|
||||||
layoutSetting: false
|
layoutSetting: false,
|
||||||
|
loginModal: false
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
SET_API_URL: (state, apiUrl) => {
|
SET_API_URL: (state, apiUrl) => {
|
||||||
|
@ -78,6 +79,9 @@ const app = {
|
||||||
TOGGLE_LAYOUT_SETTING: (state, show) => {
|
TOGGLE_LAYOUT_SETTING: (state, show) => {
|
||||||
Vue.ls.set(LAYOUT_SETTING, show)
|
Vue.ls.set(LAYOUT_SETTING, show)
|
||||||
state.layoutSetting = show
|
state.layoutSetting = show
|
||||||
|
},
|
||||||
|
TOGGLE_LOGIN_MODAL: (state, show) => {
|
||||||
|
state.loginModal = show
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
|
@ -116,6 +120,9 @@ const app = {
|
||||||
},
|
},
|
||||||
ToggleLayoutSetting({ commit }, show) {
|
ToggleLayoutSetting({ commit }, show) {
|
||||||
commit('TOGGLE_LAYOUT_SETTING', show)
|
commit('TOGGLE_LAYOUT_SETTING', show)
|
||||||
|
},
|
||||||
|
ToggleLoginModal({ commit }, show) {
|
||||||
|
commit('TOGGLE_LOGIN_MODAL', show)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ import axios from 'axios'
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import { message, notification } from 'ant-design-vue'
|
import { message, notification } from 'ant-design-vue'
|
||||||
import store from '@/store'
|
import store from '@/store'
|
||||||
import router from '@/router'
|
|
||||||
import { isObject } from './util'
|
import { isObject } from './util'
|
||||||
|
|
||||||
const service = axios.create({
|
const service = axios.create({
|
||||||
|
@ -38,7 +37,8 @@ async function refreshToken(error) {
|
||||||
await refreshTask
|
await refreshTask
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.response && err.response.data && err.response.data.data === refreshToken) {
|
if (err.response && err.response.data && err.response.data.data === refreshToken) {
|
||||||
router.push({ name: 'Login' })
|
message.warning('当前登录状态已失效,请重新登录')
|
||||||
|
store.dispatch('ToggleLoginModal', true)
|
||||||
}
|
}
|
||||||
Vue.$log.error('Failed to refresh token', err)
|
Vue.$log.error('Failed to refresh token', err)
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -124,7 +124,8 @@ service.interceptors.response.use(
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Login
|
// Login
|
||||||
router.push({ name: 'Login' })
|
message.warning('当前登录状态已失效,请重新登录')
|
||||||
|
store.dispatch('ToggleLoginModal', true)
|
||||||
}
|
}
|
||||||
} else if (data.status === 403) {
|
} else if (data.status === 403) {
|
||||||
// TODO handle 403 status error
|
// TODO handle 403 status error
|
||||||
|
|
|
@ -265,13 +265,13 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
beforeMount() {
|
||||||
this.verifyIsInstall()
|
this.handleVerifyIsInstall()
|
||||||
this.$set(this.installation, 'url', window.location.protocol + '//' + window.location.host)
|
this.$set(this.installation, 'url', window.location.protocol + '//' + window.location.host)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async verifyIsInstall() {
|
async handleVerifyIsInstall() {
|
||||||
await adminApi.isInstalled().then(response => {
|
await adminApi.isInstalled().then((response) => {
|
||||||
if (response.data.data) {
|
if (response.data.data) {
|
||||||
this.$router.push({ name: 'Login' })
|
this.$router.push({ name: 'Login' })
|
||||||
}
|
}
|
||||||
|
@ -279,7 +279,7 @@ export default {
|
||||||
},
|
},
|
||||||
handleNextStep() {
|
handleNextStep() {
|
||||||
if (this.stepCurrent === 0) {
|
if (this.stepCurrent === 0) {
|
||||||
this.$refs.generalForm.validate(valid => {
|
this.$refs.generalForm.validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
this.stepCurrent++
|
this.stepCurrent++
|
||||||
} else {
|
} else {
|
||||||
|
@ -287,7 +287,7 @@ export default {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else if (this.stepCurrent === 1) {
|
} else if (this.stepCurrent === 1) {
|
||||||
this.$refs.blogForm.validate(valid => {
|
this.$refs.blogForm.validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
this.stepCurrent++
|
this.stepCurrent++
|
||||||
} else {
|
} else {
|
||||||
|
@ -307,7 +307,7 @@ export default {
|
||||||
install() {
|
install() {
|
||||||
adminApi
|
adminApi
|
||||||
.install(this.installation)
|
.install(this.installation)
|
||||||
.then(response => {
|
.then((response) => {
|
||||||
this.$log.debug('Installation response', response)
|
this.$log.debug('Installation response', response)
|
||||||
this.$message.success('安装成功!')
|
this.$message.success('安装成功!')
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@ -326,7 +326,7 @@ export default {
|
||||||
const hide = this.$message.loading('数据导入中...', 0)
|
const hide = this.$message.loading('数据导入中...', 0)
|
||||||
migrateApi
|
migrateApi
|
||||||
.migrate(this.migrationData)
|
.migrate(this.migrationData)
|
||||||
.then(response => {
|
.then((response) => {
|
||||||
this.$log.debug('Migrated successfullly')
|
this.$log.debug('Migrated successfullly')
|
||||||
this.$message.success('数据导入成功!')
|
this.$message.success('数据导入成功!')
|
||||||
this.install()
|
this.install()
|
||||||
|
|
|
@ -2,101 +2,60 @@
|
||||||
<div class="container-wrapper">
|
<div class="container-wrapper">
|
||||||
<div class="halo-logo animated fadeInUp">
|
<div class="halo-logo animated fadeInUp">
|
||||||
<span>Halo
|
<span>Halo
|
||||||
<small v-if="apiModifyVisible">API 设置</small>
|
<small v-if="apiForm.visible">API 设置</small>
|
||||||
<small v-if="authcodeVisible">两步验证</small>
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-show="formVisible == 'login-form'"
|
v-show="!apiForm.visible"
|
||||||
class="login-form animated"
|
class="login-form animated"
|
||||||
>
|
>
|
||||||
<a-form
|
<LoginForm @success="onLoginSucceed" />
|
||||||
layout="vertical"
|
<a-row>
|
||||||
@keyup.enter.native="handleLoginPreCheck"
|
<a-col :span="24">
|
||||||
>
|
|
||||||
<a-form-item
|
|
||||||
class="animated fadeInUp"
|
|
||||||
:style="{'animation-delay': '0.1s'}"
|
|
||||||
>
|
|
||||||
<a-input
|
|
||||||
placeholder="用户名/邮箱"
|
|
||||||
v-model="username"
|
|
||||||
>
|
|
||||||
<a-icon
|
|
||||||
slot="prefix"
|
|
||||||
type="user"
|
|
||||||
style="color: rgba(0,0,0,.25)"
|
|
||||||
/>
|
|
||||||
</a-input>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item
|
|
||||||
class="animated fadeInUp"
|
|
||||||
:style="{'animation-delay': '0.2s'}"
|
|
||||||
>
|
|
||||||
<a-input
|
|
||||||
v-model="password"
|
|
||||||
type="password"
|
|
||||||
placeholder="密码"
|
|
||||||
>
|
|
||||||
<a-icon
|
|
||||||
slot="prefix"
|
|
||||||
type="lock"
|
|
||||||
style="color: rgba(0,0,0,.25)"
|
|
||||||
/>
|
|
||||||
</a-input>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item
|
|
||||||
class="animated fadeInUp"
|
|
||||||
:style="{'animation-delay': '0.3s'}"
|
|
||||||
>
|
|
||||||
<a-button
|
|
||||||
:loading="landing"
|
|
||||||
type="primary"
|
|
||||||
:block="true"
|
|
||||||
@click="handleLoginPreCheck"
|
|
||||||
>登录</a-button>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-row>
|
|
||||||
<router-link :to="{ name:'ResetPassword' }">
|
<router-link :to="{ name:'ResetPassword' }">
|
||||||
<a
|
<a
|
||||||
class="tip animated fadeInRight"
|
class="tip animated fadeInRight"
|
||||||
v-if="resetPasswordButton"
|
v-if="resetPasswordButtonVisible"
|
||||||
href="javascript:void(0);"
|
href="javascript:void(0);"
|
||||||
>
|
>
|
||||||
找回密码
|
找回密码
|
||||||
</a>
|
</a>
|
||||||
</router-link>
|
</router-link>
|
||||||
<a
|
<a
|
||||||
@click="toggleShowApiForm"
|
@click="handleToggleShowApiForm"
|
||||||
class="tip animated fadeInUp"
|
class="tip animated fadeInUp"
|
||||||
:style="{'animation-delay': '0.4s'}"
|
:style="{'animation-delay': '0.4s'}"
|
||||||
>
|
>
|
||||||
<a-icon type="setting" />
|
<a-icon type="setting" />
|
||||||
</a>
|
</a>
|
||||||
</a-row>
|
</a-col>
|
||||||
</a-form>
|
</a-row>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-show="apiModifyVisible"
|
v-show="apiForm.visible"
|
||||||
class="api-form animated"
|
class="api-form animated"
|
||||||
>
|
>
|
||||||
<a-form layout="vertical">
|
<a-form layout="vertical">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
class="animated fadeInUp"
|
class="animated fadeInUp"
|
||||||
:style="{'animation-delay': '0.1s'}"
|
:style="{'animation-delay': '0.1s'}"
|
||||||
extra="* 如果 Admin 不是独立部署,请不要更改此 API"
|
|
||||||
>
|
>
|
||||||
<a-input
|
<a-tooltip
|
||||||
placeholder="API 地址"
|
placement="top"
|
||||||
v-model="apiUrl"
|
title="如果 Admin 不是独立部署,请不要更改此 API"
|
||||||
|
trigger="click"
|
||||||
>
|
>
|
||||||
<a-icon
|
<a-input
|
||||||
slot="prefix"
|
placeholder="API 地址"
|
||||||
type="api"
|
v-model="apiForm.apiUrl"
|
||||||
style="color: rgba(0,0,0,.25)"
|
>
|
||||||
/>
|
<a-icon
|
||||||
</a-input>
|
slot="prefix"
|
||||||
|
type="api"
|
||||||
|
style="color: rgba(0,0,0,.25)"
|
||||||
|
/>
|
||||||
|
</a-input>
|
||||||
|
</a-tooltip>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item
|
<a-form-item
|
||||||
class="animated fadeInUp"
|
class="animated fadeInUp"
|
||||||
|
@ -104,7 +63,7 @@
|
||||||
>
|
>
|
||||||
<a-button
|
<a-button
|
||||||
:block="true"
|
:block="true"
|
||||||
@click="handleApiUrlRestore"
|
@click="handleRestoreApiUrl"
|
||||||
>恢复默认</a-button>
|
>恢复默认</a-button>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item
|
<a-form-item
|
||||||
|
@ -114,58 +73,12 @@
|
||||||
<a-button
|
<a-button
|
||||||
type="primary"
|
type="primary"
|
||||||
:block="true"
|
:block="true"
|
||||||
@click="handleApiModifyOk"
|
@click="handleModifyApiUrl"
|
||||||
>保存设置</a-button>
|
>保存设置</a-button>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
||||||
<a-row>
|
<a-row>
|
||||||
<a
|
<a
|
||||||
@click="toggleShowApiForm"
|
@click="handleToggleShowApiForm"
|
||||||
class="tip animated fadeInUp"
|
|
||||||
:style="{'animation-delay': '0.4s'}"
|
|
||||||
>
|
|
||||||
<a-icon type="rollback" />
|
|
||||||
</a>
|
|
||||||
</a-row>
|
|
||||||
</a-form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
v-show="authcodeVisible"
|
|
||||||
class="authcode-form animated"
|
|
||||||
>
|
|
||||||
<a-form layout="vertical" @keyup.enter.native="handleLogin">
|
|
||||||
<a-form-item
|
|
||||||
class="animated fadeInUp"
|
|
||||||
:style="{'animation-delay': '0.1s'}"
|
|
||||||
>
|
|
||||||
<a-input
|
|
||||||
placeholder="两步验证码"
|
|
||||||
v-model="authcode"
|
|
||||||
:maxLength="6"
|
|
||||||
>
|
|
||||||
<a-icon
|
|
||||||
slot="prefix"
|
|
||||||
type="safety-certificate"
|
|
||||||
style="color: rgba(0,0,0,.25)"
|
|
||||||
/>
|
|
||||||
</a-input>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item
|
|
||||||
class="animated fadeInUp"
|
|
||||||
:style="{'animation-delay': '0.3s'}"
|
|
||||||
>
|
|
||||||
<a-button
|
|
||||||
:loading="landing"
|
|
||||||
type="primary"
|
|
||||||
:block="true"
|
|
||||||
@click="handleLogin"
|
|
||||||
>验证</a-button>
|
|
||||||
</a-form-item>
|
|
||||||
|
|
||||||
<a-row>
|
|
||||||
<a
|
|
||||||
@click="toggleShowLoginForm"
|
|
||||||
class="tip animated fadeInUp"
|
class="tip animated fadeInUp"
|
||||||
:style="{'animation-delay': '0.4s'}"
|
:style="{'animation-delay': '0.4s'}"
|
||||||
>
|
>
|
||||||
|
@ -181,107 +94,47 @@
|
||||||
import adminApi from '@/api/admin'
|
import adminApi from '@/api/admin'
|
||||||
import { mapActions, mapGetters, mapMutations } from 'vuex'
|
import { mapActions, mapGetters, mapMutations } from 'vuex'
|
||||||
|
|
||||||
|
import LoginForm from '@/components/Login/LoginForm'
|
||||||
export default {
|
export default {
|
||||||
|
components: {
|
||||||
|
LoginForm
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
username: null,
|
resetPasswordButtonVisible: false,
|
||||||
password: null,
|
apiForm: {
|
||||||
authcode: null,
|
apiUrl: window.location.host,
|
||||||
needAuthCode: false,
|
visible: false
|
||||||
formVisible: 'login-form', // login-form api-form authcode-form
|
}
|
||||||
loginVisible: true,
|
|
||||||
apiModifyVisible: false,
|
|
||||||
authcodeVisible: false,
|
|
||||||
defaultApiBefore: window.location.protocol + '//',
|
|
||||||
apiUrl: window.location.host,
|
|
||||||
resetPasswordButton: false,
|
|
||||||
landing: false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters({ defaultApiUrl: 'apiUrl' })
|
...mapGetters({ defaultApiUrl: 'apiUrl' })
|
||||||
},
|
},
|
||||||
created() {
|
beforeMount() {
|
||||||
this.verifyIsInstall()
|
|
||||||
const _this = this
|
const _this = this
|
||||||
|
_this.handleVerifyIsInstall()
|
||||||
document.addEventListener('keydown', function(e) {
|
document.addEventListener('keydown', function(e) {
|
||||||
if (e.keyCode === 72 && e.altKey && e.shiftKey) {
|
if (e.keyCode === 72 && e.altKey && e.shiftKey) {
|
||||||
_this.toggleHidden()
|
_this.resetPasswordButtonVisible = !_this.resetPasswordButtonVisible
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
watch: {
|
|
||||||
formVisible(value) {
|
|
||||||
this.loginVisible = (value === 'authcode-form')
|
|
||||||
this.apiModifyVisible = (value === 'api-form')
|
|
||||||
this.authcodeVisible = (value === 'authcode-form')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(['login', 'refreshUserCache', 'refreshOptionsCache']),
|
...mapActions(['refreshUserCache', 'refreshOptionsCache']),
|
||||||
...mapMutations({
|
...mapMutations({
|
||||||
setApiUrl: 'SET_API_URL',
|
setApiUrl: 'SET_API_URL',
|
||||||
restoreApiUrl: 'RESTORE_API_URL'
|
restoreApiUrl: 'RESTORE_API_URL'
|
||||||
}),
|
}),
|
||||||
verifyIsInstall() {
|
handleVerifyIsInstall() {
|
||||||
adminApi.isInstalled().then(response => {
|
adminApi.isInstalled().then((response) => {
|
||||||
if (!response.data.data) {
|
if (!response.data.data) {
|
||||||
this.$router.push({ name: 'Install' })
|
this.$router.push({ name: 'Install' })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
handleLoginPreCheck() {
|
onLoginSucceed() {
|
||||||
if (!this.username) {
|
// Refresh the user info
|
||||||
this.$message.warn('用户名不能为空!')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.password) {
|
|
||||||
this.$message.warn('密码不能为空!')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
adminApi.loginPreCheck(this.username, this.password).then(response => {
|
|
||||||
if (response.data.data && response.data.data.needMFACode) {
|
|
||||||
this.formVisible = 'authcode-form'
|
|
||||||
this.authcode = null
|
|
||||||
this.needAuthCode = true
|
|
||||||
} else {
|
|
||||||
this.needAuthCode = false
|
|
||||||
this.handleLogin()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
handleLogin() {
|
|
||||||
if (!this.username) {
|
|
||||||
this.$message.warn('用户名不能为空!')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.password) {
|
|
||||||
this.$message.warn('密码不能为空!')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.needAuthCode && !this.authcode) {
|
|
||||||
this.$message.warn('两步验证码不能为空!')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.landing = true
|
|
||||||
this.login({ username: this.username, password: this.password, authcode: this.authcode })
|
|
||||||
.then(response => {
|
|
||||||
// Go to dashboard
|
|
||||||
this.loginSuccess()
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.landing = false
|
|
||||||
}, 400)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
loginSuccess() {
|
|
||||||
// Cache the user info
|
|
||||||
this.refreshUserCache()
|
this.refreshUserCache()
|
||||||
this.refreshOptionsCache()
|
this.refreshOptionsCache()
|
||||||
if (this.$route.query.redirect) {
|
if (this.$route.query.redirect) {
|
||||||
|
@ -290,27 +143,19 @@ export default {
|
||||||
this.$router.replace({ name: 'Dashboard' })
|
this.$router.replace({ name: 'Dashboard' })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleApiModifyOk() {
|
handleModifyApiUrl() {
|
||||||
this.setApiUrl(this.apiUrl)
|
this.setApiUrl(this.apiForm.apiUrl)
|
||||||
this.formVisible = 'login-form'
|
this.apiForm.visible = false
|
||||||
},
|
},
|
||||||
handleApiUrlRestore() {
|
handleRestoreApiUrl() {
|
||||||
this.restoreApiUrl()
|
this.restoreApiUrl()
|
||||||
this.apiUrl = this.defaultApiUrl
|
this.apiForm.apiUrl = this.defaultApiUrl
|
||||||
},
|
},
|
||||||
toggleShowApiForm() {
|
handleToggleShowApiForm() {
|
||||||
this.formVisible = this.apiModifyVisible ? 'login-form' : 'api-form'
|
this.apiForm.visible = !this.apiForm.visible
|
||||||
this.apiModifyVisible = !this.apiModifyVisible
|
if (this.apiForm.visible) {
|
||||||
if (this.apiModifyVisible) {
|
this.apiForm.apiUrl = this.defaultApiUrl
|
||||||
this.apiUrl = this.defaultApiUrl
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
toggleShowLoginForm() {
|
|
||||||
this.formVisible = 'login-form'
|
|
||||||
this.password = null
|
|
||||||
},
|
|
||||||
toggleHidden() {
|
|
||||||
this.resetPasswordButton = !this.resetPasswordButton
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue