GZMachinesWeb/WebContent/WEB-INF/views/login/login.jsp

1132 lines
38 KiB
Plaintext
Raw Normal View History

2025-06-20 17:47:53 +08:00
<%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<title>贵送机具管理系统</title>
<c:set var="bonuspath" value="${pageContext.request.contextPath}" />
<script>
var bonuspath = '${bonuspath}';
</script>
<!DOCTYPE html>
<html lang="zh-CN">
2025-06-20 17:47:53 +08:00
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no,maximum-scale=1.0,minimum-scale=1.0">
<title>贵送机具管理系统 - 登录</title>
2025-06-20 17:47:53 +08:00
<%
String uuid = UUID.randomUUID().toString().replaceAll("-", "");
request.getSession().setAttribute("randTxt", uuid);
String sessionId = request.getSession().getId();
response.setHeader("SET-COOKIE", "JSESSIONID="+sessionId+";secure;HttpOnly");
%>
<!-- CSS Resources -->
2025-06-20 17:47:53 +08:00
<link rel="icon" href="${bonuspath}/favicon.ico" type="image/x-icon" />
<link rel="shortcut icon" href="${bonuspath}/favicon.ico" type="image/x-icon" />
2025-06-20 17:47:53 +08:00
<link rel="bookmark" href="${bonuspath}/favicon.ico" type="image/x-icon" />
<link rel="stylesheet" href="${bonuspath}/static/css/bootstrap/bootstrap1.min.css" />
<link href="${bonuspath}/static/css/sys/images/iconfont/style.css" type="text/css" rel="stylesheet">
<link rel="stylesheet" href="${bonuspath}/static/css/jquery/jquery-ui.css" />
<link rel="stylesheet" href="${bonuspath}/static/js/layui/css/layui.css" />
<!-- JavaScript Resources -->
<script src="${bonuspath}/static/js/jquery/jquery-3.6.1.js"></script>
<script type="text/javascript" src="${bonuspath}/static/js/jquery/jquery.tips.js"></script>
2025-06-20 17:47:53 +08:00
<script src="${bonuspath}/static/js/jquery/jquery-ui.min.js"></script>
<script src="${bonuspath}/static/js/jquery/jquery.md5.js"></script>
2025-06-20 17:47:53 +08:00
<script src="${bonuspath}/static/js/layui/layui.js"></script>
<script src="${bonuspath}/static/plugins/layer/2.1/layer.js"></script>
<script type="text/javascript" src="${bonuspath}/static/js/sys/login.js"></script>
2025-06-20 17:47:53 +08:00
<script>
// 显示用户协议
function showAgreement() {
layui.use('layer', function(){
var layer = layui.layer;
layer.open({
type: 1,
title: '用户协议',
area: ['90%', '90%'],
maxWidth: '900px',
maxHeight: '700px',
2025-06-20 17:47:53 +08:00
shadeClose: false,
scrollbar: true,
content: $('#agreementContent').html(),
success: function(layero, index){
console.log('弹窗加载成功');
},
error: function(err){
console.error('弹窗加载失败:', err);
}
});
});
}
</script>
<!-- 用户协议内容模板 -->
<script type="text/html" id="agreementContent">
<div style="padding: 20px; height: 500px; overflow-y: auto; background-color: #fff;">
<h3 style="text-align: center; margin-bottom: 20px; color: #333; font-size: 18px;">用户协议</h3>
<p style="text-align: right; color: #666; margin-bottom: 20px;">本协议更新时间【2024】年【12】月【17】日</p>
<div style="color: #333; line-height: 1.6;">
<h4 style="color: #333; font-size: 16px; margin: 15px 0;">一、引言</h4>
<p style="margin-bottom: 10px;">鉴于个人信息和隐私保护的重要性,以及我们对您个人信息和隐私的尊重,我们制定了本《个人信息和隐私保护协议》(以下简称"本协议")。本协议旨在明确我们对您个人信息和隐私的收集、使用、存储、传输和删除等方面的规定,以确保您的个人信息和隐私得到妥善保护。</p>
<h4 style="color: #333; font-size: 16px; margin: 15px 0;">二、协议适用说明</h4>
<p style="margin-bottom: 10px;">1. 个人信息:指能够单独或与其他信息结合后识别特定自然人身份的信息,包括但不限于姓名、性别、出生日期、身份证号、联系方式、家庭住址等。</p>
<p style="margin-bottom: 10px;">2. 隐私安全:指个人在特定社会关系中,享有私人生活,不愿公开的个人信息和私人事务。</p>
<p style="margin-bottom: 10px;">3. 适用范围:本协议适用于我们对您个人信息和隐私的保护,包括我们收集、使用、存储、传输和删除您的个人信息和隐私。</p>
<h4 style="color: #333; font-size: 16px; margin: 15px 0;">三、信息收集</h4>
<p style="margin-bottom: 10px;">1. 合法性原则:我们将遵循合法性原则,仅在您同意或法律允许的情况下收集您的个人信息和隐私。</p>
<p style="margin-bottom: 10px;">2. 必要性原则:我们将遵循必要性原则,仅收集与实现我们的服务目的直接相关的信息。</p>
<p style="margin-bottom: 10px;">3. 透明性原则:我们将遵循透明性原则,向您公开我们收集的个人信息和隐私的种类、目的和使用方式。</p>
<h4 style="color: #333; font-size: 16px; margin: 15px 0;">四、信息使用</h4>
<p style="margin-bottom: 10px;">1. 合法使用:我们将仅在法律允许或您同意的情况下使用您的个人信息和隐私。</p>
<p style="margin-bottom: 10px;">2. 正当使用:我们将遵循正当使用原则,确保使用您的个人信息和隐私是为了实现我们的服务目的,并且不会损害您的合法权益。</p>
<p style="margin-bottom: 10px;">3. 透明使用:我们将遵循透明使用原则,向您公开我们使用您的个人信息和隐私的具体情况。</p>
<h4 style="color: #333; font-size: 16px; margin: 15px 0;">五、信息存储与传输</h4>
<p style="margin-bottom: 10px;">1. 安全存储:我们将采取必要的技术和组织措施,确保您的个人信息和隐私得到安全存储。</p>
<p style="margin-bottom: 10px;">2. 加密传输:我们将对您的个人信息和隐私进行加密传输,以确保数据传输过程中的安全性。</p>
<p style="margin-bottom: 10px;">3. 访问控制:我们将严格控制对您的个人信息和隐私的访问权限,确保只有授权人员才能访问相关信息。</p>
<p style="margin-bottom: 10px;">4. 定期审计:为您提供安全保障,个人信息处理者应当定期对其处理个人信息遵守法律、行政法规的情况进行合规审计。</p>
<h4 style="color: #333; font-size: 16px; margin: 15px 0;">六、信息删除与注销</h4>
<p style="margin-bottom: 10px;">1. 删除原则:我们将遵循删除原则,确保在达到收集目的后或您要求删除时,及时删除您的个人信息和隐私。</p>
<p style="margin-bottom: 10px;">2. 注销权利:您有权要求我们注销您的个人信息和隐私,我们将在收到您的请求后尽快处理。</p>
<p style="margin-bottom: 10px;">3. 在不幸发生个人信息安全事件后,我们将按照法律法规的要求向您告知:安全事件的基本情况和可能的影响、我们已采取或将要采取的处置措施、您可自主防范和降低风险的建议、对您的补救措施等。</p>
<h4 style="color: #333; font-size: 16px; margin: 15px 0;">七、违约责任</h4>
<p style="margin-bottom: 10px;">1. 违反本协议规定的,我们将依法承担相应的法律责任。</p>
<p style="margin-bottom: 10px;">2. 您违反本协议规定的,我们将有权依法追究您的法律责任。</p>
<h4 style="color: #333; font-size: 16px; margin: 15px 0;">八、如何保护你的信息</h4>
<p style="margin-bottom: 10px;">(一)我们已采取符合业界标准、合理可行的安全防护措施保护您的信息,防止个人信息遭到未经授权访问、公开披露、使用、修改、损坏或丢失。</p>
<p style="margin-bottom: 10px;">(二)我们有行业先进的以数据为核心,围绕数据生命周期进行的数据安全管理体系,从组织建设、制度设计、人员管理、产品技术等方面多维度提升整个系统的安全性。</p>
<p style="margin-bottom: 10px;">(三)我们会采取合理可行的措施,尽力避免收集无关的个人信息。</p>
<p style="margin-bottom: 10px;">(四)互联网并非绝对安全的环境,使用服务时,我们强烈建议通过安全方式、使用复杂密码,协助我们保证您的账号安全。</p>
<p style="margin-bottom: 10px;">(五)在不幸发生个人信息安全事件后,我们将按照法律法规的要求及时告知您。</p>
<h4 style="color: #333; font-size: 16px; margin: 15px 0;">九、我们如何更新本政策</h4>
<p style="margin-bottom: 10px;">1. 为给您提供更好的服务,本应用的产品与服务将不时更新与变化,我们会适时对本协议进行修订。</p>
<p style="margin-bottom: 10px;">2. 本协议更新后,我们会在本应用中发出更新版本,并以弹窗的方式提醒您。</p>
<p style="margin-bottom: 10px;">3. 对于重大变更,我们还会提供更为显著的通知。</p>
<h4 style="color: #333; font-size: 16px; margin: 15px 0;">十、我们如何委托处理、共享、转让、公开披露您的个人信息</h4>
<p style="margin-bottom: 10px;">1. 委托处理:为了向您提供更完善、更优质的产品和服务,我们可能会委托合作方处理您的某些个人信息。</p>
<p style="margin-bottom: 10px;">2. 共享:在本应用进行用户注册时,您的账号注册信息会在相关政务服务系统间共享。</p>
<h4 style="color: #333; font-size: 16px; margin: 15px 0;">十一、其他条款</h4>
<p style="margin-bottom: 10px;">1. 本协议自双方签字或盖章之日起生效。</p>
<p style="margin-bottom: 10px;">2. 本协议一式两份,双方各执一份。</p>
<p style="margin-bottom: 10px;">3. 本协议未尽事宜,由双方另行协商确定。如有任何疑问或需要进一步了解,请随时联系我们。</p>
</div>
</div>
</script>
2025-06-20 17:47:53 +08:00
<style>
/* Reset and base styles */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
2025-06-20 17:47:53 +08:00
}
html, body {
height: 100%;
font-family: "Microsoft YaHei", "微软雅黑", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
line-height: 1.6;
color: #333;
overflow-x: hidden;
}
/* 南网蓝色系配色变量 */
:root {
--nangwang-blue: #007aa5;
--nangwang-blue-light: #0089b9;
--nangwang-blue-lighter: #00a0d8;
--nangwang-blue-dark: #006b91;
--nangwang-blue-darker: #005d7e;
--nangwang-blue-gradient: linear-gradient(135deg, #007aa5 0%, #00a0d8 100%);
--nangwang-blue-shadow: rgba(0, 122, 165, 0.3);
--nangwang-blue-shadow-light: rgba(0, 122, 165, 0.1);
}
/* Background and layout */
2025-06-20 17:47:53 +08:00
body {
background: var(--nangwang-blue-gradient);
background-attachment: fixed;
background-size: cover;
position: relative;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
body::before {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: url('${bonuspath}/static/css/sys/images/login/bg.png') no-repeat center center;
background-size: cover;
opacity: 0.1;
z-index: -1;
}
/* Main container */
.login-container {
width: 100%;
max-width: 420px;
margin: 20px;
perspective: 1000px;
}
.login-card {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
border-radius: 20px;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
overflow: hidden;
transform-style: preserve-3d;
transition: all 0.3s ease;
}
.login-card:hover {
transform: translateY(-5px);
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.15);
}
/* Header section */
.login-header {
background: var(--nangwang-blue-gradient);
padding: 30px 20px;
text-align: center;
position: relative;
overflow: hidden;
}
.login-header::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 70%);
animation: rotate 20s linear infinite;
}
@keyframes rotate {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.logo-container {
position: relative;
z-index: 2;
}
.logo-container img {
max-width: 120px;
height: auto;
filter: brightness(1.2);
transition: transform 0.3s ease;
}
.logo-container img:hover {
transform: scale(1.05);
}
.system-title {
color: white;
font-size: 18px;
font-weight: 500;
margin-top: 10px;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
letter-spacing: 1px;
}
/* Form section */
.login-form {
padding: 40px 30px 30px;
background: white;
2025-06-20 17:47:53 +08:00
}
.form-group {
position: relative;
margin-bottom: 25px;
}
.input-container {
position: relative;
display: flex;
align-items: center;
}
.input-icon {
position: absolute;
left: 15px;
font-size: 18px;
color: var(--nangwang-blue);
z-index: 2;
transition: color 0.3s ease;
}
.form-input {
width: 100%;
height: 50px;
padding: 0 15px 0 45px;
border: 2px solid #e1e5e9;
border-radius: 12px;
font-size: 16px;
background: #f8f9fa;
transition: all 0.3s ease;
outline: none;
}
.form-input:focus {
border-color: var(--nangwang-blue);
background: white;
box-shadow: 0 0 0 3px var(--nangwang-blue-shadow-light);
transform: translateY(-1px);
}
.form-input:focus + .input-icon {
color: var(--nangwang-blue-light);
}
.form-input::placeholder {
color: #a0a0a0;
transition: color 0.3s ease;
}
.form-input:focus::placeholder {
color: #c0c0c0;
}
/* Error messages */
.error-message {
position: absolute;
bottom: -20px;
left: 0;
color: #e74c3c;
font-size: 12px;
opacity: 0;
transition: opacity 0.3s ease;
}
.error-message.show {
opacity: 1;
}
/* 记住密码选项区域 */
.remember-section {
display: flex;
justify-content: space-between;
align-items: center;
margin: 15px 0 20px;
font-size: 14px;
}
.remember-label {
display: inline-flex;
align-items: center;
cursor: pointer;
color: #666;
transition: color 0.3s ease;
}
.remember-label:hover {
color: #333;
}
.remember-checkbox {
margin-right: 8px;
cursor: pointer;
transform: scale(1.1);
accent-color: var(--nangwang-blue);
}
.forgot-password {
color: var(--nangwang-blue);
text-decoration: none;
font-size: 13px;
transition: all 0.3s ease;
}
.forgot-password:hover {
color: var(--nangwang-blue-light);
text-decoration: underline;
2025-06-20 17:47:53 +08:00
}
/* Agreement section */
.agreement-section {
margin: 20px 0;
text-align: center;
2025-06-20 17:47:53 +08:00
}
.agreement-label {
display: inline-flex;
align-items: center;
cursor: pointer;
font-size: 14px;
color: #666;
transition: color 0.3s ease;
2025-06-20 17:47:53 +08:00
}
.agreement-label:hover {
color: #333;
2025-06-20 17:47:53 +08:00
}
.agreement-checkbox {
margin-right: 8px;
cursor: pointer;
transform: scale(1.1);
accent-color: var(--nangwang-blue);
2025-06-20 17:47:53 +08:00
}
.agreement-link {
color: var(--nangwang-blue);
text-decoration: none;
font-weight: 500;
margin-left: 4px;
border-bottom: 1px solid transparent;
transition: all 0.3s ease;
2025-06-20 17:47:53 +08:00
}
.agreement-link:hover {
border-bottom-color: var(--nangwang-blue);
color: var(--nangwang-blue-light);
2025-06-20 17:47:53 +08:00
}
/* Login button */
.login-button {
width: 100%;
height: 50px;
background: var(--nangwang-blue-gradient);
border: none;
border-radius: 12px;
color: white;
font-size: 16px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
margin-top: 10px;
2025-06-20 17:47:53 +08:00
}
.login-button::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
transition: left 0.5s ease;
2025-06-20 17:47:53 +08:00
}
.login-button:hover {
transform: translateY(-2px);
box-shadow: 0 10px 20px var(--nangwang-blue-shadow);
background: linear-gradient(135deg, var(--nangwang-blue-light) 0%, var(--nangwang-blue-lighter) 100%);
2025-06-20 17:47:53 +08:00
}
.login-button:hover::before {
left: 100%;
2025-06-20 17:47:53 +08:00
}
.login-button:active {
transform: translateY(0);
2025-06-20 17:47:53 +08:00
}
.login-button:disabled {
background: #ccc;
cursor: not-allowed;
transform: none;
box-shadow: none;
}
/* Responsive design */
@media (max-width: 768px) {
.login-container {
margin: 10px;
max-width: 100%;
}
.login-form {
padding: 30px 20px 20px;
}
.system-title {
font-size: 16px;
}
.form-input {
height: 45px;
font-size: 14px;
}
.login-button {
height: 45px;
font-size: 14px;
}
.remember-section {
flex-direction: column;
align-items: flex-start;
gap: 10px;
}
}
@media (max-width: 480px) {
.login-container {
margin: 5px;
}
.login-header {
padding: 20px 15px;
}
.login-form {
padding: 25px 15px 15px;
}
.system-title {
font-size: 14px;
}
}
/* Animation for form elements */
.form-group {
animation: slideInUp 0.6s ease forwards;
opacity: 0;
transform: translateY(30px);
}
.form-group:nth-child(1) { animation-delay: 0.1s; }
.form-group:nth-child(2) { animation-delay: 0.2s; }
.form-group:nth-child(3) { animation-delay: 0.3s; }
.form-group:nth-child(4) { animation-delay: 0.4s; }
.form-group:nth-child(5) { animation-delay: 0.5s; }
@keyframes slideInUp {
to {
opacity: 1;
transform: translateY(0);
}
}
/* Auto-fill styles */
.form-input:-webkit-autofill {
-webkit-box-shadow: 0 0 0 1000px #f8f9fa inset;
-webkit-text-fill-color: #333;
}
.form-input:-webkit-autofill:focus {
-webkit-box-shadow: 0 0 0 1000px white inset;
}
/* Loading state */
.login-button.loading {
pointer-events: none;
}
.login-button.loading::after {
content: '';
position: absolute;
width: 16px;
height: 16px;
margin: auto;
border: 2px solid transparent;
border-top-color: white;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Focus indicators for accessibility */
.form-input:focus,
.login-button:focus,
.agreement-checkbox:focus,
.remember-checkbox:focus,
.agreement-link:focus,
.forgot-password:focus {
outline: 2px solid var(--nangwang-blue);
outline-offset: 2px;
}
/* High contrast mode support */
@media (prefers-contrast: high) {
.login-card {
background: white;
border: 2px solid #333;
}
.form-input {
border-color: #333;
}
.login-button {
background: #333;
}
}
/* Reduced motion support */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* Custom checkbox styles for better visual consistency */
.remember-checkbox,
.agreement-checkbox {
width: 18px;
height: 18px;
border-radius: 3px;
position: relative;
}
.remember-checkbox:checked,
.agreement-checkbox:checked {
background-color: var(--nangwang-blue);
border-color: var(--nangwang-blue);
}
/* 安全提示区域 */
.security-tip {
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
border-left: 4px solid var(--nangwang-blue);
padding: 12px 15px;
margin: 20px 0;
border-radius: 0 8px 8px 0;
font-size: 13px;
color: #666;
}
.security-tip .tip-icon {
color: var(--nangwang-blue);
margin-right: 8px;
font-weight: bold;
}
2025-06-20 17:47:53 +08:00
</style>
</head>
<body>
<div class="login-container">
<div class="login-card">
<!-- Header Section -->
<div class="login-header">
<div class="logo-container">
<img src="${bonuspath}/static/img/loginIcon.png" alt="系统Logo">
<div class="system-title">贵送机具管理系统</div>
</div>
</div>
<!-- Form Section -->
<div class="login-form">
<form action="" method="post" onsubmit="return false" id="loginForm">
<input type="hidden" value="<%=request.getSession().getAttribute("randTxt")%>" name="randSession">
<!-- Username Input -->
<div class="form-group">
<div class="input-container">
<input
class="form-input"
type="text"
id="accountNameId"
name="username"
placeholder="请输入用户名"
required
autocomplete="username"
aria-label="用户名"
/>
<i class="icon-user input-icon" aria-hidden="true"></i>
</div>
<div class="error-message" id="usererror" role="alert"></div>
</div>
<!-- Password Input -->
<div class="form-group">
<div class="input-container">
<input
class="form-input"
type="password"
id="passwordId"
name="password"
placeholder="请输入密码"
required
autocomplete="current-password"
aria-label="密码"
/>
<i class="icon-lock input-icon" aria-hidden="true"></i>
</div>
<div class="error-message" id="passworderror" role="alert"></div>
</div>
<!-- Remember Password and Forgot Password Section -->
<div class="form-group">
<div class="remember-section">
<label class="remember-label">
<input
type="checkbox"
id="rememberCheckbox"
class="remember-checkbox"
aria-label="记住密码"
>
记住密码
</label>
<a style="display: none ;" href="javascript:void(0)" class="forgot-password" onclick="showForgotPassword()"
role="button" aria-label="忘记密码">忘记密码?</a>
</div>
</div>
<!-- Security Tip -->
<div class="form-group" style="display: none">
<div class="security-tip">
<span class="tip-icon">💡</span>
为了您的账户安全,建议在私人设备上使用记住密码功能
</div>
</div>
<!-- Agreement Section -->
<div class="form-group">
<div class="agreement-section">
<label class="agreement-label">
<input
type="checkbox"
id="agreementCheckbox"
class="agreement-checkbox"
required
aria-describedby="agreement-text"
>
<span id="agreement-text">
我已阅读并同意
<a href="javascript:void(0)" onclick="showAgreement()" class="agreement-link"
role="button" aria-label="查看用户协议详情">《用户协议》</a>
</span>
</label>
</div>
</div>
<!-- Login Button -->
<div class="form-group">
<button
type="button"
class="login-button"
id="loginBtn"
aria-label="登录系统"
>
登录
</button>
</div>
</form>
</div>
</div>
</div>
<script>
// Enhanced login functionality with remember password
2025-07-15 18:16:08 +08:00
let isLoginInProgress = false; // 添加登录状态标志
$(document).ready(function() {
// 页面加载时检查是否有保存的用户名
loadRememberedCredentials();
// Input focus effects
$('.form-input').on('focus', function() {
$(this).closest('.form-group').addClass('focused');
}).on('blur', function() {
$(this).closest('.form-group').removeClass('focused');
});
// Real-time validation
$('#accountNameId').on('input', function() {
validateUsername();
});
$('#passwordId').on('input', function() {
validatePassword();
});
// Agreement checkbox validation
$('#agreementCheckbox').on('change', function() {
validateAgreement();
});
// Remember password functionality
$('#rememberCheckbox').on('change', function() {
if (!$(this).is(':checked')) {
// 如果取消勾选,清除保存的信息
clearRememberedCredentials();
}
});
2025-07-15 18:16:08 +08:00
// 重写原有的登录按钮点击事件,添加防重复点击保护
$('#loginBtn').off('click').on('click', function(e) {
e.preventDefault();
if (isLoginInProgress) {
return false;
}
// 清除之前的错误消息
errorclean();
// 检查用户协议
if (!$('#agreementCheckbox').prop('checked')) {
layui.use('layer', function(){
var layer = layui.layer;
layer.msg('请阅读并同意用户协议');
});
return false;
}
// 验证用户名
if($("#accountNameId").val() == '') {
$("#usererror").append("登录名不能为空");
return false;
} else if($("#passwordId").val() == '') {
$("#passworderror").append("密码不能为空");
return false;
} else {
// 设置登录进行中状态
isLoginInProgress = true;
// 保存记住密码的凭据
const username = $('#accountNameId').val().trim();
const password = $('#passwordId').val();
const remember = $('#rememberCheckbox').is(':checked');
if (remember) {
saveCredentials(username, password, true);
}
// 执行原有的登录逻辑
dialogloading();
var loginname = $("#accountNameId").val();
var password = $("#passwordId").val();
loginname = encodeURI(encodeURI(loginname));
password = encodeURI(encodeURI(password));
localStorage.setItem("pwd", $.md5(password));
localStorage.setItem("uname", loginname);
var verifyCode = null;
var code = loginname + ",jy," + $.md5(password) + ",jy," + verifyCode;
$.ajax({
type: 'POST',
url: bonuspath + '/system_login',
data: {
KEYDATA: code,
tm: new Date().getTime(),
uuId: uuid()
},
dataType: 'json',
success: function(data, textStatus) {
dialogloadingClose();
// 重置登录状态(防重复提交保护)
isLoginInProgress = false;
const result = data.result;
if ("success" == result) {
sessionStorage.setItem("token", data.token);
dialogloadingClose();
clearLoginForm();
loginAlert(result);
window.location.href = bonuspath + "/backstage/index";
} else {
clearLoginForm();
loginAlert(result);
const errInfo = " ";
data.result = " ";
}
},
error: function(xhr, status, error) {
dialogloadingClose();
// 重置登录状态(防重复提交保护)
isLoginInProgress = false;
// 处理网络错误
loginAlert("error");
}
});
}
});
2025-07-15 18:16:08 +08:00
// Enter key support - 修复重复触发问题
$('#loginForm').on('keypress', function(e) {
if (e.which === 13) {
2025-07-15 18:16:08 +08:00
e.preventDefault();
if (!isLoginInProgress) {
$('#loginBtn').trigger('click');
}
}
});
2025-07-15 18:16:08 +08:00
// 防止表单默认提交
$('#loginForm').on('submit', function(e) {
e.preventDefault();
return false;
});
});
// 加载记住的凭据
function loadRememberedCredentials() {
try {
const rememberedUsername = localStorage.getItem('rememberedUsername');
const rememberedPassword = localStorage.getItem('rememberedPassword');
const isRemembered = localStorage.getItem('isPasswordRemembered') === 'true';
if (isRemembered && rememberedUsername) {
$('#accountNameId').val(rememberedUsername);
$('#rememberCheckbox').prop('checked', true);
// 只有在有记住的密码时才填充
if (rememberedPassword) {
$('#passwordId').val(atob(rememberedPassword)); // 简单的base64解码
}
// 如果用户名已填充,焦点移动到密码框
if (rememberedUsername && !rememberedPassword) {
$('#passwordId').focus();
}
}
} catch (error) {
console.log('加载记住的凭据时出错:', error);
}
}
// 保存凭据
function saveCredentials(username, password, remember) {
try {
if (remember) {
localStorage.setItem('rememberedUsername', username);
localStorage.setItem('rememberedPassword', btoa(password)); // 简单的base64编码
localStorage.setItem('isPasswordRemembered', 'true');
} else {
clearRememberedCredentials();
}
} catch (error) {
console.log('保存凭据时出错:', error);
}
}
// 清除记住的凭据
function clearRememberedCredentials() {
try {
localStorage.removeItem('rememberedUsername');
localStorage.removeItem('rememberedPassword');
localStorage.removeItem('isPasswordRemembered');
} catch (error) {
console.log('清除凭据时出错:', error);
}
}
function validateUsername() {
const username = $('#accountNameId').val().trim();
const errorElement = $('#usererror');
if (username.length === 0) {
showError(errorElement, '请输入用户名');
return false;
} else if (username.length < 2) {
showError(errorElement, '用户名至少需要2个字符');
return false;
} else {
hideError(errorElement);
return true;
}
}
function validatePassword() {
const password = $('#passwordId').val();
const errorElement = $('#passworderror');
if (password.length === 0) {
showError(errorElement, '请输入密码');
return false;
} else if (password.length < 6) {
showError(errorElement, '密码至少需要6个字符');
return false;
} else {
hideError(errorElement);
return true;
}
}
function validateAgreement() {
const isChecked = $('#agreementCheckbox').is(':checked');
if (!isChecked) {
layui.use('layer', function(){
var layer = layui.layer;
layer.msg('请先阅读并同意用户协议', {icon: 5});
});
return false;
}
return true;
}
function validateForm() {
const isUsernameValid = validateUsername();
const isPasswordValid = validatePassword();
const isAgreementValid = validateAgreement();
return isUsernameValid && isPasswordValid && isAgreementValid;
}
function showError(element, message) {
element.text(message).addClass('show');
element.closest('.form-group').addClass('error');
}
function hideError(element) {
element.removeClass('show');
element.closest('.form-group').removeClass('error');
}
2025-07-15 18:16:08 +08:00
// 清除所有错误消息
function hideAllErrors() {
$('.error-message').removeClass('show');
$('.form-group').removeClass('error');
}
// 添加原有登录逻辑中需要的工具函数
function uuid() {
var s = [];
var hexDigits = "0123456789abcdef";
for (var i = 0; i < 32; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
s[8] = s[13] = s[18] = s[23];
var uuid = s.join("");
return uuid;
}
function errorclean() {
$("#usererror").empty();
$("#passworderror").empty();
}
function clearLoginForm() {
$("#verifyCodeId").val("");
$("#passwordId").val("");
}
function loginAlert(msg) {
if("codeerror" == msg){
$("#verifyCodeId").tips({side : 3,msg : "验证码不正确!",bg : '#FF2D2D',time : 2});
$("#verifyCodeId").focus();
} else if("nullup" == msg){
$("#accountNameId").tips({side : 3,msg : "用户名或密码不能为空!",bg : '#FF2D2D',time : 2});
$("#accountNameId").focus();
} else if("nullcode" == msg){
$("#verifyCodeId").tips({side : 3,msg : "验证码不能为空!",bg : '#FF2D2D',time : 2});
$("#verifyCodeId").focus();
} else if("usererror" == msg){
$("#accountNameId").tips({side : 3,msg : "用户名或密码有误!",bg : '#FF2D2D',time : 2});
$("#accountNameId").focus();
} else if("attemptserror" == msg){
dialogerror("错误次数过多!");
} else if("error" == msg){
dialogerror("输入有误!");
} else if("inactive" == msg){
dialogerror("未激活!");
}
}
function dialogerror(Str) {
layui.use('layer', function(){
var layer = layui.layer;
layer.msg(Str, {icon: 5, time: 3000});
});
}
function dialogloading() {
layui.use('layer', function(){
var layer = layui.layer;
layer.load(1, {
shade: [0.1,'#fff']
});
2025-07-15 18:16:08 +08:00
});
}
function dialogloadingClose() {
layui.use('layer', function(){
var layer = layui.layer;
layer.closeAll('loading');
});
}
// 忘记密码功能
function showForgotPassword() {
layui.use('layer', function(){
var layer = layui.layer;
layer.prompt({
title: '忘记密码',
formType: 0,
value: $('#accountNameId').val(),
area: ['300px', '150px']
}, function(value, index){
if (value.trim() === '') {
layer.msg('请输入用户名', {icon: 5});
return false;
}
// 这里应该调用重置密码的接口
layer.msg('密码重置链接已发送到您的邮箱', {icon: 1, time: 3000});
layer.close(index);
});
});
}
// 增强的键盘导航
$(document).on('keydown', function(e) {
// Tab键在表单元素间导航
if (e.key === 'Tab') {
const focusableElements = $('#loginForm').find('input, button, a').filter(':visible');
const currentIndex = focusableElements.index(document.activeElement);
if (e.shiftKey) {
// Shift + Tab (向上)
if (currentIndex === 0) {
focusableElements.last().focus();
e.preventDefault();
}
} else {
// Tab (向下)
if (currentIndex === focusableElements.length - 1) {
focusableElements.first().focus();
e.preventDefault();
}
}
}
});
</script>
2025-06-20 17:47:53 +08:00
</body>
</html>