diff --git a/package-lock.json b/package-lock.json index a8fc34fd2..fed371a14 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2601,6 +2601,34 @@ "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": { "version": "6.2.0", "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": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/vue-ls/-/vue-ls-3.2.1.tgz", diff --git a/package.json b/package.json index bde40e9eb..4bf50334f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,17 @@ { "name": "halo-admin", "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": { "serve": "vue-cli-service serve", "build": "vue-cli-service build", @@ -137,16 +148,5 @@ "> 1%", "last 2 versions", "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" -} + ] +} \ No newline at end of file diff --git a/src/components/Attachment/AttachmentSelectDrawer.vue b/src/components/Attachment/AttachmentSelectDrawer.vue index ce5d9640b..37c651bfd 100644 --- a/src/components/Attachment/AttachmentSelectDrawer.vue +++ b/src/components/Attachment/AttachmentSelectDrawer.vue @@ -150,7 +150,7 @@ export default { this.queryParam.sort = this.pagination.sort attachmentApi .query(this.queryParam) - .then(response => { + .then((response) => { this.attachments = response.data.data.content this.pagination.total = response.data.data.total }) diff --git a/src/components/Editor/MarkdownEditor.vue b/src/components/Editor/MarkdownEditor.vue index 6e3ec42fe..ef395a80a 100644 --- a/src/components/Editor/MarkdownEditor.vue +++ b/src/components/Editor/MarkdownEditor.vue @@ -47,7 +47,7 @@ export default { handleAttachmentUpload(pos, $file) { var formdata = new FormData() formdata.append('file', $file) - attachmentApi.upload(formdata).then(response => { + attachmentApi.upload(formdata).then((response) => { var responseObject = response.data var HaloEditor = this.$refs.md HaloEditor.$img2Url(pos, encodeURI(responseObject.data.path)) diff --git a/src/components/Ellipsis/Ellipsis.vue b/src/components/Ellipsis/Ellipsis.vue index fa612b95e..642e54ad0 100644 --- a/src/components/Ellipsis/Ellipsis.vue +++ b/src/components/Ellipsis/Ellipsis.vue @@ -29,27 +29,23 @@ export default { }, methods: { getStrDom(str, fullLength) { - return ( - { cutStrByFullLength(str, this.length) + (fullLength > this.length ? '...' : '') } - ) + return {cutStrByFullLength(str, this.length) + (fullLength > this.length ? '...' : '')} }, getTooltip(fullStr, fullLength) { return ( - - { this.getStrDom(fullStr, fullLength) } + + {this.getStrDom(fullStr, fullLength)} ) } }, render() { 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 strDom = tooltip && fullLength > length ? this.getTooltip(str, fullLength) : this.getStrDom(str, fullLength) - return ( - strDom - ) + return strDom } } diff --git a/src/components/FooterToolbar/index.less b/src/components/FooterToolbar/index.less index f966dfeb6..0cb6621ff 100644 --- a/src/components/FooterToolbar/index.less +++ b/src/components/FooterToolbar/index.less @@ -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} { position: fixed; @@ -16,8 +16,8 @@ z-index: 1000; &:after { - content: ""; + content: ''; display: block; clear: both; } -} \ No newline at end of file +} diff --git a/src/components/Login/LoginForm.vue b/src/components/Login/LoginForm.vue new file mode 100644 index 000000000..3eaa84904 --- /dev/null +++ b/src/components/Login/LoginForm.vue @@ -0,0 +1,162 @@ + + diff --git a/src/components/Login/LoginModal.vue b/src/components/Login/LoginModal.vue new file mode 100644 index 000000000..cbacddb44 --- /dev/null +++ b/src/components/Login/LoginModal.vue @@ -0,0 +1,38 @@ + + + diff --git a/src/components/Menu/SideMenu.vue b/src/components/Menu/SideMenu.vue index 2349a6b88..df57e65e1 100644 --- a/src/components/Menu/SideMenu.vue +++ b/src/components/Menu/SideMenu.vue @@ -6,7 +6,7 @@ v-model="collapsed" :trigger="null" > - + - ) + typeof icon === 'object' ? (props.component = icon) : (props.type = icon) + return } }, render() { @@ -162,6 +160,6 @@ export default { return this.renderItem(item) }) - return ({menuTree}) + return {menuTree} } } diff --git a/src/components/Menu/menu.render.js b/src/components/Menu/menu.render.js index ccf8631c3..73c34e03e 100644 --- a/src/components/Menu/menu.render.js +++ b/src/components/Menu/menu.render.js @@ -62,7 +62,7 @@ export default { return null } 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 } }) }, renderMenuItem: function(h, menu, pIndex, index) { diff --git a/src/components/PageHeader/PageHeader.vue b/src/components/PageHeader/PageHeader.vue index 09ca753e9..1d5735689 100644 --- a/src/components/PageHeader/PageHeader.vue +++ b/src/components/PageHeader/PageHeader.vue @@ -3,22 +3,38 @@
-
+
- +
-
+
-
+
-
+
diff --git a/src/components/SettingDrawer/SettingItem.vue b/src/components/SettingDrawer/SettingItem.vue index 2b3b553c0..bcf79108d 100644 --- a/src/components/SettingDrawer/SettingItem.vue +++ b/src/components/SettingDrawer/SettingItem.vue @@ -2,7 +2,7 @@

{{ title }}

- +
@@ -23,16 +23,14 @@ export default { diff --git a/src/components/Tools/Breadcrumb.vue b/src/components/Tools/Breadcrumb.vue index e8cedfe1a..bd45a92d5 100644 --- a/src/components/Tools/Breadcrumb.vue +++ b/src/components/Tools/Breadcrumb.vue @@ -1,6 +1,9 @@ @@ -71,6 +73,7 @@ import SideMenu from '@/components/Menu/SideMenu' import GlobalHeader from '@/components/GlobalHeader' import GlobalFooter from '@/components/GlobalFooter' import SettingDrawer from '@/components/SettingDrawer/SettingDrawer' +import LoginModal from '@/components/Login/LoginModal' export default { name: 'BasicLayout', @@ -80,7 +83,8 @@ export default { SideMenu, GlobalHeader, GlobalFooter, - SettingDrawer + SettingDrawer, + LoginModal }, data() { return { @@ -92,7 +96,7 @@ export default { computed: { ...mapState({ // 动态主路由 - mainMenu: state => state.permission.addRouters + mainMenu: (state) => state.permission.addRouters }), contentPaddingLeft() { if (!this.fixSidebar || this.isMobile()) { @@ -110,7 +114,7 @@ export default { } }, 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.collapsed = !this.sidebarOpened }, @@ -126,7 +130,7 @@ export default { } }, methods: { - ...mapActions(['setSidebar']), + ...mapActions(['setSidebar', 'ToggleLoginModal']), toggle() { this.collapsed = !this.collapsed this.setSidebar(!this.collapsed) @@ -137,7 +141,7 @@ export default { if (this.sidebarOpened) { left = this.isDesktop() ? '256px' : '80px' } else { - left = (this.isMobile() && '0') || ((this.fixSidebar && '80px') || '0') + left = (this.isMobile() && '0') || (this.fixSidebar && '80px') || '0' } return left }, @@ -148,6 +152,9 @@ export default { }, drawerClose() { this.collapsed = false + }, + onLoginSucceed() { + this.ToggleLoginModal(false) } } } diff --git a/src/store/getters.js b/src/store/getters.js index 48e03d239..8056f1a48 100644 --- a/src/store/getters.js +++ b/src/store/getters.js @@ -3,6 +3,7 @@ const getters = { theme: state => state.app.theme, color: state => state.app.color, layoutSetting: state => state.app.layoutSetting, + loginModal: state => state.app.loginModal, token: state => state.user.token, user: state => state.user.user, addRouters: state => state.permission.addRouters, diff --git a/src/store/modules/app.js b/src/store/modules/app.js index 94bd78ee1..414af9d31 100644 --- a/src/store/modules/app.js +++ b/src/store/modules/app.js @@ -24,7 +24,8 @@ const app = { autoHideHeader: false, color: null, apiUrl: null, - layoutSetting: false + layoutSetting: false, + loginModal: false }, mutations: { SET_API_URL: (state, apiUrl) => { @@ -78,6 +79,9 @@ const app = { TOGGLE_LAYOUT_SETTING: (state, show) => { Vue.ls.set(LAYOUT_SETTING, show) state.layoutSetting = show + }, + TOGGLE_LOGIN_MODAL: (state, show) => { + state.loginModal = show } }, actions: { @@ -116,6 +120,9 @@ const app = { }, ToggleLayoutSetting({ commit }, show) { commit('TOGGLE_LAYOUT_SETTING', show) + }, + ToggleLoginModal({ commit }, show) { + commit('TOGGLE_LOGIN_MODAL', show) } } } diff --git a/src/utils/service.js b/src/utils/service.js index 9e08e93c3..7d152b3ab 100644 --- a/src/utils/service.js +++ b/src/utils/service.js @@ -2,7 +2,6 @@ import axios from 'axios' import Vue from 'vue' import { message, notification } from 'ant-design-vue' import store from '@/store' -import router from '@/router' import { isObject } from './util' const service = axios.create({ @@ -38,7 +37,8 @@ async function refreshToken(error) { await refreshTask } catch (err) { 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) } finally { @@ -124,7 +124,8 @@ service.interceptors.response.use( } } else { // Login - router.push({ name: 'Login' }) + message.warning('当前登录状态已失效,请重新登录') + store.dispatch('ToggleLoginModal', true) } } else if (data.status === 403) { // TODO handle 403 status error diff --git a/src/views/system/Installation.vue b/src/views/system/Installation.vue index 61d3c8672..1957880ec 100644 --- a/src/views/system/Installation.vue +++ b/src/views/system/Installation.vue @@ -265,13 +265,13 @@ export default { } } }, - created() { - this.verifyIsInstall() + beforeMount() { + this.handleVerifyIsInstall() this.$set(this.installation, 'url', window.location.protocol + '//' + window.location.host) }, methods: { - async verifyIsInstall() { - await adminApi.isInstalled().then(response => { + async handleVerifyIsInstall() { + await adminApi.isInstalled().then((response) => { if (response.data.data) { this.$router.push({ name: 'Login' }) } @@ -279,7 +279,7 @@ export default { }, handleNextStep() { if (this.stepCurrent === 0) { - this.$refs.generalForm.validate(valid => { + this.$refs.generalForm.validate((valid) => { if (valid) { this.stepCurrent++ } else { @@ -287,7 +287,7 @@ export default { } }) } else if (this.stepCurrent === 1) { - this.$refs.blogForm.validate(valid => { + this.$refs.blogForm.validate((valid) => { if (valid) { this.stepCurrent++ } else { @@ -307,7 +307,7 @@ export default { install() { adminApi .install(this.installation) - .then(response => { + .then((response) => { this.$log.debug('Installation response', response) this.$message.success('安装成功!') setTimeout(() => { @@ -326,7 +326,7 @@ export default { const hide = this.$message.loading('数据导入中...', 0) migrateApi .migrate(this.migrationData) - .then(response => { + .then((response) => { this.$log.debug('Migrated successfullly') this.$message.success('数据导入成功!') this.install() diff --git a/src/views/user/Login.vue b/src/views/user/Login.vue index 21b872948..18592f78a 100644 --- a/src/views/user/Login.vue +++ b/src/views/user/Login.vue @@ -2,101 +2,60 @@
- - - + + + + 恢复默认 保存设置 - - - - - - - -
- -
- - - - - - - - 验证 - - @@ -181,107 +94,47 @@ import adminApi from '@/api/admin' import { mapActions, mapGetters, mapMutations } from 'vuex' +import LoginForm from '@/components/Login/LoginForm' export default { + components: { + LoginForm + }, data() { return { - username: null, - password: null, - authcode: null, - needAuthCode: 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 + resetPasswordButtonVisible: false, + apiForm: { + apiUrl: window.location.host, + visible: false + } } }, computed: { ...mapGetters({ defaultApiUrl: 'apiUrl' }) }, - created() { - this.verifyIsInstall() + beforeMount() { const _this = this + _this.handleVerifyIsInstall() document.addEventListener('keydown', function(e) { 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: { - ...mapActions(['login', 'refreshUserCache', 'refreshOptionsCache']), + ...mapActions(['refreshUserCache', 'refreshOptionsCache']), ...mapMutations({ setApiUrl: 'SET_API_URL', restoreApiUrl: 'RESTORE_API_URL' }), - verifyIsInstall() { - adminApi.isInstalled().then(response => { + handleVerifyIsInstall() { + adminApi.isInstalled().then((response) => { if (!response.data.data) { this.$router.push({ name: 'Install' }) } }) }, - handleLoginPreCheck() { - if (!this.username) { - 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 + onLoginSucceed() { + // Refresh the user info this.refreshUserCache() this.refreshOptionsCache() if (this.$route.query.redirect) { @@ -290,27 +143,19 @@ export default { this.$router.replace({ name: 'Dashboard' }) } }, - handleApiModifyOk() { - this.setApiUrl(this.apiUrl) - this.formVisible = 'login-form' + handleModifyApiUrl() { + this.setApiUrl(this.apiForm.apiUrl) + this.apiForm.visible = false }, - handleApiUrlRestore() { + handleRestoreApiUrl() { this.restoreApiUrl() - this.apiUrl = this.defaultApiUrl + this.apiForm.apiUrl = this.defaultApiUrl }, - toggleShowApiForm() { - this.formVisible = this.apiModifyVisible ? 'login-form' : 'api-form' - this.apiModifyVisible = !this.apiModifyVisible - if (this.apiModifyVisible) { - this.apiUrl = this.defaultApiUrl + handleToggleShowApiForm() { + this.apiForm.visible = !this.apiForm.visible + if (this.apiForm.visible) { + this.apiForm.apiUrl = this.defaultApiUrl } - }, - toggleShowLoginForm() { - this.formVisible = 'login-form' - this.password = null - }, - toggleHidden() { - this.resetPasswordButton = !this.resetPasswordButton } } }