From 45792b3776cda2e1ada31755ffc226a663f90b48 Mon Sep 17 00:00:00 2001
From: zouyu <2723363702@qq.com>
Date: 星期三, 19 三月 2025 15:32:23 +0800
Subject: [PATCH] 锁屏功能
---
src/layout/components/lock/index.vue | 121 +++++++++++++
src/permission.js | 10
src/views/login.vue | 6
src/utils/store.js | 103 +++++++++++
src/layout/components/Navbar.vue | 78 ++++----
src/layout/components/top-lock.vue | 73 ++++++++
src/store/getters.js | 2
src/store/modules/app.js | 56 +++++
src/assets/images/lock_bg.png | 0
src/const/website.js | 25 ++
src/router/index.js | 5
src/utils/validate.js | 32 +++
12 files changed, 459 insertions(+), 52 deletions(-)
diff --git a/src/assets/images/lock_bg.png b/src/assets/images/lock_bg.png
new file mode 100644
index 0000000..eb92779
--- /dev/null
+++ b/src/assets/images/lock_bg.png
Binary files differ
diff --git a/src/const/website.js b/src/const/website.js
new file mode 100644
index 0000000..4832ead
--- /dev/null
+++ b/src/const/website.js
@@ -0,0 +1,25 @@
+export default {
+ title: 'ZTTC-LIMS',
+ copyright: 'Copyright 漏 2021 chinaztt.com. All rights reserved.',
+ isFirstPage: true, // 閰嶇疆棣栭〉涓嶅彲鍏抽棴
+ key: 'ztt', // 閰嶇疆涓婚敭,鐩墠鐢ㄤ簬瀛樺偍
+ whiteList: ['/login', '/404', '/401', '/lock'], // 閰嶇疆鏃犳潈闄愬彲浠ヨ闂殑椤甸潰
+ whiteTagList: ['/login', '/404', '/401', '/lock'], // 閰嶇疆涓嶆坊鍔爐ags椤甸潰 锛�'/advanced-router/mutative-detail/*'鈥斺��*涓洪�氶厤绗︼級
+ fistPage: {
+ label: '棣栭〉',
+ value: '/wel/index',
+ params: {},
+ query: {},
+ group: [],
+ close: false
+ },
+ // 閰嶇疆鑿滃崟鐨勫睘鎬�
+ menu: {
+ props: {
+ label: 'label',
+ path: 'path',
+ icon: 'icon',
+ children: 'children'
+ }
+ }
+}
diff --git a/src/layout/components/Navbar.vue b/src/layout/components/Navbar.vue
index 79b01c4..f5f4cb5 100644
--- a/src/layout/components/Navbar.vue
+++ b/src/layout/components/Navbar.vue
@@ -9,8 +9,7 @@
<span class="label">LIMS瀹為獙瀹ょ鐞嗙郴缁�</span>
</div>
<div class="right-menu">
- <div class="avatar-wrapper">
- <!-- <img :src="avatar" class="user-avatar" /> -->
+ <!-- <div class="avatar-wrapper">
<el-avatar :size="28">{{ nickName.substring(0, 1) }}</el-avatar>
<span class="userName">{{ nickName }}</span>
<img
@@ -19,54 +18,51 @@
@click="logout"
title="閫�鍑鸿处鍙�"
/>
- </div>
- <!-- <template v-if="device!=='mobile'">-->
- <!-- <search id="header-search" class="right-menu-item" />-->
+ </div> -->
+ <template v-if="device !== 'mobile'">
+ <el-tooltip
+ class="right-menu-item"
+ effect="dark"
+ content="閿佸睆"
+ placement="bottom"
+ >
+ <top-lock />
+ </el-tooltip>
+ </template>
- <!-- <el-tooltip content="婧愮爜鍦板潃" effect="dark" placement="bottom">-->
- <!-- <ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />-->
- <!-- </el-tooltip>-->
-
- <!-- <el-tooltip content="鏂囨。鍦板潃" effect="dark" placement="bottom">-->
- <!-- <ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />-->
- <!-- </el-tooltip>-->
-
- <!-- <screenfull id="screenfull" class="right-menu-item hover-effect" />-->
-
- <!-- <el-tooltip content="甯冨眬澶у皬" effect="dark" placement="bottom">-->
- <!-- <size-select id="size-select" class="right-menu-item hover-effect" />-->
- <!-- </el-tooltip>-->
-
- <!-- </template>-->
-
- <!-- <div class="avatar-container">-->
- <!-- <el-dropdown-menu slot="dropdown">-->
- <!-- <router-link to="/user/profile">-->
- <!-- <el-dropdown-item>涓汉涓績</el-dropdown-item>-->
- <!-- </router-link>-->
- <!-- <el-dropdown-item @click.native="setting = true">-->
- <!-- <span>甯冨眬璁剧疆</span>-->
- <!-- </el-dropdown-item>-->
- <!-- <el-dropdown-item divided @click.native="logout">-->
- <!-- <span>閫�鍑虹櫥褰�</span>-->
- <!-- </el-dropdown-item>-->
- <!-- </el-dropdown-menu>-->
- <!-- </div>-->
+ <el-dropdown
+ class="avatar-container right-menu-item hover-effect"
+ trigger="click"
+ >
+ <div class="avatar-wrapper">
+ <img :src="avatar" class="user-avatar" />
+ <i class="el-icon-caret-bottom" />
+ </div>
+ <el-dropdown-menu slot="dropdown">
+ <router-link to="/user/profile">
+ <el-dropdown-item>涓汉涓績</el-dropdown-item>
+ </router-link>
+ <el-dropdown-item @click.native="setting = true">
+ <span>甯冨眬璁剧疆</span>
+ </el-dropdown-item>
+ <el-dropdown-item divided @click.native="logout">
+ <span>閫�鍑虹櫥褰�</span>
+ </el-dropdown-item>
+ </el-dropdown-menu>
+ </el-dropdown>
</div>
</div>
</template>
<script>
-import { mapGetters } from "vuex";
+import { mapGetters, mapState } from "vuex";
import Breadcrumb from "@/components/Breadcrumb";
import TopNav from "@/components/TopNav";
import Hamburger from "@/components/Hamburger";
import Screenfull from "@/components/Screenfull";
import SizeSelect from "@/components/SizeSelect";
import Search from "@/components/HeaderSearch";
-import RuoYiGit from "@/components/RuoYi/Git";
-import RuoYiDoc from "@/components/RuoYi/Doc";
-
+import topLock from "./top-lock";
export default {
components: {
Breadcrumb,
@@ -75,10 +71,12 @@
Screenfull,
SizeSelect,
Search,
- RuoYiGit,
- RuoYiDoc,
+ topLock,
},
computed: {
+ ...mapState({
+ showLock: (state) => state.app.showLock,
+ }),
...mapGetters(["avatar", "device", "nickName"]),
setting: {
get() {
diff --git a/src/layout/components/lock/index.vue b/src/layout/components/lock/index.vue
new file mode 100644
index 0000000..9a345fb
--- /dev/null
+++ b/src/layout/components/lock/index.vue
@@ -0,0 +1,121 @@
+<template>
+ <div class="lock-container">
+ <div class="lock-form animated bounceInDown">
+ <div class="animated" :class="{ shake: passwdError, bounceOut: pass }">
+ <h3 class="title">{{ loginUserInfo.nickName }}</h3>
+ <el-input
+ placeholder="璇疯緭鍏ョ櫥褰曞瘑鐮�"
+ type="password"
+ class="input-with-select animated"
+ v-model="passwd"
+ @keyup.enter.native="handleLogin"
+ >
+ <el-button
+ slot="append"
+ icon="el-icon-unlock"
+ @click="handleLogin"
+ ></el-button>
+ <el-button
+ slot="append"
+ icon="el-icon-switch-button"
+ @click="handleLogout"
+ ></el-button>
+ </el-input>
+ </div>
+ </div>
+ </div>
+</template>
+<script>
+import { mapGetters } from "vuex";
+export default {
+ name: "lock",
+ data() {
+ return {
+ passwd: "",
+ passwdError: false,
+ pass: false,
+ };
+ },
+ created() {},
+ mounted() {},
+ computed: {
+ ...mapGetters([
+ "visitedViews",
+ "iframeViews",
+ "cachedViews",
+ "lockPasswd",
+ "loginUserInfo",
+ ]),
+ },
+ props: [],
+ methods: {
+ handleLogout() {
+ this.$confirm("鏄惁閫�鍑虹郴缁�, 鏄惁缁х画?", "鎻愮ず", {
+ confirmButtonText: "纭畾",
+ cancelButtonText: "鍙栨秷",
+ closeOnClickModal: false,
+ type: "warning",
+ }).then(() => {
+ this.$store.dispatch("LogOut").then(() => {
+ this.$router.push({ path: "/login" });
+ });
+ });
+ },
+ handleLogin() {
+ if (this.passwd != this.lockPasswd) {
+ this.passwd = "";
+ this.$message({
+ message: "瑙i攣瀵嗙爜閿欒,璇烽噸鏂拌緭鍏�",
+ type: "error",
+ });
+ this.passwdError = true;
+ setTimeout(() => {
+ this.passwdError = false;
+ }, 1000);
+ return;
+ }
+ this.pass = true;
+ setTimeout(() => {
+ this.$store.dispatch("app/clearLock");
+ //閲嶅畾鍚戣矾鐢辫繕闇�璋冩暣
+ let path =
+ this.visitedViews && this.visitedViews.length > 0
+ ? this.visitedViews.pop().fullPath
+ : "/index";
+ this.$router.push({
+ path: path,
+ });
+ }, 1000);
+ },
+ },
+ components: {},
+};
+</script>
+
+<style lang="scss">
+.lock-container {
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: relative;
+ .title {
+ text-align: center;
+ margin-bottom: 8px;
+ }
+}
+.lock-container::before {
+ z-index: -999;
+ content: "";
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ background-image: url("~@/assets/images/lock_bg.png");
+ background-size: cover;
+}
+.lock-form {
+ width: 300px;
+}
+</style>
diff --git a/src/layout/components/top-lock.vue b/src/layout/components/top-lock.vue
new file mode 100644
index 0000000..90acb03
--- /dev/null
+++ b/src/layout/components/top-lock.vue
@@ -0,0 +1,73 @@
+<template>
+ <span>
+ <i class="fa fa-lock" @click="handleLock"></i>
+ <el-dialog
+ title="璁剧疆閿佸睆瀵嗙爜"
+ :visible.sync="box"
+ width="30%"
+ append-to-body
+ >
+ <el-form :model="form" ref="form" label-width="80px">
+ <el-form-item
+ label="閿佸睆瀵嗙爜"
+ prop="passwd"
+ :rules="[{ required: true, message: '閿佸睆瀵嗙爜涓嶈兘涓虹┖' }]"
+ >
+ <el-input
+ v-model="form.passwd"
+ placeholder="璇疯緭鍏ラ攣灞忓瘑鐮�"
+ ></el-input>
+ </el-form-item>
+ </el-form>
+ <span slot="footer" class="dialog-footer">
+ <el-button type="primary" @click="handleSetLock">纭� 瀹�</el-button>
+ </span>
+ </el-dialog>
+ </span>
+</template>
+
+<script>
+import { validatenull } from "@/utils/validate";
+import { mapGetters } from "vuex";
+export default {
+ name: "top-lock",
+ data() {
+ return {
+ box: false,
+ form: {
+ passwd: "",
+ },
+ };
+ },
+ created() {},
+ mounted() {},
+ computed: {
+ ...mapGetters(["lockPasswd"]),
+ },
+ props: [],
+ methods: {
+ handleSetLock() {
+ this.$refs["form"].validate((valid) => {
+ if (valid) {
+ this.$store.dispatch("app/setLockPasswd", this.form.passwd);
+ // this.$store.commit("SET_LOCK_PASSWD", this.form.passwd);
+ this.handleLock();
+ }
+ });
+ },
+ handleLock() {
+ if (validatenull(this.lockPasswd)) {
+ this.box = true;
+ return;
+ }
+ this.$store.dispatch("app/setLock");
+ setTimeout(() => {
+ this.$router.push({ path: "/lock" });
+ }, 100);
+ },
+ },
+ components: {},
+};
+</script>
+
+<style lang="scss" scoped></style>
diff --git a/src/permission.js b/src/permission.js
index b63bc64..aeb591e 100644
--- a/src/permission.js
+++ b/src/permission.js
@@ -26,7 +26,7 @@
} else if (isWhiteList(to.path)) {
next()
} else {
- if (store.getters.roles.length === 0) {
+ if (store.getters.roles.length === 0) {
isRelogin.show = true
// 鍒ゆ柇褰撳墠鐢ㄦ埛鏄惁宸叉媺鍙栧畬user_info淇℃伅
store.dispatch('GetInfo').then(() => {
@@ -42,8 +42,12 @@
next({ path: '/' })
})
})
- } else {
- next()
+ } else {
+ if (store.getters.isLock && to.path !=='/lock') {
+ next('/lock')
+ } else {
+ next()
+ }
}
}
} else {
diff --git a/src/router/index.js b/src/router/index.js
index 0817afc..a476b13 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -74,6 +74,11 @@
hidden: true,
},
{
+ path: "/lock",
+ component: () => import("@/layout/components/lock/index"),
+ hidden: true,
+ },
+ {
path: "",
component: Layout,
redirect: "index",
diff --git a/src/store/getters.js b/src/store/getters.js
index 099391b..f44d244 100644
--- a/src/store/getters.js
+++ b/src/store/getters.js
@@ -19,5 +19,7 @@
topbarRouters: (state) => state.permission.topbarRouters,
defaultRoutes: (state) => state.permission.defaultRoutes,
sidebarRouters: (state) => state.permission.sidebarRouters,
+ isLock: (state) => state.app.isLock,
+ lockPasswd: (state) => state.app.lockPasswd,
};
export default getters;
diff --git a/src/store/modules/app.js b/src/store/modules/app.js
index 3e22d1c..cdd6139 100644
--- a/src/store/modules/app.js
+++ b/src/store/modules/app.js
@@ -1,5 +1,6 @@
import Cookies from 'js-cookie'
-
+import website from '@/const/website'
+import { getStore, removeStore, setStore } from '@/utils/store'
const state = {
sidebar: {
opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
@@ -7,7 +8,11 @@
hide: false
},
device: 'desktop',
- size: Cookies.get('size') || 'medium'
+ size: Cookies.get('size') || 'medium',
+ lockPasswd: getStore({ name: 'lockPasswd' }) || '',
+ isLock: getStore({ name: 'isLock' }) || false,
+ website: website,
+ showLock: getStore({ name: 'showLock' }),
}
const mutations = {
@@ -37,7 +42,41 @@
},
SET_SIDEBAR_HIDE: (state, status) => {
state.sidebar.hide = status
- }
+ },
+ SET_LOCK_PASSWD: (state, lockPasswd) => {
+ state.lockPasswd = lockPasswd
+ setStore({
+ name: 'lockPasswd',
+ content: state.lockPasswd,
+ type: 'session'
+ })
+ },
+ CLEAR_LOCK: (state) => {
+ state.isLock = false
+ state.lockPasswd = ''
+ removeStore({
+ name: 'lockPasswd'
+ })
+ removeStore({
+ name: 'isLock',
+ type: 'session'
+ })
+ },
+ SET_LOCK: (state) => {
+ state.isLock = true
+ setStore({
+ name: 'isLock',
+ content: state.isLock,
+ type: 'session'
+ })
+ },
+ SET_SHOW_LOCK: (state, active) => {
+ state.showLock = active
+ setStore({
+ name: 'showLock',
+ content: state.showLock
+ })
+ },
}
const actions = {
@@ -55,7 +94,16 @@
},
toggleSideBarHide({ commit }, status) {
commit('SET_SIDEBAR_HIDE', status)
- }
+ },
+ setLockPasswd({ commit }, lockPasswd) {
+ commit('SET_LOCK_PASSWD', lockPasswd)
+ },
+ setLock({ commit }) {
+ commit('SET_LOCK')
+ },
+ clearLock({ commit }) {
+ commit('CLEAR_LOCK')
+ },
}
export default {
diff --git a/src/utils/store.js b/src/utils/store.js
new file mode 100644
index 0000000..c5b6880
--- /dev/null
+++ b/src/utils/store.js
@@ -0,0 +1,103 @@
+import { validatenull } from '@/utils/validate'
+import website from '@/const/website'
+
+const keyName = website.key + '-'
+/**
+ * 瀛樺偍localStorage
+ */
+export const setStore = (params = {}) => {
+ let { name, content, type } = params
+ name = keyName + name
+ const obj = {
+ dataType: typeof content,
+ content: content,
+ type: type,
+ datetime: new Date().getTime()
+ }
+ if (type) window.sessionStorage.setItem(name, JSON.stringify(obj))
+ else window.localStorage.setItem(name, JSON.stringify(obj))
+}
+/**
+ * 鑾峰彇localStorage
+ */
+
+export const getStore = (params = {}) => {
+ let { name, debug } = params
+ name = keyName + name
+ let obj = {}
+ let content
+ obj = window.sessionStorage.getItem(name)
+ if (validatenull(obj)) obj = window.localStorage.getItem(name)
+ if (validatenull(obj)) return
+ try {
+ obj = JSON.parse(obj)
+ } catch (e) {
+ return obj
+ }
+ if (debug) {
+ return obj
+ }
+ if (obj.dataType === 'string') {
+ content = obj.content
+ } else if (obj.dataType === 'number') {
+ content = Number(obj.content)
+ } else if (obj.dataType === 'boolean') {
+ content = eval(obj.content)
+ } else if (obj.dataType === 'object') {
+ content = obj.content
+ }
+ return content
+}
+/**
+ * 鍒犻櫎localStorage
+ */
+export const removeStore = (params = {}) => {
+ let { name, type } = params
+ name = keyName + name
+ if (type) {
+ window.sessionStorage.removeItem(name)
+ } else {
+ window.localStorage.removeItem(name)
+ }
+}
+
+/**
+ * 鑾峰彇鍏ㄩ儴localStorage
+ */
+export const getAllStore = (params = {}) => {
+ const list = []
+ const { type } = params
+ if (type) {
+ for (let i = 0; i <= window.sessionStorage.length; i++) {
+ list.push({
+ name: window.sessionStorage.key(i),
+ content: getStore({
+ name: window.sessionStorage.key(i),
+ type: 'session'
+ })
+ })
+ }
+ } else {
+ for (let i = 0; i <= window.localStorage.length; i++) {
+ list.push({
+ name: window.localStorage.key(i),
+ content: getStore({
+ name: window.localStorage.key(i)
+ })
+ })
+ }
+ }
+ return list
+}
+
+/**
+ * 娓呯┖鍏ㄩ儴localStorage
+ */
+export const clearStore = (params = {}) => {
+ const { type } = params
+ if (type) {
+ window.sessionStorage.clear()
+ } else {
+ window.localStorage.clear()
+ }
+}
diff --git a/src/utils/validate.js b/src/utils/validate.js
index 6a4c0c5..ca8d579 100644
--- a/src/utils/validate.js
+++ b/src/utils/validate.js
@@ -11,7 +11,7 @@
}
/**
- * 鍒ゆ柇value瀛楃涓叉槸鍚︿负绌�
+ * 鍒ゆ柇value瀛楃涓叉槸鍚︿负绌�
* @param {string} value
* @returns {Boolean}
*/
@@ -23,7 +23,7 @@
}
/**
- * 鍒ゆ柇url鏄惁鏄痟ttp鎴杊ttps
+ * 鍒ゆ柇url鏄惁鏄痟ttp鎴杊ttps
* @param {string} url
* @returns {Boolean}
*/
@@ -112,3 +112,31 @@
}
return Array.isArray(arg)
}
+
+/**
+ * 鍒ゆ柇鏄惁涓虹┖
+ */
+export function validatenull(val) {
+ if (typeof val === 'boolean') {
+ return false
+ }
+ if (typeof val === 'number') {
+ return false
+ }
+ if (val instanceof Array) {
+ if (val.length === 0) return true
+ } else if (val instanceof Object) {
+ if (JSON.stringify(val) === '{}') return true
+ } else {
+ if (
+ val === 'null' ||
+ val == null ||
+ val === 'undefined' ||
+ val === undefined ||
+ val === ''
+ )
+ return true
+ return false
+ }
+ return false
+}
diff --git a/src/views/login.vue b/src/views/login.vue
index a67d503..1656428 100644
--- a/src/views/login.vue
+++ b/src/views/login.vue
@@ -41,7 +41,7 @@
/>
</el-input>
</el-form-item>
- <el-form-item prop="code" v-if="captchaEnabled">
+ <!-- <el-form-item prop="code" v-if="captchaEnabled">
<el-input
v-model="loginForm.code"
auto-complete="off"
@@ -58,7 +58,7 @@
<div class="login-code">
<img :src="codeUrl" @click="getCode" class="login-code-img" />
</div>
- </el-form-item>
+ </el-form-item> -->
<el-checkbox
v-model="loginForm.rememberMe"
style="margin: 0px 0px 25px 0px"
@@ -121,7 +121,7 @@
},
loading: false,
// 楠岃瘉鐮佸紑鍏�
- captchaEnabled: true,
+ captchaEnabled: false,
// 娉ㄥ唽寮�鍏�
register: false,
redirect: undefined,
--
Gitblit v1.9.3