Quellcode durchsuchen

新增锁定屏幕功能

RuoYi vor 4 Jahren
Ursprung
Commit
fb480530c8

+ 35 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java

@@ -9,8 +9,12 @@ import org.springframework.stereotype.Controller;
 import org.springframework.ui.ModelMap;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
 import com.ruoyi.common.config.RuoYiConfig;
+import com.ruoyi.common.constant.ShiroConstants;
 import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.core.domain.entity.SysMenu;
 import com.ruoyi.common.core.domain.entity.SysUser;
 import com.ruoyi.common.core.text.Convert;
@@ -19,6 +23,7 @@ import com.ruoyi.common.utils.DateUtils;
 import com.ruoyi.common.utils.ServletUtils;
 import com.ruoyi.common.utils.ShiroUtils;
 import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.framework.shiro.service.SysPasswordService;
 import com.ruoyi.system.service.ISysConfigService;
 import com.ruoyi.system.service.ISysMenuService;
 
@@ -36,6 +41,9 @@ public class SysIndexController extends BaseController
     @Autowired
     private ISysConfigService configService;
 
+    @Autowired
+    private SysPasswordService passwordService;
+
     // 系统首页
     @GetMapping("/index")
     public String index(ModelMap mmap)
@@ -73,6 +81,33 @@ public class SysIndexController extends BaseController
         return webIndex;
     }
 
+    // 锁定屏幕
+    @GetMapping("/lockscreen")
+    public String lockscreen(ModelMap mmap)
+    {
+        mmap.put("user", ShiroUtils.getSysUser());
+        ServletUtils.getSession().setAttribute(ShiroConstants.LOCK_SCREEN, true);
+        return "lock";
+    }
+
+    // 解锁屏幕
+    @PostMapping("/unlockscreen")
+    @ResponseBody
+    public AjaxResult unlockscreen(String password)
+    {
+        SysUser user = ShiroUtils.getSysUser();
+        if (StringUtils.isNull(user))
+        {
+            return AjaxResult.error("服务器超时,请重新登陆");
+        }
+        if (passwordService.matches(user, password))
+        {
+            ServletUtils.getSession().removeAttribute(ShiroConstants.LOCK_SCREEN);
+            return AjaxResult.success();
+        }
+        return AjaxResult.error("密码不正确,请重新输入。");
+    }
+
     // 切换主题
     @GetMapping("/system/switchSkin")
     public String switchSkin()

Datei-Diff unterdrückt, da er zu groß ist
+ 305 - 0
ruoyi-admin/src/main/resources/static/js/three.min.js


+ 5 - 0
ruoyi-admin/src/main/resources/static/ruoyi/index.js

@@ -480,6 +480,11 @@ $(function() {
     $('#fullScreen').on('click', function () {
     	$(document).toggleFullScreen();
     });
+    
+    // 锁定屏幕
+    $('#lockScreen').on('click', function () {
+    	location.href  = ctx + "lockscreen";
+    });
 
     // 页签刷新按钮
     $('.tabReload').on('click', refreshTab);

+ 1 - 1
ruoyi-admin/src/main/resources/templates/include.html

@@ -18,6 +18,7 @@
 
 <!-- 通用JS -->
 <div th:fragment="footer">
+    <script th:inline="javascript"> var ctx = [[@{/}]]; var lockscreen = [[${session.lockscreen}]]; if(lockscreen){window.top.location=ctx+"lockscreen";} </script>
     <a id="scroll-up" href="#" class="btn btn-sm display"><i class="fa fa-angle-double-up"></i></a>
 	<script th:src="@{/js/jquery.min.js}"></script>
 	<script th:src="@{/js/bootstrap.min.js}"></script>
@@ -38,7 +39,6 @@
 	<script th:src="@{/ajax/libs/layui/layui.js}"></script>
 	<script th:src="@{/ruoyi/js/common.js?v=4.5.1}"></script>
 	<script th:src="@{/ruoyi/js/ry-ui.js?v=4.5.1}"></script>
-	<script th:inline="javascript"> var ctx = [[@{/}]]; </script>
 </div>
 
 <!-- ztree树插件 -->

+ 10 - 4
ruoyi-admin/src/main/resources/templates/index-topnav.html

@@ -234,9 +234,10 @@
 				</div>
                 <!-- 右侧栏 -->
                 <ul class="nav navbar-top-links navbar-right welcome-message">
-                    <li><a title="视频教程" href="http://doc.ruoyi.vip/ruoyi/document/spjc.html" target="_blank"><i class="fa fa-video-camera"></i> 视频教程</a></li>
-                    <li><a title="开发文档" href="http://doc.ruoyi.vip" target="_blank"><i class="fa fa-question-circle"></i> 开发文档</a></li>
-	                <li><a title="全屏显示" href="javascript:void(0)" id="fullScreen"><i class="fa fa-arrows-alt"></i> 全屏显示</a></li>
+                    <li><a data-toggle="tooltip" data-trigger="hover" data-placement="bottom" title="开发文档" href="http://doc.ruoyi.vip/ruoyi" target="_blank"><i class="fa fa-question-circle"></i> 文档</a></li>
+                    <li><a data-toggle="tooltip" data-trigger="hover" data-placement="bottom" title="锁定屏幕" href="#" id="lockScreen"><i class="fa fa-lock"></i> 锁屏</a></li>
+	                <li><a data-toggle="tooltip" data-trigger="hover" data-placement="bottom" title="全屏显示" href="#" id="fullScreen"><i class="fa fa-arrows-alt"></i> 全屏</a></li>
+                
                     <li class="dropdown user-menu">
 						<a href="javascript:void(0)" class="dropdown-toggle" data-hover="dropdown">
 							<img th:src="(${#strings.isEmpty(user.avatar)}) ? @{/img/profile.jpg} : @{${user.avatar}}" th:onerror="this.src='img/profile.jpg'" class="user-image">
@@ -311,7 +312,10 @@
 <script th:src="@{/ajax/libs/fullscreen/jquery.fullscreen.js}"></script>
 <script th:src="@{/js/resize-tabs.js}"></script>
 <script th:inline="javascript">
-var ctx = [[@{/}]];
+window.history.forward(1);
+var ctx = [[@{/}]]; 
+var lockscreen = [[${session.lockscreen}]]; 
+if(lockscreen){window.top.location=ctx+"lockscreen";}
 // 皮肤缓存
 var skin = storage.get("skin");
 // history(表示去掉地址的#)否则地址以"#"形式展示
@@ -417,6 +421,8 @@ $(function() {
 			layer.close(index);
 		});
 	}
+	
+	$("[data-toggle='tooltip']").tooltip();
 });
 </script>
 </body>

+ 8 - 4
ruoyi-admin/src/main/resources/templates/index.html

@@ -185,9 +185,9 @@
                     </a>
                 </div>
                 <ul class="nav navbar-top-links navbar-right welcome-message">
-                    <li><a title="视频教程" href="http://doc.ruoyi.vip/ruoyi/document/spjc.html" target="_blank"><i class="fa fa-video-camera"></i> 视频教程</a></li>
-                    <li><a title="开发文档" href="http://doc.ruoyi.vip" target="_blank"><i class="fa fa-question-circle"></i> 开发文档</a></li>
-	                <li><a title="全屏显示" href="javascript:void(0)" id="fullScreen"><i class="fa fa-arrows-alt"></i> 全屏显示</a></li>
+                    <li><a data-toggle="tooltip" data-trigger="hover" data-placement="bottom" title="开发文档" href="http://doc.ruoyi.vip/ruoyi" target="_blank"><i class="fa fa-question-circle"></i> 文档</a></li>
+                    <li><a data-toggle="tooltip" data-trigger="hover" data-placement="bottom" title="锁定屏幕" href="#" id="lockScreen"><i class="fa fa-lock"></i> 锁屏</a></li>
+	                <li><a data-toggle="tooltip" data-trigger="hover" data-placement="bottom" title="全屏显示" href="#" id="fullScreen"><i class="fa fa-arrows-alt"></i> 全屏</a></li>
                     <li class="dropdown user-menu">
 						<a href="javascript:void(0)" class="dropdown-toggle" data-hover="dropdown">
 							<img th:src="(${#strings.isEmpty(user.avatar)}) ? @{/img/profile.jpg} : @{${user.avatar}}" th:onerror="this.src='img/profile.jpg'" class="user-image">
@@ -261,7 +261,10 @@
 <script th:src="@{/ruoyi/index.js}"></script>
 <script th:src="@{/ajax/libs/fullscreen/jquery.fullscreen.js}"></script>
 <script th:inline="javascript">
-var ctx = [[@{/}]];
+window.history.forward(1);
+var ctx = [[@{/}]]; 
+var lockscreen = [[${session.lockscreen}]]; 
+if(lockscreen){window.top.location=ctx+"lockscreen";}
 // 皮肤缓存
 var skin = storage.get("skin");
 // history(表示去掉地址的#)否则地址以"#"形式展示
@@ -357,6 +360,7 @@ $(function() {
 			layer.close(index);
 		});
 	}
+	$("[data-toggle='tooltip']").tooltip();
 });
 </script>
 </body>

+ 208 - 0
ruoyi-admin/src/main/resources/templates/lock.html

@@ -0,0 +1,208 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org">
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <!--360浏览器优先以webkit内核解析-->
+    <title>锁定屏幕</title>
+    <link th:href="@{favicon.ico}" rel="shortcut icon"/>
+    <link href="../static/css/bootstrap.min.css" th:href="@{/css/bootstrap.min.css}" rel="stylesheet"/>
+    <link href="../static/css/font-awesome.min.css" th:href="@{/css/font-awesome.min.css}" rel="stylesheet"/>
+	<style>.lockscreen{background:#d2d6de;height:auto;}.lockscreen .lockscreen-name{text-align:center;font-weight:600;margin-top:50px;margin-bottom:30px;}.lockscreen-wrapper{max-width:400px;margin:10% auto;z-index:800;position:relative;}.lockscreen .lockscreen-name{text-align:center;font-weight:600;margin-top:50px;margin-bottom:30px;}.lockscreen-item{border-radius:4px;padding:0;background:#fff;position:relative;margin:10px auto 30px auto;width:290px}.lockscreen-image{border-radius:50%;position:absolute;left:-10px;top:-25px;background:#fff;padding:5px;z-index:10}.lockscreen-image>img{border-radius:50%;width:70px;height:70px}.lockscreen-credentials{margin-left:70px}.lockscreen-credentials .form-control{border:0}.lockscreen-credentials .btn{background-color:#fff;border:0;padding:0 10px}.lockscreen-footer{margin-top:150px}.lockscreen-time{width:100%;color:#fff;font-size:60px;display:inline-block;text-align:center;font-family:'Open Sans',sans-serif;font-weight:300;}</style>
+</head>
+<body class="lockscreen">
+<div class="lockscreen-wrapper">
+    <div class="lockscreen-time"></div>
+    <div class="lockscreen-name">[[ ${user.loginName} ]] / [[${#strings.defaultString(user.userName, '-')}]]</div>
+
+    <div class="lockscreen-item">
+        <div class="lockscreen-image">
+            <img th:src="(${#strings.isEmpty(user.avatar)}) ? @{/img/profile.jpg} : @{${user.avatar}}" th:onerror="this.src='img/profile.jpg'" class="img-circle" alt="User Image">
+        </div>
+        <form class="lockscreen-credentials" method="post" action="#" onsubmit="return false;">
+            <div class="input-group">
+                <input type="password" name="password" autocomplete="off" class="form-control" placeholder="密码">
+                <div class="input-group-btn">
+                    <button type="button" class="btn" onclick="unlock()"><i class="fa fa-arrow-right text-muted"></i></button>
+                </div>
+            </div>
+        </form>
+    </div>
+    
+    <div class="help-block text-center" style="margin-top: 50px;">系统锁屏,请输入密码登陆!</div>
+    <div class="text-center">
+        <a th:href="@{logout}">退出重新登陆</a>
+    </div>
+</div>
+<script src="../static/js/jquery.min.js" th:src="@{/js/jquery.min.js}"></script>
+<script src="../static/js/bootstrap.min.js" th:src="@{/js/bootstrap.min.js}"></script>
+<script src="../static/js/three.min.js" th:src="@{/js/three.min.js}"></script>
+<script src="../static/ajax/libs/layer/layer.min.js" th:src="@{/ajax/libs/layer/layer.min.js}"></script>
+<script src="../static/ruoyi/js/ry-ui.js" th:src="@{/ruoyi/js/ry-ui.js?v=4.5.1}"></script>
+</body>
+<script th:inline="javascript">
+    var ctx = [[@{/}]];
+    Date.prototype.format = function(fmt) {
+	  var o = {
+	    "M+" : this.getMonth()+1,                 //月份
+	    "d+" : this.getDate(),                    //日
+	    "h+" : this.getHours(),                   //小时
+	    "m+" : this.getMinutes(),                 //分
+	    "s+" : this.getSeconds(),                 //秒
+	    "q+" : Math.floor((this.getMonth()+3)/3), //季度
+	    "S"  : this.getMilliseconds()             //毫秒
+	  };
+
+	  if (/(y+)/.test(fmt)) {
+          fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
+	  }
+
+	  for (var k in o) {
+		  if (new RegExp("(" + k + ")").test(fmt)) {
+		      fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
+		  }
+      }
+	  return fmt;
+	}
+    
+    $(function() {
+        $('.lockscreen-time').text((new Date()).format('hh:mm:ss'));
+        setInterval(function() {
+            $('.lockscreen-time').text((new Date()).format('hh:mm:ss'));
+        }, 500);
+        init();
+        animate();
+    });
+
+    $(document).keydown(function(event) {
+   	    if (event.keyCode == 13) {
+   	    	unlock();
+   	    }
+   	});
+     
+    function unlock() {
+        var username = $("input[name='username']").val();
+        var password = $("input[name='password']").val();
+        if ($.common.isEmpty(password)) {
+        	$.modal.msg("请输入密码");
+            return;
+        }
+        
+        var index = "";
+        var config = {
+            url: ctx + "unlockscreen",
+            type: "post",
+            dataType: "json",
+            data: { password: password },
+            beforeSend: function() {
+            	index = layer.load(2, {shade: false});
+            },
+            success: function(result) {
+                if (result.code == web_status.SUCCESS) {
+                    location.href = ctx + 'index';
+                } else {
+                    $.modal.msg(result.msg);
+                    $("input[name='password']").val("");
+                }
+                layer.close(index);
+            }
+        };
+        $.ajax(config);
+    };
+
+    var container;
+    var camera, scene, projector, renderer;
+    var PI2 = Math.PI * 2;
+
+    var programFill = function(context) {
+        context.beginPath();
+        context.arc(0, 0, 1, 0, PI2, true);
+        context.closePath();
+        context.fill();
+    };
+
+    var programStroke = function(context) {
+        context.lineWidth = 0.05;
+        context.beginPath();
+        context.arc(0, 0, 1, 0, PI2, true);
+        context.closePath();
+        context.stroke();
+    };
+
+    var mouse = { x: 0, y: 0 }, INTERSECTED;
+    function init() {
+    	container = document.createElement('div');
+    	container.id = 'bgc';
+    	container.style.position = 'absolute';
+    	container.style.zIndex = '0';
+    	container.style.top = '0px';
+    	$(".lockscreen-wrapper").before(container);
+
+        camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 10000);
+        camera.position.set(0, 300, 500);
+        scene = new THREE.Scene();
+
+        for (var i = 0; i < 100; i++) {
+            var particle = new THREE.Particle(new THREE.ParticleCanvasMaterial({ color: Math.random() * 0x808080 + 0x808080, program: programStroke }));
+            particle.position.x = Math.random() * 800 - 400;
+            particle.position.y = Math.random() * 800 - 400;
+            particle.position.z = Math.random() * 800 - 400;
+            particle.scale.x = particle.scale.y = Math.random() * 10 + 10;
+            scene.add(particle);
+        }
+        projector = new THREE.Projector();
+        renderer = new THREE.CanvasRenderer();
+        renderer.setSize(window.innerWidth, window.innerHeight - 10);
+        container.appendChild(renderer.domElement);
+        document.addEventListener('mousemove', onDocumentMouseMove, false);
+        window.addEventListener('resize', onWindowResize, false);
+    };
+
+    function onWindowResize() {
+        camera.aspect = window.innerWidth / window.innerHeight;
+        camera.updateProjectionMatrix();
+        renderer.setSize(window.innerWidth, window.innerHeight - 10);
+    };
+
+    function onDocumentMouseMove(event) {
+        event.preventDefault();
+        mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
+        mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
+    };
+
+    function animate() {
+        requestAnimationFrame(animate);
+        render();
+    };
+
+    var radius = 600;
+    var theta = 0;
+
+    function render() {
+    	theta += 0.2;
+    	camera.position.x = radius * Math.sin(theta * Math.PI / 360);
+    	camera.position.y = radius * Math.sin(theta * Math.PI / 360);
+    	camera.position.z = radius * Math.cos(theta * Math.PI / 360);
+    	camera.lookAt(scene.position);
+    	camera.updateMatrixWorld();
+
+    	var vector = new THREE.Vector3(mouse.x, mouse.y, 0.5);
+    	projector.unprojectVector(vector, camera);
+
+    	var ray = new THREE.Ray(camera.position, vector.subSelf(camera.position).normalize());
+    	var intersects = ray.intersectObjects(scene.children);
+
+        if (intersects.length > 0) {
+            if (INTERSECTED != intersects[0].object) {
+                if (INTERSECTED) INTERSECTED.material.program = programStroke;
+                INTERSECTED = intersects[0].object;
+                INTERSECTED.material.program = programFill;
+            }
+        } else {
+            if (INTERSECTED) INTERSECTED.material.program = programStroke;
+            INTERSECTED = null;
+        }
+        renderer.render(scene, camera);
+    }
+</script>
+</html>

+ 6 - 1
ruoyi-common/src/main/java/com/ruoyi/common/constant/ShiroConstants.java

@@ -13,10 +13,15 @@ public class ShiroConstants
     public static final String CURRENT_USER = "currentUser";
 
     /**
-     * 用户名
+     * 用户名字段
      */
     public static final String CURRENT_USERNAME = "username";
 
+    /**
+     * 锁定屏幕字段
+     */
+    public static final String LOCK_SCREEN = "lockscreen";
+
     /**
      * 消息key
      */

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.