import request from '@/plugin/axios' export function AccountLogin (data) { return request({ url: '/login', method: 'post', data }) }
import { Message, MessageBox } from 'element-ui' import util from '@/libs/util.js' import router from '@/router' import { AccountLogin } from '@api/sys.login' export default { namespaced: true, actions: { /** * @description 登陸 * @param {Object} param context * @param {Object} param username {String} 用戶帳號 * @param {Object} param password {String} 密碼 * @param {Object} param route {Object} 登陸成功後定向的路由對象 任何 vue-router 支持的格式 */ login ({ dispatch }, { username = '', password = '' } = {}) { return new Promise((resolve, reject) => { // 開始請求登陸接口 AccountLogin({ username, password }) .then(async res => { // 設置 cookie 必定要存 uuid 和 token 兩個 cookie // 整個系統依賴這兩個數據進行校驗和存儲 // uuid 是用戶身份惟一標識 用戶註冊的時候肯定 而且不可改變 不可重複 // token 表明用戶當前登陸狀態 建議在網絡請求中攜帶 token // 若有必要 token 須要定時更新,默認保存一天 util.cookies.set('uuid', res.uuid) util.cookies.set('token', res.token) // 設置 vuex 用戶信息 await dispatch('d2admin/user/set', { name: res.name }, { root: true }) // 用戶登陸後從持久化數據加載一系列的設置 await dispatch('load') // 結束 resolve() }) .catch(err => { console.log('err: ', err) reject(err) }) }) }, /** * @description 註銷用戶並返回登陸頁面 * @param {Object} param context * @param {Object} param confirm {Boolean} 是否須要確認 */ logout ({ commit, dispatch }, { confirm = false } = {}) { /** * @description 註銷 */ async function logout () { // 刪除cookie util.cookies.remove('token') util.cookies.remove('uuid') // 清空 vuex 用戶信息 await dispatch('d2admin/user/set', {}, { root: true }) // 跳轉路由 router.push({ name: 'login' }) } // 判斷是否須要確認 if (confirm) { commit('d2admin/gray/set', true, { root: true }) MessageBox.confirm('註銷當前帳戶嗎? 打開的標籤頁和用戶設置將會被保存。', '確認操做', { confirmButtonText: '肯定註銷', cancelButtonText: '放棄', type: 'warning' }) .then(() => { commit('d2admin/gray/set', false, { root: true }) logout() }) .catch(() => { commit('d2admin/gray/set', false, { root: true }) Message({ message: '放棄註銷用戶' }) }) } else { logout() } }, /** * @description 用戶登陸後從持久化數據加載一系列的設置 * @param {Object} state vuex state */ load ({ dispatch }) { return new Promise(async resolve => { // DB -> store 加載用戶名 await dispatch('d2admin/user/load', null, { root: true }) // DB -> store 加載主題 await dispatch('d2admin/theme/load', null, { root: true }) // DB -> store 加載頁面過渡效果設置 await dispatch('d2admin/transition/load', null, { root: true }) // DB -> store 持久化數據加載上次退出時的多頁列表 await dispatch('d2admin/page/openedLoad', null, { root: true }) // DB -> store 持久化數據加載側邊欄摺疊狀態 await dispatch('d2admin/menu/asideCollapseLoad', null, { root: true }) // DB -> store 持久化數據加載全局尺寸 await dispatch('d2admin/size/load', null, { root: true }) // end resolve() }) } } }
methods: { ...mapActions('d2admin/account', [ 'login' ]),
<template> <div class="page-login"> <div class="page-login--layer page-login--layer-area"> <ul class="circles"> <li v-for="n in 10" :key="n"></li> </ul> </div> <div class="page-login--layer page-login--layer-time" flex="main:center cross:center"> {{time}} </div> <div class="page-login--layer"> <div class="page-login--content" flex="dir:top main:justify cross:center box:justify"> <div class="page-login--content-header"> <p class="page-login--content-header-motto"> 時間是一切財富中最寶貴的財富。 <span>—— 德奧弗拉斯多</span> </p> </div> <div class="page-login--content-main" flex="dir:top main:center cross:center"> <!-- logo --> <img class="page-login--logo" src="./image/logo@2x.png"> <!-- 表單 --> <div class="page-login--form"> <el-card shadow="never"> <el-form ref="loginForm" label-position="top" :rules="rules" :model="formLogin" size="default"> <el-form-item prop="username"> <el-input type="text" v-model="formLogin.username" placeholder="用戶名"> <i slot="prepend" class="fa fa-user-circle-o"></i> </el-input> </el-form-item> <el-form-item prop="password"> <el-input type="password" v-model="formLogin.password" placeholder="密碼"> <i slot="prepend" class="fa fa-keyboard-o"></i> </el-input> </el-form-item> <el-form-item prop="code"> <el-input type="text" v-model="formLogin.code" placeholder="- - - -"> <template slot="prepend">驗證碼</template> <template slot="append"> <img class="login-code" src="./image/login-code.png"> </template> </el-input> </el-form-item> <el-button size="default" @click="submit" type="primary" class="button-login">登陸</el-button> </el-form> </el-card> <p class="page-login--options" flex="main:justify cross:center"> <span><d2-icon name="question-circle"/> 忘記密碼</span> <span>註冊用戶</span> </p> <!-- 快速登陸按鈕 --> <el-button class="page-login--quick" size="default" type="info" @click="dialogVisible = true"> 快速選擇用戶(測試功能) </el-button> </div> </div> <div class="page-login--content-footer"> <p class="page-login--content-footer-options"> <a href="#">幫助</a> <a href="#">隱私</a> <a href="#">條款</a> </p> <p class="page-login--content-footer-copyright"> Copyright <d2-icon name="copyright"/> 2018 D2 Projects 開源組織出品 <a href="https://github.com/FairyEver">@FairyEver</a> </p> </div> </div> </div> <el-dialog title="快速選擇用戶" :visible.sync="dialogVisible" width="400px"> <el-row :gutter="10" style="margin: -20px 0px -10px 0px;"> <el-col v-for="(user, index) in users" :key="index" :span="8"> <div class="page-login--quick-user" @click="handleUserBtnClick(user)"> <d2-icon name="user-circle-o"/> <span>{{user.name}}</span> </div> </el-col> </el-row> </el-dialog> </div> </template> <script> import dayjs from 'dayjs' import { mapActions } from 'vuex' export default { data () { return { timeInterval: null, time: dayjs().format('HH:mm:ss'), // 快速選擇用戶 dialogVisible: false, users: [ { name: '管理員', username: 'admin', password: 'admin' }, { name: '編輯', username: 'editor', password: 'editor' }, { name: '用戶1', username: 'user1', password: 'user1' } ], // 表單 formLogin: { username: 'admin', password: 'admin', code: 'v9am' }, // 校驗 rules: { username: [ { required: true, message: '請輸入用戶名', trigger: 'blur' } ], password: [ { required: true, message: '請輸入密碼', trigger: 'blur' } ], code: [ { required: true, message: '請輸入驗證碼', trigger: 'blur' } ] } } }, mounted () { this.timeInterval = setInterval(() => { this.refreshTime() }, 1000) }, beforeDestroy () { clearInterval(this.timeInterval) }, methods: { ...mapActions('d2admin/account', [ 'login' ]), refreshTime () { this.time = dayjs().format('HH:mm:ss') }, /** * @description 接收選擇一個用戶快速登陸的事件 * @param {Object} user 用戶信息 */ handleUserBtnClick (user) { this.formLogin.username = user.username this.formLogin.password = user.password this.submit() }, /** * @description 提交表單 */ // 提交登陸信息 submit () { this.$refs.loginForm.validate((valid) => { if (valid) { // 登陸 // 注意 這裏的演示沒有傳驗證碼 // 具體須要傳遞的數據請自行修改代碼 this.login({ username: this.formLogin.username, password: this.formLogin.password }) .then(() => { // 重定向對象不存在則返回頂層路徑 this.$router.replace(this.$route.query.redirect || '/') }) } else { // 登陸表單校驗失敗 this.$message.error('表單校驗失敗') } }) } } } </script> <style lang="scss"> .page-login { @extend %unable-select; $backgroundColor: #F0F2F5; // --- background-color: $backgroundColor; height: 100%; position: relative; // 層 .page-login--layer { @extend %full; overflow: auto; } .page-login--layer-area { overflow: hidden; } // 時間 .page-login--layer-time { font-size: 24em; font-weight: bold; color: rgba(0, 0, 0, 0.03); overflow: hidden; } // 登錄頁面控件的容器 .page-login--content { height: 100%; min-height: 500px; } // header .page-login--content-header { padding: 1em 0; .page-login--content-header-motto { margin: 0px; padding: 0px; color: $color-text-normal; text-align: center; font-size: 12px; span { color: $color-text-sub; } } } // main .page-login--logo { width: 240px; margin-bottom: 2em; margin-top: -2em; } // 登陸表單 .page-login--form { width: 280px; // 卡片 .el-card { margin-bottom: 15px; } // 登陸按鈕 .button-login { width: 100%; } // 輸入框左邊的圖表區域縮窄 .el-input-group__prepend { padding: 0px 14px; } .login-code { height: 40px - 2px; display: block; margin: 0px -20px; border-top-right-radius: 2px; border-bottom-right-radius: 2px; } // 登錄選項 .page-login--options { margin: 0px; padding: 0px; font-size: 14px; color: $color-primary; margin-bottom: 15px; font-weight: bold; } .page-login--quick { width: 100%; } } // 快速選擇用戶面板 .page-login--quick-user { @extend %flex-center-col; padding: 10px 0px; border-radius: 4px; &:hover { background-color: $color-bg; i { color: $color-text-normal; } span { color: $color-text-normal; } } i { font-size: 36px; color: $color-text-sub; } span { font-size: 12px; margin-top: 10px; color: $color-text-sub; } } // footer .page-login--content-footer { padding: 1em 0; .page-login--content-footer-options { padding: 0px; margin: 0px; margin-bottom: 10px; font-size: 14px; text-align: center; a { color: $color-text-normal; margin: 0 1em; } } .page-login--content-footer-copyright { padding: 0px; margin: 0px; font-size: 12px; color: $color-text-normal; a { color: $color-text-normal; } } } // 背景 .circles { position: absolute; top: 0; left: 0; width: 100%; height: 100%; overflow: hidden; li { position: absolute; display: block; list-style: none; width: 20px; height: 20px; background: #FFF; animation: animate 25s linear infinite; bottom: -200px; @keyframes animate { 0%{ transform: translateY(0) rotate(0deg); opacity: 1; border-radius: 0; } 100%{ transform: translateY(-1000px) rotate(720deg); opacity: 0; border-radius: 50%; } } &:nth-child(1) { left: 15%; width: 80px; height: 80px; animation-delay: 0s; } &:nth-child(2) { left: 5%; width: 20px; height: 20px; animation-delay: 2s; animation-duration: 12s; } &:nth-child(3) { left: 70%; width: 20px; height: 20px; animation-delay: 4s; } &:nth-child(4) { left: 40%; width: 60px; height: 60px; animation-delay: 0s; animation-duration: 18s; } &:nth-child(5) { left: 65%; width: 20px; height: 20px; animation-delay: 0s; } &:nth-child(6) { left: 75%; width: 150px; height: 150px; animation-delay: 3s; } &:nth-child(7) { left: 35%; width: 200px; height: 200px; animation-delay: 7s; } &:nth-child(8) { left: 50%; width: 25px; height: 25px; animation-delay: 15s; animation-duration: 45s; } &:nth-child(9) { left: 20%; width: 15px; height: 15px; animation-delay: 2s; animation-duration: 35s; } &:nth-child(10) { left: 85%; width: 150px; height: 150px; animation-delay: 0s; animation-duration: 11s; } } } } </style>
跨域問題,在vue.config.js裏面配置css