1. 新增登录页面 2. 新增登录接口 3. 新增stores/userToken.js 保存登录状态登录和退出登录 和 stores/activeCheck.js 保存登录超时和延时函数 4. components/core/Header完善退出登录点击事件 5. 新增cookie工具类 6. 新增登录工具类
| | |
| | | <template> |
| | | <el-config-provider :locale="locale"> |
| | | <template v-if="$route.name == 'loginView'"> |
| | | <el-scrollbar> |
| | | <div class="el-main__content"> |
| | | <Content></Content> |
| | | </div> |
| | | </el-scrollbar> |
| | | </template> |
| | | <el-config-provider v-else :locale="locale"> |
| | | <el-container class="el-container"> |
| | | <el-aside class="el-aside" |
| | | ><SiderMenu |
| | | :collapse="isCollapsed" |
| | | @nav-page="navPage" |
| | | ></SiderMenu |
| | | ></el-aside> |
| | | <el-aside class="el-aside"> |
| | | <SiderMenu :collapse="isCollapsed" @nav-page="navPage"></SiderMenu> |
| | | </el-aside> |
| | | <el-container> |
| | | <el-header class="el-header" |
| | | ><Header |
| | | :navTitles="navTitles" |
| | | :collapse="isCollapsed" |
| | | @collapsed-sider="collapsedSider" |
| | | ></Header |
| | | ></el-header> |
| | | <el-header class="el-header"> |
| | | <Header :navTitles="navTitles" :collapse="isCollapsed" @collapsed-sider="collapsedSider"></Header> |
| | | </el-header> |
| | | <el-main class="el-main"> |
| | | <el-scrollbar> |
| | | <div class="el-main__content"> |
| | |
| | | /* background-color: aqua; */ |
| | | /* overflow: auto; */ |
| | | } |
| | | |
| | | .back-top { |
| | | display: flex; |
| | | align-items: center; |
| | |
| | | import axios from 'axios'; |
| | | import pinia from '../stores/index' |
| | | import { ElMessage } from 'element-plus'; |
| | | import { useActiveCheck } from '@/stores/activeCheck'; |
| | | import { router } from '@/router/index'; |
| | | |
| | | const debug = false; |
| | | |
| | |
| | | }); |
| | | $fytz.imgUrl = `${ip2_file}images/`; |
| | | |
| | | const activeCheck = useActiveCheck(pinia); |
| | | |
| | | function resetLoginTime() { |
| | | if (activeCheck.isActive()) { |
| | | // éç½®ç»å½æ¶é |
| | | activeCheck.updateLoginTime() |
| | | } |
| | | } |
| | | //æ·»å æ¦æªå¨ |
| | | [$fysp, $fytz].forEach((i) => { |
| | | // æ·»å è¯·æ±æ¦æªå¨ |
| | | i.interceptors.request.use( |
| | | function (config) { |
| | | // å¨åé请æ±ä¹ååäºä»ä¹ |
| | | // æ·»å ç»å½éªè¯ |
| | | if (router.currentRoute._value.fullPath !== '/common/loginView') { |
| | | resetLoginTime() |
| | | } |
| | | // if (import.meta.env.DEV) { |
| | | // console.log('==>请æ±å¼å§'); |
| | | // console.log(`${config.baseURL}${config.url}`); |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import { $fysp } from './index'; |
| | | |
| | | export default { |
| | | /** |
| | | * ç»å½æ¥å£ |
| | | */ |
| | | login({ username, password }) { |
| | | return $fysp |
| | | .post(`/userinfo/login`, { |
| | | acountname: username, |
| | | departmentname: '', |
| | | dguid: '', |
| | | extension1: '', |
| | | extension2: '', |
| | | extension3: '', |
| | | guid: '', |
| | | isenable: true, |
| | | password: password, |
| | | realname: '', |
| | | remark: '', |
| | | telephone: '', |
| | | usertype: '', |
| | | usertypeid: '', |
| | | wechatid: '', |
| | | workno: '' |
| | | }) |
| | | .then((res) => res.data); |
| | | } |
| | | }; |
| | |
| | | ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb'] |
| | | ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem'] |
| | | ElButton: typeof import('element-plus/es')['ElButton'] |
| | | ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup'] |
| | | ElCalendar: typeof import('element-plus/es')['ElCalendar'] |
| | | ElCard: typeof import('element-plus/es')['ElCard'] |
| | | ElCascader: typeof import('element-plus/es')['ElCascader'] |
| | |
| | | ElDialog: typeof import('element-plus/es')['ElDialog'] |
| | | ElDivider: typeof import('element-plus/es')['ElDivider'] |
| | | ElDrawer: typeof import('element-plus/es')['ElDrawer'] |
| | | ElDropdown: typeof import('element-plus/es')['ElDropdown'] |
| | | ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] |
| | | ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu'] |
| | | ElEmpty: typeof import('element-plus/es')['ElEmpty'] |
| | | ElForm: typeof import('element-plus/es')['ElForm'] |
| | | ElFormItem: typeof import('element-plus/es')['ElFormItem'] |
| | |
| | | ElImage: typeof import('element-plus/es')['ElImage'] |
| | | ElImageViewer: typeof import('element-plus/es')['ElImageViewer'] |
| | | ElInput: typeof import('element-plus/es')['ElInput'] |
| | | ElInputNumber: typeof import('element-plus/es')['ElInputNumber'] |
| | | ElLink: typeof import('element-plus/es')['ElLink'] |
| | | ElMain: typeof import('element-plus/es')['ElMain'] |
| | | ElMenu: typeof import('element-plus/es')['ElMenu'] |
| | | ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] |
| | | ElMenuItemGroup: typeof import('element-plus/es')['ElMenuItemGroup'] |
| | | ElOption: typeof import('element-plus/es')['ElOption'] |
| | | ElPageHeader: typeof import('element-plus/es')['ElPageHeader'] |
| | | ElPagination: typeof import('element-plus/es')['ElPagination'] |
| | | ElPopconfirm: typeof import('element-plus/es')['ElPopconfirm'] |
| | | ElPopover: typeof import('element-plus/es')['ElPopover'] |
| | | ElRadio: typeof import('element-plus/es')['ElRadio'] |
| | | ElRadioButton: typeof import('element-plus/es')['ElRadioButton'] |
| | | ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup'] |
| | | ElRow: typeof import('element-plus/es')['ElRow'] |
| | | ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] |
| | | ElSegmented: typeof import('element-plus/es')['ElSegmented'] |
| | |
| | | ElStep: typeof import('element-plus/es')['ElStep'] |
| | | ElSteps: typeof import('element-plus/es')['ElSteps'] |
| | | ElSubMenu: typeof import('element-plus/es')['ElSubMenu'] |
| | | ElSwitch: typeof import('element-plus/es')['ElSwitch'] |
| | | ElTable: typeof import('element-plus/es')['ElTable'] |
| | | ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] |
| | | ElTabPane: typeof import('element-plus/es')['ElTabPane'] |
| | |
| | | ElTag: typeof import('element-plus/es')['ElTag'] |
| | | ElText: typeof import('element-plus/es')['ElText'] |
| | | ElTooltip: typeof import('element-plus/es')['ElTooltip'] |
| | | ElTransfer: typeof import('element-plus/es')['ElTransfer'] |
| | | ElTree: typeof import('element-plus/es')['ElTree'] |
| | | ElUpload: typeof import('element-plus/es')['ElUpload'] |
| | | Footer: typeof import('./components/core/Footer.vue')['default'] |
| | |
| | | </el-col> |
| | | <el-col :span="12" class="logout"> |
| | | <FYBgTaskDialog></FYBgTaskDialog> |
| | | <el-button icon="SwitchButton">éåºç»å½</el-button> |
| | | <el-button icon="SwitchButton" @click="logout">éåºç»å½</el-button> |
| | | </el-col> |
| | | </el-row> |
| | | </template> |
| | | |
| | | <script> |
| | | import { useUserStore } from '@/stores/userToken' |
| | | import { useRouter } from 'vue-router'; |
| | | import { ElNotification } from 'element-plus'; |
| | | export default { |
| | | setup() { |
| | | const userStore = useUserStore() |
| | | const router = useRouter() |
| | | return { userStore, router } |
| | | }, |
| | | name: 'CoreHeader', |
| | | props: { |
| | | collapse: { |
| | |
| | | collapsedSider() { |
| | | this.isCollapsed = !this.isCollapsed; |
| | | this.$emit('collapsedSider', this.isCollapsed); |
| | | }, |
| | | logout() { |
| | | this.userStore.logout() |
| | | this.router.push('/common/loginView') |
| | | ElNotification({ |
| | | title: `éåºæå`, |
| | | message: `éåºæå`, |
| | | type: 'success', |
| | | // offset: 170, |
| | | position: 'bottom-left', |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | |
| | | import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router' |
| | | import pinia from '../stores/index' |
| | | import { useLoadingStore } from '../stores/loadingStore' |
| | | |
| | | import { useActiveCheck } from '@/stores/activeCheck'; |
| | | import { useUserStore } from '@/stores/userToken'; |
| | | import loginUtil from '../utils/loginUtil'; |
| | | const routes = [ |
| | | // { |
| | | // //æ´æ¹å®¡æ ¸ |
| | |
| | | name: 'docTest', |
| | | path: '/common/docTest', |
| | | component: () => import('@/views/DocTest.vue') |
| | | }, |
| | | { |
| | | //ç»é |
| | | name: 'loginView', |
| | | path: '/common/loginView', |
| | | component: () => import('@/views/LoginView.vue') |
| | | } |
| | | ] |
| | | ]; |
| | | |
| | | const router = createRouter({ |
| | | // history: createWebHistory(import.meta.env.BASE_URL) |
| | | history: createWebHashHistory(), |
| | | routes: routes |
| | | }) |
| | | }); |
| | | |
| | | const loadingStore = useLoadingStore(pinia) |
| | | const loadingStore = useLoadingStore(pinia); |
| | | const activeCheck = useActiveCheck(pinia); |
| | | const userStore = useUserStore(pinia); |
| | | // eslint-disable-next-line no-unused-vars |
| | | router.afterEach((to, from) => { |
| | | loadingStore.clearLoading() |
| | | }) |
| | | |
| | | export { router, routes } |
| | | loadingStore.clearLoading(); |
| | | }); |
| | | function loginJudge() { |
| | | // å¦ææ¯æªç»å½ å°è¯ä»cookieç»å½ |
| | | if (!userStore.isLoggedIn()) { |
| | | loginUtil.loginFromCookie(); |
| | | } |
| | | // 妿ç»å½è¶
æ¶ è·³è½¬å°ç»å½é¡µé¢ |
| | | if (!activeCheck.isActive()) { |
| | | router.push('/common/loginView'); |
| | | } |
| | | } |
| | | router.beforeEach((to, from) => { |
| | | // æ·»å ç»å½éªè¯ |
| | | if (to.fullPath !== '/common/loginView') { |
| | | loginJudge(); |
| | | } |
| | | }); |
| | | export { router, routes }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import { defineStore } from 'pinia'; |
| | | // ç»å½æ¶é åä½ä¸ºmin |
| | | const maxActiveTime = 15; |
| | | export const useActiveCheck = defineStore('activeCheck', { |
| | | state: () => ({ |
| | | loginTime: null |
| | | }), |
| | | actions: { |
| | | // æ´æ°ç»éæ¶é´ä¸ºå½åæ¶é´ |
| | | updateLoginTime() { |
| | | this.loginTime = new Date(); |
| | | }, |
| | | // 夿ç»éæ¯å¦è¶
æ¶ |
| | | isActive() { |
| | | if (this.loginTime == null) { |
| | | return false; |
| | | } |
| | | const now = new Date(); |
| | | // ææ©çæææ¶é´ |
| | | const earliestActiveTime = now.getTime() - maxActiveTime * 60 * 1000; |
| | | const currLoginTime = this.loginTime.getTime(); |
| | | return currLoginTime > earliestActiveTime; |
| | | }, |
| | | clearLoginTime() { |
| | | this.loginTime = null; |
| | | } |
| | | }, |
| | | getters: {} |
| | | }); |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import loginApi from '@/api/loginApi.js'; |
| | | import loginUtil from '@/utils/loginUtil.js'; |
| | | import pinia from './index'; |
| | | import { defineStore } from 'pinia'; |
| | | import { useActiveCheck } from './activeCheck'; |
| | | export const useUserStore = defineStore('userToken', { |
| | | state: () => ({ |
| | | user: null |
| | | }), |
| | | actions: { |
| | | login({ username, password, user = null }, onSuccess, onError) { |
| | | // éè¿ä¼ é user 对象ç»å½ |
| | | if (user && user != null && user != {}) { |
| | | loginUtil.addUserCookie(user); |
| | | this.user = user; |
| | | const activeCheck = useActiveCheck(pinia); |
| | | activeCheck.updateLoginTime(); |
| | | onSuccess && onSuccess(); |
| | | return; |
| | | } |
| | | // éè¿ä¼ é ç¨æ·åå¯ç ç»å½ |
| | | loginApi |
| | | .login({ username, password }) |
| | | .then((res) => { |
| | | if (res.guid != 'null') { |
| | | loginUtil.addUserCookie(res); |
| | | this.user = res; |
| | | const activeCheck = useActiveCheck(pinia); |
| | | activeCheck.updateLoginTime(); |
| | | onSuccess(); |
| | | } else { |
| | | onError(); |
| | | } |
| | | }) |
| | | .catch((error) => { |
| | | onError(); |
| | | throw error; |
| | | }); |
| | | }, |
| | | logout() { |
| | | this.user = null; |
| | | const activeCheck = useActiveCheck(pinia); |
| | | activeCheck.clearLoginTime(); |
| | | loginUtil.deleteUserCookie(); |
| | | }, |
| | | isLoggedIn() { |
| | | return this.user != null; |
| | | } |
| | | }, |
| | | getters: {} |
| | | }); |
¶Ô±ÈÐÂÎļþ |
| | |
| | | export default { |
| | | |
| | | //读Cookie |
| | | getCookie(objName) { |
| | | //è·åæå®åç§°çcookieçå¼ |
| | | var arrStr = document.cookie.split(';'); |
| | | for (var i = 0; i < arrStr.length; i++) { |
| | | var temp = arrStr[i].split('='); |
| | | if (temp[0].trim() == objName) return unescape(temp[1]); //è§£ç |
| | | } |
| | | return ''; |
| | | }, |
| | | // å é¤ |
| | | deleteCookie(name) { |
| | | document.cookie = name + '=' + '1;expires=Thu, 01 Jan 1970 00:00:00 GMT'; |
| | | } |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import cookieUtil from './cookieUtil'; |
| | | import pinia from '../stores/index'; |
| | | import { useUserStore } from '../stores/userToken'; |
| | | export default { |
| | | // æ·»å cookieä¸ç¨æ·ç»å½ä¿¡æ¯ |
| | | addUserCookie(user) { |
| | | /**æ·»å 设置cookie**/ |
| | | let userObj = 'user=' + escape(JSON.stringify(user)); |
| | | var expires = new Date(); |
| | | expires.setTime(expires.getTime() + 0.5 * 24 * 60 * 60 * 1000); |
| | | //path=/ï¼è¡¨ç¤ºcookieè½å¨æ´ä¸ªç½ç«ä¸ä½¿ç¨ï¼path=/tempï¼è¡¨ç¤ºcookieåªè½å¨tempç®å½ä¸ä½¿ç¨ |
| | | // path = ';path=/html' |
| | | //GMT(Greenwich Mean Time)æ¯æ ¼æå°¼æ²»å¹³æ¶ï¼ç°å¨çæ åæ¶é´ï¼åè°ä¸çæ¶æ¯UTC |
| | | //åæ°daysåªè½æ¯æ°åå |
| | | var _expires = ';expires=' + expires.toGMTString(); |
| | | document.cookie = userObj + _expires; |
| | | }, |
| | | // å é¤cookieä¸ç¨æ·ç»å½ä¿¡æ¯ |
| | | deleteUserCookie() { |
| | | cookieUtil.deleteCookie('user') |
| | | }, |
| | | // ä»cookieç»å½ |
| | | loginFromCookie() { |
| | | const userStore = useUserStore(pinia); |
| | | const userCookie = cookieUtil.getCookie('user'); |
| | | if (userCookie && userCookie != undefined && userCookie != {}) { |
| | | userStore.login({ user: JSON.parse(userCookie) }); |
| | | } |
| | | } |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="container"> |
| | | <div class="header"> |
| | | <h1 class="header-top">çæç¯å¢çº¿ä¸çç®¡å¤§æ°æ®ç®¡çå¹³å°</h1> |
| | | </div> |
| | | <div class="main"> |
| | | <div class="main-login"> |
| | | <div class="width100 main-top-p"><span>ç¨æ·ç»å½</span></div> |
| | | <el-form :model="formObj" :rules="rules" ref="formRef"> |
| | | <el-form-item prop="username"> |
| | | <el-input v-model="formObj.username" placeholder="请è¾å
¥ç¨æ·å" class="user-input"></el-input> |
| | | </el-form-item> |
| | | <el-form-item prop="password"> |
| | | <el-input v-model="formObj.password" placeholder="请è¾å
¥å¯ç " type='password' |
| | | class="user-input"></el-input> |
| | | </el-form-item> |
| | | </el-form> |
| | | <div class="width100 media-footer"> |
| | | <label class="pwd-label"> |
| | | <input type="checkbox" class="check-pwd" />è®°ä½å¯ç |
| | | </label> |
| | | <span class="change-pwd">å¿è®°å¯ç ï¼</span> |
| | | </div> |
| | | <div class="footer width100"> |
| | | <el-button class="login-btn u-loginBtn" @click="onSubmit(false)">ç»å½</el-button> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | <script setup> |
| | | import { useFormConfirm } from '@/composables/formConfirm'; |
| | | import { reactive } from 'vue'; |
| | | import { useRouter } from 'vue-router'; |
| | | import pinia from '@/stores/index'; |
| | | import { useUserStore } from '@/stores/userToken' |
| | | import { ElNotification } from 'element-plus'; |
| | | |
| | | const router = useRouter(); |
| | | const rules = reactive({ |
| | | username: [ |
| | | { |
| | | required: true, |
| | | message: 'ç¨æ·åä¸è½ä¸ºç©º', |
| | | trigger: 'change' |
| | | } |
| | | ], |
| | | password: [ |
| | | { |
| | | required: true, |
| | | message: 'å¯ç ä¸è½ä¸ºç©º', |
| | | trigger: 'change' |
| | | } |
| | | ], |
| | | }) |
| | | const userStore = useUserStore(pinia); |
| | | function login() { |
| | | userStore.login({ username: formObj.value.username, password: formObj.value.password }, () => { |
| | | router.push('/fysp/procheck') |
| | | ElNotification({ |
| | | title: `ç»å½æå`, |
| | | message: `ç»å½æå`, |
| | | type: 'success', |
| | | // offset: 170, |
| | | position: 'bottom-left', |
| | | }); |
| | | }, () => { |
| | | router.push('/common/loginView') |
| | | ElNotification({ |
| | | title: `ç»å½å¤±è´¥`, |
| | | message: `ç¨æ·åæå¯ç é误`, |
| | | type: 'error', |
| | | // offset: 170, |
| | | position: 'bottom-left', |
| | | }); |
| | | }) |
| | | } |
| | | |
| | | //表åæä½å½æ° |
| | | const { formObj, formRef, onSubmit } = |
| | | useFormConfirm({ |
| | | submit: { |
| | | do: login |
| | | } |
| | | }); |
| | | </script> |
| | | <style scoped> |
| | | html { |
| | | font-size: 62.5%; |
| | | } |
| | | |
| | | body { |
| | | margin: 0 !important; |
| | | } |
| | | |
| | | .container { |
| | | width: 100vw; |
| | | height: 100vh; |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: flex-start; |
| | | align-items: center; |
| | | background-image: url(@/assets/image/background_img.jpg); |
| | | } |
| | | |
| | | .header { |
| | | margin-top: 5rem; |
| | | } |
| | | |
| | | .header-top { |
| | | color: #fefffd; |
| | | font-size: 5rem; |
| | | letter-spacing: 0.5rem; |
| | | } |
| | | |
| | | .main { |
| | | width: 30rem; |
| | | height: 29rem; |
| | | opacity: 0.8; |
| | | background-color: #092367; |
| | | background-image: url(@/assets/image/background_main.png); |
| | | background-size: 100%; |
| | | } |
| | | |
| | | .main-top-p { |
| | | text-align: center; |
| | | font-size: 2rem; |
| | | color: white; |
| | | letter-spacing: 0.5rem; |
| | | } |
| | | |
| | | .background-img { |
| | | width: 100%; |
| | | height: 100%; |
| | | |
| | | } |
| | | |
| | | .main-login { |
| | | padding: 5rem; |
| | | padding-bottom: 0.5rem; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | } |
| | | |
| | | .width100 { |
| | | width: 100%; |
| | | margin: 1rem 0; |
| | | } |
| | | |
| | | .media-footer { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | font-size: 1rem; |
| | | margin-top: 3rem; |
| | | } |
| | | |
| | | .pwd-label { |
| | | color: white; |
| | | } |
| | | |
| | | .user-input::-webkit-input-placeholder { |
| | | color: white; |
| | | font-size: 2rem; |
| | | line-height: 2rem; |
| | | } |
| | | |
| | | .user-input { |
| | | /* margin-top: 2rem; */ |
| | | border: 2px solid #046eb0; |
| | | border-radius: 8px; |
| | | width: 100%; |
| | | font-size: 1rem; |
| | | color: white; |
| | | /* padding: 0.8rem 0 0 4rem; */ |
| | | background-color: #03286a; |
| | | |
| | | } |
| | | |
| | | .check-pwd::before { |
| | | border: 1px solid #0270ae; |
| | | background-color: #042866; |
| | | |
| | | } |
| | | |
| | | .change-pwd { |
| | | color: #00aded; |
| | | |
| | | } |
| | | |
| | | .login-btn { |
| | | width: 100%; |
| | | padding: 0.8rem; |
| | | font-size: 1rem; |
| | | border-radius: 9px; |
| | | color: white; |
| | | background-image: url(@/assets/image/login_btn.jpg); |
| | | background-size: 100%; |
| | | opacity: 1; |
| | | border: none; |
| | | /* margin-top: 3rem; */ |
| | | } |
| | | |
| | | .icon-user { |
| | | background-image: url(@/assets/image/user_icon.png); |
| | | |
| | | |
| | | |
| | | background-repeat: no-repeat; |
| | | /*设置å¾çä¸éå¤*/ |
| | | |
| | | height: 100%; |
| | | |
| | | } |
| | | |
| | | .icon-pwd { |
| | | background-image: url(@/assets/image/pwd_icon.png); |
| | | |
| | | background-repeat: no-repeat; |
| | | /*设置å¾çä¸éå¤*/ |
| | | |
| | | height: 80%; |
| | | } |
| | | |
| | | ::v-deep .el-input__inner { |
| | | width: 300px; |
| | | } |
| | | </style> |