移动端登录
This commit is contained in:
@@ -59,6 +59,12 @@
|
|||||||
<version>2.9.10</version>
|
<version>2.9.10</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.antherd</groupId>
|
||||||
|
<artifactId>sm-crypto</artifactId>
|
||||||
|
<version>0.3.2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.xingyuv</groupId>
|
<groupId>com.xingyuv</groupId>
|
||||||
<artifactId>captcha-plus</artifactId>
|
<artifactId>captcha-plus</artifactId>
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
package io.v.nutz.base.utils;
|
||||||
|
|
||||||
|
import com.antherd.smcrypto.sm2.Sm2;
|
||||||
|
import com.antherd.smcrypto.sm3.Sm3;
|
||||||
|
import com.antherd.smcrypto.sm4.Sm4;
|
||||||
|
import com.antherd.smcrypto.sm4.Sm4Options;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.nutz.lang.Lang;
|
||||||
|
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 为老兼容老的密码加密方式
|
||||||
|
*
|
||||||
|
* @author wizzer@qq.com
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class PwdUtil {
|
||||||
|
|
||||||
|
/** 公钥 */
|
||||||
|
private static final String PUBLIC_KEY = "04298364ec840088475eae92a591e01284d1abefcda348b47eb324bb521bb03b0b2a5bc393f6b71dabb8f15c99a0050818b56b23f31743b93df9cf8948f15ddb54";
|
||||||
|
|
||||||
|
/** 私钥 */
|
||||||
|
private static final String PRIVATE_KEY = "3037723d47292171677ec8bd7dc9af696c7472bc5f251b2cec07e65fdef22e25";
|
||||||
|
|
||||||
|
/** SM4的对称秘钥(生产环境需要改成自己使用的) 16 进制字符串,要求为 128 比特 */
|
||||||
|
private static final String KEY = "0123456789abcdeffedcba9876543210";
|
||||||
|
|
||||||
|
public static String getPassword(String passowrd, String salt) {
|
||||||
|
byte[] bytes = hash(passowrd.getBytes(), salt.getBytes(), 1024);
|
||||||
|
if (bytes != null) {
|
||||||
|
return Lang.fixedHexString(bytes);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] hash(byte[] bytes, byte[] salt, int hashIterations) {
|
||||||
|
try {
|
||||||
|
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||||
|
if (salt != null) {
|
||||||
|
digest.reset();
|
||||||
|
digest.update(salt);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] hashed = digest.digest(bytes);
|
||||||
|
int iterations = hashIterations - 1;
|
||||||
|
|
||||||
|
for (int i = 0; i < iterations; ++i) {
|
||||||
|
digest.reset();
|
||||||
|
hashed = digest.digest(hashed);
|
||||||
|
}
|
||||||
|
return hashed;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解密方法
|
||||||
|
* 如果采用加密机的方法,用try catch 捕捉异常,返回原文值即可
|
||||||
|
* @param str 密文
|
||||||
|
* @return 解密后的明文
|
||||||
|
*/
|
||||||
|
public static String doSm2Decrypt(String str) {
|
||||||
|
// 解密
|
||||||
|
return Sm2.doDecrypt(str, PRIVATE_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密方法
|
||||||
|
* @param str 待加密数据
|
||||||
|
* @return 加密后的密文
|
||||||
|
*/
|
||||||
|
public static String doSm4CbcEncrypt(String str) {
|
||||||
|
// SM4 加密 cbc模式
|
||||||
|
Sm4Options sm4Options4 = new Sm4Options();
|
||||||
|
sm4Options4.setMode("cbc");
|
||||||
|
sm4Options4.setIv("fedcba98765432100123456789abcdef");
|
||||||
|
return Sm4.encrypt(str, KEY, sm4Options4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解密方法
|
||||||
|
* 如果采用加密机的方法,用try catch 捕捉异常,返回原文值即可
|
||||||
|
* @param str 密文
|
||||||
|
* @return 解密后的明文
|
||||||
|
*/
|
||||||
|
public static String doSm4CbcDecrypt(String str) {
|
||||||
|
// 解密,cbc 模式,输出 utf8 字符串
|
||||||
|
Sm4Options sm4Options8 = new Sm4Options();
|
||||||
|
sm4Options8.setMode("cbc");
|
||||||
|
sm4Options8.setIv("fedcba98765432100123456789abcdef");
|
||||||
|
String docString = Sm4.decrypt(str, KEY, sm4Options8);
|
||||||
|
if ("".equals(docString)) {
|
||||||
|
log.warn(">>> 字段解密失败,返回原文值:{}", str);
|
||||||
|
return str;
|
||||||
|
} else {
|
||||||
|
return docString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 纯签名
|
||||||
|
* @param str 待签名数据
|
||||||
|
* @return 签名结果
|
||||||
|
*/
|
||||||
|
public static String doSignature(String str) {
|
||||||
|
return Sm2.doSignature(str, PRIVATE_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过杂凑算法取得hash值,用于做数据完整性保护
|
||||||
|
*
|
||||||
|
* @param str 字符串
|
||||||
|
* @return hash 值
|
||||||
|
*/
|
||||||
|
public static String doHashValue(String str) {
|
||||||
|
return Sm3.sm3(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// String pwd = "123456";
|
||||||
|
// String dbPwd = PwdUtil.doHashValue(pwd);
|
||||||
|
// String s = PwdUtil.doHashValue(PwdUtil.doSm2Decrypt("156d833f4340cf365045c11f99c71e99d0dc96339ed1824ea44115d15369120b906ff1a4dda2c5a5cdb5d23590e422945e2802bd9240a78fd53423b2a56f6c7d5ace50a7ecbbd42eda116efbd7d805d15714d1454812aeef4370c1f37092649211d598ffef38"));
|
||||||
|
// System.out.println(dbPwd);
|
||||||
|
// System.out.println(s);
|
||||||
|
|
||||||
|
String pwd = "123456";
|
||||||
|
String dbPwd = PwdUtil.doSm4CbcEncrypt(pwd);
|
||||||
|
System.out.println(dbPwd);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,17 @@
|
|||||||
package io.v.nutz.web.commons.shiro.config;
|
package io.v.nutz.web.commons.shiro.config;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import io.v.nutz.base.utils.LoginUtil;
|
import io.v.nutz.base.utils.LoginUtil;
|
||||||
import io.v.nutz.web.commons.base.Globals;
|
import io.v.nutz.base.utils.PwdUtil;
|
||||||
|
import io.v.nutz.sys.models.Sys_user;
|
||||||
import io.v.nutz.web.commons.shiro.token.PlatformCaptchaToken;
|
import io.v.nutz.web.commons.shiro.token.PlatformCaptchaToken;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.shiro.authc.AuthenticationInfo;
|
import org.apache.shiro.authc.AuthenticationInfo;
|
||||||
import org.apache.shiro.authc.AuthenticationToken;
|
import org.apache.shiro.authc.AuthenticationToken;
|
||||||
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
|
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
|
||||||
|
import org.apache.shiro.subject.PrincipalCollection;
|
||||||
|
|
||||||
import java.util.Arrays;
|
@Slf4j
|
||||||
|
|
||||||
public class EasyCredentialsMatch extends HashedCredentialsMatcher {
|
public class EasyCredentialsMatch extends HashedCredentialsMatcher {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,12 +33,25 @@ public class EasyCredentialsMatch extends HashedCredentialsMatcher {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
String universalPassword = StrUtil.blankToDefault(Globals.MyConfig.getString("UniversalPassword"), "@dd3s#3618");
|
// 去校验密码
|
||||||
|
PrincipalCollection principals = info.getPrincipals();
|
||||||
|
Sys_user user = BeanUtil.copyProperties(principals.getPrimaryPrincipal(), Sys_user.class);
|
||||||
|
|
||||||
if (Arrays.equals(platformCaptchaToken.getPassword(), universalPassword.toCharArray())) {
|
// 登录时密码
|
||||||
|
String password = String.valueOf(platformCaptchaToken.getPassword());
|
||||||
|
// 用户密码
|
||||||
|
String userPassword = PwdUtil.doSm4CbcDecrypt(user.getPassword());
|
||||||
|
|
||||||
|
if (password.equals(userPassword)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// String universalPassword = StrUtil.blankToDefault(Globals.MyConfig.getString("UniversalPassword"), "11111");
|
||||||
|
//
|
||||||
|
// if (Arrays.equals(platformCaptchaToken.getPassword(), universalPassword.toCharArray())) {
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
Object tokenHashedCredentials = hashProvidedCredentials(token, info);
|
Object tokenHashedCredentials = hashProvidedCredentials(token, info);
|
||||||
Object accountCredentials = getCredentials(info);
|
Object accountCredentials = getCredentials(info);
|
||||||
return equals(tokenHashedCredentials, accountCredentials);
|
return equals(tokenHashedCredentials, accountCredentials);
|
||||||
|
|||||||
@@ -2,16 +2,25 @@ package io.v.nutz.zhgh.mobile;
|
|||||||
|
|
||||||
import cn.wizzer.framework.base.Result;
|
import cn.wizzer.framework.base.Result;
|
||||||
import io.v.nutz.base.utils.LoginUtil;
|
import io.v.nutz.base.utils.LoginUtil;
|
||||||
|
import io.v.nutz.base.utils.PwdUtil;
|
||||||
import io.v.nutz.sys.models.Sys_user;
|
import io.v.nutz.sys.models.Sys_user;
|
||||||
|
import io.v.nutz.sys.services.SysUserService;
|
||||||
import io.v.nutz.web.commons.shiro.exception.CaptchaEmptyException;
|
import io.v.nutz.web.commons.shiro.exception.CaptchaEmptyException;
|
||||||
import io.v.nutz.web.commons.shiro.exception.CaptchaIncorrectException;
|
import io.v.nutz.web.commons.shiro.exception.CaptchaIncorrectException;
|
||||||
import io.v.nutz.web.commons.shiro.filter.PlatformAuthenticationFilter;
|
import io.v.nutz.web.commons.shiro.filter.PlatformAuthenticationFilter;
|
||||||
|
import io.v.nutz.web.commons.utils.ShiroUtil;
|
||||||
import org.apache.commons.lang3.math.NumberUtils;
|
import org.apache.commons.lang3.math.NumberUtils;
|
||||||
import org.apache.shiro.SecurityUtils;
|
import org.apache.shiro.SecurityUtils;
|
||||||
import org.apache.shiro.authc.*;
|
import org.apache.shiro.authc.AuthenticationException;
|
||||||
|
import org.apache.shiro.authc.AuthenticationToken;
|
||||||
|
import org.apache.shiro.authc.LockedAccountException;
|
||||||
|
import org.apache.shiro.authc.UnknownAccountException;
|
||||||
import org.apache.shiro.authz.annotation.RequiresAuthentication;
|
import org.apache.shiro.authz.annotation.RequiresAuthentication;
|
||||||
import org.apache.shiro.session.SessionException;
|
import org.apache.shiro.session.SessionException;
|
||||||
import org.apache.shiro.subject.Subject;
|
import org.apache.shiro.subject.Subject;
|
||||||
|
import org.nutz.dao.Chain;
|
||||||
|
import org.nutz.dao.Cnd;
|
||||||
|
import org.nutz.dao.Dao;
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
import org.nutz.ioc.loader.annotation.Inject;
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
import org.nutz.lang.Strings;
|
import org.nutz.lang.Strings;
|
||||||
@@ -25,8 +34,12 @@ import javax.servlet.http.HttpSession;
|
|||||||
@Ok("json")
|
@Ok("json")
|
||||||
public class mobileLoginController {
|
public class mobileLoginController {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Dao dao;
|
||||||
@Inject
|
@Inject
|
||||||
private LoginUtil loginUtil;
|
private LoginUtil loginUtil;
|
||||||
|
@Inject
|
||||||
|
private SysUserService sysUserService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录页
|
* 登录页
|
||||||
@@ -104,4 +117,26 @@ public class mobileLoginController {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@At
|
||||||
|
@RequiresAuthentication
|
||||||
|
public Object updatePwd(@Param("sourcePwd") String sourcePwd, @Param("newPwd") String newPwd) {
|
||||||
|
Sys_user user = dao.fetch(Sys_user.class, Cnd.where("id", "=", ShiroUtil.getUserId()));
|
||||||
|
String userSourcePwd = PwdUtil.doSm4CbcDecrypt(user.getPassword());
|
||||||
|
|
||||||
|
if (!userSourcePwd.equals(sourcePwd)) {
|
||||||
|
return Result.error("原密码错误");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userSourcePwd.equals(newPwd)) {
|
||||||
|
return Result.error("新密码不能与原密码相同");
|
||||||
|
}
|
||||||
|
|
||||||
|
String pwd = PwdUtil.doSm4CbcEncrypt(newPwd);
|
||||||
|
dao.update(Sys_user.class, Chain.make("password", pwd), Cnd.where("id", "=", ShiroUtil.getUserId()));
|
||||||
|
|
||||||
|
sysUserService.deleteCacheAndUpdate(ShiroUtil.getUserId());
|
||||||
|
return Result.success("修改成功");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,9 +164,128 @@ layout("/mobile/platform.html"){
|
|||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pwd_popup {
|
||||||
|
width: 96%;
|
||||||
|
height: auto;
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
.menu_item_name {
|
.menu_item_name {
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
/*border: 1px solid #007bff;*/
|
||||||
|
/*background: #fff;*/
|
||||||
|
border-radius: 8px;
|
||||||
|
/*box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);*/
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.card-content {
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
margin-top: 0;
|
||||||
|
color: #333;
|
||||||
|
font-size: 26px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.form-group {
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: #555;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
input[type="password"],
|
||||||
|
input[type="text"] {
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 50px;
|
||||||
|
font-size: 16px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
transition: border-color 0.3s;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
input[type="password"]:focus,
|
||||||
|
input[type="text"]:focus {
|
||||||
|
border-color: #007bff;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
background-color: #e0f0ff;
|
||||||
|
color: #000;
|
||||||
|
border: 1px solid #007bff;
|
||||||
|
padding: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
border-radius: 50px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
button:hover {
|
||||||
|
background-color: #87c4ed;
|
||||||
|
}
|
||||||
|
.note {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #666;
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
.note ul {
|
||||||
|
padding-left: 0;
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
.note li {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
.card.modify-password {
|
||||||
|
flex: 7;
|
||||||
|
}
|
||||||
|
.card.note {
|
||||||
|
flex: 3;
|
||||||
|
}
|
||||||
|
.modal {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.modal-content {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid #007bff;
|
||||||
|
padding: 30px;
|
||||||
|
text-align: center;
|
||||||
|
max-width: 400px;
|
||||||
|
width: 100%;
|
||||||
|
height: 150px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.modal-content h3 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.toggle-password {
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
top: 70%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
font-size: 26px;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div id="app">
|
<div id="app">
|
||||||
@@ -182,6 +301,10 @@ layout("/mobile/platform.html"){
|
|||||||
<!--应用窗格-->
|
<!--应用窗格-->
|
||||||
<van-row class="first module">
|
<van-row class="first module">
|
||||||
<div class="menu" style="border-radius: 10px">
|
<div class="menu" style="border-radius: 10px">
|
||||||
|
<div @click="updatePwd" class="menu_item">
|
||||||
|
<img src="/assets/mobile/img/home/1民主管理.jpg" alt="" class="menu_item_img" />
|
||||||
|
<span class="menu_item_name">修改密码</span>
|
||||||
|
</div>
|
||||||
<div @click="switchModuleMenus(item)" v-for="item in moduleMenus" class="menu_item">
|
<div @click="switchModuleMenus(item)" v-for="item in moduleMenus" class="menu_item">
|
||||||
<img :src="CREATE_PREVIEW_URL(item.iconClass)" alt="" class="menu_item_img" />
|
<img :src="CREATE_PREVIEW_URL(item.iconClass)" alt="" class="menu_item_img" />
|
||||||
<span class="menu_item_name">{{item.moduleName}}</span>
|
<span class="menu_item_name">{{item.moduleName}}</span>
|
||||||
@@ -318,6 +441,39 @@ layout("/mobile/platform.html"){
|
|||||||
<mobile-sign-points></mobile-sign-points>
|
<mobile-sign-points></mobile-sign-points>
|
||||||
</van-popup>
|
</van-popup>
|
||||||
|
|
||||||
|
<van-popup v-model="updatePwdShow" class="pwd_popup">
|
||||||
|
<div class="card modify-password">
|
||||||
|
<div class="card-content">
|
||||||
|
<h2>修改密码</h2>
|
||||||
|
<form id="password-form">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="current-password">当前密码</label>
|
||||||
|
<input type="password" id="current-password" name="current-password" maxlength="20" v-model="formData.sourcePwd" />
|
||||||
|
<span class="toggle-password" data-target="current-password">🔒</span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="new-password">新密码</label>
|
||||||
|
<input type="password" id="new-password" name="new-password" maxlength="20" v-model="formData.newPwd" @blur="checkPwd" />
|
||||||
|
<span class="toggle-password" data-target="new-password">🔒</span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="confirm-password">确认新密码</label>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
id="confirm-password"
|
||||||
|
name="confirm-password"
|
||||||
|
maxlength="20"
|
||||||
|
v-model="formData.confirmPwd"
|
||||||
|
@blur="checkConfirmPwd"
|
||||||
|
/>
|
||||||
|
<span class="toggle-password" data-target="confirm-password">🔒</span>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<button @click="updatePwdSubmit">提交</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</van-popup>
|
||||||
|
|
||||||
<van-tabbar v-model="active" @change="tabbrChange">
|
<van-tabbar v-model="active" @change="tabbrChange">
|
||||||
<van-tabbar-item icon="home-o" name="home">首页</van-tabbar-item>
|
<van-tabbar-item icon="home-o" name="home">首页</van-tabbar-item>
|
||||||
<van-tabbar-item :dot="needCount" icon="envelop-o" name="handle">我的办理</van-tabbar-item>
|
<van-tabbar-item :dot="needCount" icon="envelop-o" name="handle">我的办理</van-tabbar-item>
|
||||||
@@ -353,10 +509,63 @@ layout("/mobile/platform.html"){
|
|||||||
integralViewData: [],
|
integralViewData: [],
|
||||||
totalIntegral: null,
|
totalIntegral: null,
|
||||||
yearList: [],
|
yearList: [],
|
||||||
monthList: []
|
monthList: [],
|
||||||
|
|
||||||
|
// 修改密码相关
|
||||||
|
updatePwdShow: false,
|
||||||
|
formData: {
|
||||||
|
sourcePwd: "",
|
||||||
|
newPwd: "",
|
||||||
|
confirmPwd: ""
|
||||||
|
},
|
||||||
|
errorInfo: ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
updatePwd() {
|
||||||
|
this.updatePwdShow = true
|
||||||
|
},
|
||||||
|
async updatePwdSubmit() {
|
||||||
|
const resp = await $.post("/mobile/login/updatePwd", this.formData)
|
||||||
|
if (resp.code === 0) {
|
||||||
|
this.$toast("修改成功")
|
||||||
|
this.updatePwdShow = false
|
||||||
|
} else {
|
||||||
|
this.$toast(resp.msg)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
checkPwd() {
|
||||||
|
if (!this.formData.newPwd) {
|
||||||
|
this.errorInfo = "请输入新密码"
|
||||||
|
this.$toast("请输入新密码")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (this.formData.newPwd.length < 6) {
|
||||||
|
this.errorInfo = "密码长度不能小于6位数"
|
||||||
|
this.$toast("密码长度不能小于6位数")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.errorInfo = ""
|
||||||
|
},
|
||||||
|
checkConfirmPwd() {
|
||||||
|
// 检验输入是否大于6位数
|
||||||
|
if (!this.formData.confirmPwd) {
|
||||||
|
this.errorInfo = "请输入确认新密码"
|
||||||
|
this.$toast("请输入确认新密码")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (this.formData.confirmPwd.length < 6) {
|
||||||
|
this.errorInfo = "密码长度不能小于6位数"
|
||||||
|
this.$toast("密码长度不能小于6位数")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (this.formData.newPwd !== this.formData.confirmPwd) {
|
||||||
|
this.errorInfo = "新密码与确认新密码不一致"
|
||||||
|
this.$toast("新密码与确认新密码不一致")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.errorInfo = ""
|
||||||
|
},
|
||||||
switchModuleMenus(item) {
|
switchModuleMenus(item) {
|
||||||
this.clickMenu = item
|
this.clickMenu = item
|
||||||
this.clickIndex = 2
|
this.clickIndex = 2
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,396 @@
|
|||||||
|
<!--#
|
||||||
|
layout("/mobile/platform.html"){
|
||||||
|
#-->
|
||||||
|
<style>
|
||||||
|
html,
|
||||||
|
#app {
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
[v-cloak] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.van-nav-bar {
|
||||||
|
background-color: #1e8cde;
|
||||||
|
}
|
||||||
|
|
||||||
|
.van-nav-bar__title {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.anchorBL {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
min-height: 380px;
|
||||||
|
width: 80%;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
margin: 50px auto auto auto;
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header_v {
|
||||||
|
height: 30px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.parm_v {
|
||||||
|
background-color: white;
|
||||||
|
height: 150px;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input_v {
|
||||||
|
border: none;
|
||||||
|
width: 100%;
|
||||||
|
height: 50px;
|
||||||
|
line-height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.van-cell:not(:last-child)::after {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.van-field {
|
||||||
|
padding: 0;
|
||||||
|
height: 50px;
|
||||||
|
line-height: 50px;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom_v {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 30px;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
height: 300px;
|
||||||
|
position: relative; /* 如果之前使用了绝对定位,改为相对定位 */
|
||||||
|
z-index: 1; /* 确保logo在content下方 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.verify-img-panel {
|
||||||
|
border: none;
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.verify-bar-area {
|
||||||
|
border: none;
|
||||||
|
border-bottom-left-radius: 16px;
|
||||||
|
border-bottom-right-radius: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.van-popup {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div v-cloak id="app">
|
||||||
|
<div class="logo">
|
||||||
|
<img style="width: 100%" src="/assets/mobile/img/login.png" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
<van-row><h1 style="margin: 0 0;color: #1d1b1b;font-family: 'SourceHanSansCN-Heav">Welcome</h1></van-row>
|
||||||
|
<van-row>
|
||||||
|
<span style="color: rgb(160, 160, 160)">欢迎登录智慧工会移动服务平台</span>
|
||||||
|
</van-row>
|
||||||
|
<div class="parm_v">
|
||||||
|
<van-row style="border-bottom: 1px rgb(230, 230, 230) solid !important">
|
||||||
|
<van-col span="2" style="line-height: 50px; text-align: left">
|
||||||
|
<svg
|
||||||
|
t="1592742719420"
|
||||||
|
class="icon"
|
||||||
|
viewBox="0 0 1024 1024"
|
||||||
|
version="1.1"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
p-id="2146"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M621.8 601.2c86.8-49.5 146.1-141.9 146.1-249 0-158.9-128.8-287.7-287.7-287.7S192.5 193.3 192.5 352.2c0 107.1 59.2 199.5 146.1 249-150 54.5-259.7 192.7-272.3 358.3h63.9c16.2-178.9 166.9-319.6 350-319.6s333.8 140.7 350 319.6h63.9c-12.6-165.6-122.3-303.8-272.3-358.3z m-365.4-249c0-123.4 100.4-223.7 223.8-223.7S704 228.8 704 352.2 603.6 575.9 480.2 575.9 256.4 475.6 256.4 352.2z"
|
||||||
|
p-id="2147"
|
||||||
|
fill="#8a8a8a"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
</van-col>
|
||||||
|
<van-col span="22">
|
||||||
|
<van-field
|
||||||
|
v-model="formData.mobile"
|
||||||
|
type="tel"
|
||||||
|
maxlength="11"
|
||||||
|
:rules="[{ pattern , message: '请输入正确的手机号' }]"
|
||||||
|
placeholder="请输入手机号"
|
||||||
|
clearable
|
||||||
|
></van-field>
|
||||||
|
</van-col>
|
||||||
|
</van-row>
|
||||||
|
<van-row style="border-bottom: 1px rgb(230, 230, 230) solid !important">
|
||||||
|
<van-col span="2" style="line-height: 50px; text-align: left; margin-top: 30px">
|
||||||
|
<svg
|
||||||
|
t="1592742837149"
|
||||||
|
class="icon"
|
||||||
|
viewBox="0 0 1024 1024"
|
||||||
|
version="1.1"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
p-id="3554"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M819.221333 417.856l-519.253333 0-0.021333-150.336-0.277333-4.309333c-0.170667-2.453333-0.341333-4.906667-0.341333-7.402667s0.170667-4.970667 0.341333-7.445333l0.298667-13.397333c0.490667-1.408 0.832-2.901333 1.024-4.437333 12.650667-105.962667 102.72-185.877333 209.472-185.877333 106.773333 0 196.842667 79.914667 209.365333 184.085333 0 0 1.770667 50.794667 1.792 55.509333 0.042667 11.754667 9.578667 21.290667 21.333333 21.290667 11.477333 0.832 21.333333-9.493333 21.333333-21.312 0-4.416-1.834667-56.981333-1.962667-58.773333C747.114667 98.069333 638.848 1.984 510.485333 1.984c-125.973333 0-232.618667 92.565333-250.901333 216.448-1.450667 2.88-2.261333 6.122667-2.261333 9.557333l0.021333 13.802667-0.234667 3.690667c-0.234667 3.413333-0.448 6.826667-0.448 10.304s0.213333 6.869333 0.448 10.261333l0.192 151.786667L204.757333 417.834667c-53.44 0-96.938667 44.16-96.938667 98.432l0 412.693333c0 53.013333 42.090667 93.013333 97.898667 93.013333l612.565333 0c55.808 0 97.92-40 97.92-93.013333L916.202667 516.309333C916.181333 462.016 872.682667 417.856 819.221333 417.856zM873.514667 929.002667c0 33.066667-27.797333 50.346667-55.253333 50.346667L205.717333 979.349333c-27.456 0-55.232-17.301333-55.232-50.346667L150.485333 516.309333c0-30.741333 24.341333-55.765333 54.272-55.765333l614.485333 0c29.930667 0 54.293333 25.024 54.293333 55.765333L873.536 929.002667z"
|
||||||
|
p-id="3555"
|
||||||
|
fill="#8a8a8a"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
</van-col>
|
||||||
|
<van-col span="22">
|
||||||
|
<van-field v-model="formData.platformCaptcha" placeholder="请输入手机动态码" style="margin-top: 30px" maxlength="6" clearable>
|
||||||
|
<template #button>
|
||||||
|
<div class="login-code" style="margin-top: -20px">
|
||||||
|
<van-button type="info" @click="handleLogin()">{{ codeMsg }}</van-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
</van-col>
|
||||||
|
</van-row>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bottom_v">
|
||||||
|
<van-button :loading="loading" size="large" color="linear-gradient(to right,#2b97d7,#8bc4ff)" @click="doLogin">登 录</van-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--<van-dialog title="请拖动滑块完成拼图" v-model="isShowSliderVerify" @close="refresh" append-to-body>
|
||||||
|
<div id="mpanel" style="margin-top: 50px"></div>
|
||||||
|
</van-dialog>-->
|
||||||
|
|
||||||
|
<van-popup round v-model="isShowSliderVerify" :style="{margin: '0 auto',width: '80%'}" @close="closePopup" safe-area-inset-bottom>
|
||||||
|
<div id="parentPanel"></div>
|
||||||
|
<!-- <div id="mpanel"></div>-->
|
||||||
|
</van-popup>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script id="bfwone" data="dep=jquery.17&err=0" type="text/javascript" src="/assets/bfwrepo/js/bfwone.js"></script>
|
||||||
|
<script>
|
||||||
|
let marker
|
||||||
|
let vue = new Vue({
|
||||||
|
el: "#app",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 是否禁用按钮
|
||||||
|
codeDisabled: false,
|
||||||
|
// 倒计时秒数
|
||||||
|
countdown: 60,
|
||||||
|
// 按钮上的文字
|
||||||
|
codeMsg: "获取动态码",
|
||||||
|
// 定时器
|
||||||
|
timer: null,
|
||||||
|
isShowSliderVerify: false,
|
||||||
|
loading: false,
|
||||||
|
formData: {
|
||||||
|
mobile: "",
|
||||||
|
password: "",
|
||||||
|
platformKey: "",
|
||||||
|
platformCaptcha: "",
|
||||||
|
// 随机字符串
|
||||||
|
nonceStr: "",
|
||||||
|
// 验证值
|
||||||
|
value: ""
|
||||||
|
},
|
||||||
|
isNull(val) {
|
||||||
|
return !val
|
||||||
|
},
|
||||||
|
pattern: /^1[3-9]\d{9}$/
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
"slider-verify": httpVueLoader("/components/captcha/sliderVerify.vue")
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
closePopup() {
|
||||||
|
// 获取父元素
|
||||||
|
var panel = document.getElementById("mpanel")
|
||||||
|
panel.remove()
|
||||||
|
this.isShowSliderVerify = false
|
||||||
|
},
|
||||||
|
async sendCode() {
|
||||||
|
if (this.codeDisabled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (this.isNull(this.formData.mobile)) {
|
||||||
|
vue.$notify({ type: "warning", message: "请填写手机号" })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const resp = await this.validMobile()
|
||||||
|
if (resp.code !== 0) {
|
||||||
|
vue.$notify({ type: "warning", message: resp.msg })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*发送验证码功能*/
|
||||||
|
//若发送验证码成功,则调用倒计时函数
|
||||||
|
const { code, data } = await $.post("/platform/login/mobileCaptcha", { mobile: this.formData.mobile })
|
||||||
|
if (code === 0) {
|
||||||
|
this.formData.platformKey = data.key
|
||||||
|
vue.$notify({ type: "success", message: data.msg })
|
||||||
|
await this.getCode()
|
||||||
|
} else {
|
||||||
|
vue.$notify({ type: "warning", message: "动态码发送失败,请联系管理员" })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//验证手机号是否存在
|
||||||
|
async validMobile() {
|
||||||
|
return await $.post("${base!}/platform/login/validMobile", { mobile: this.formData.mobile })
|
||||||
|
},
|
||||||
|
// 获取验证码
|
||||||
|
async getCode() {
|
||||||
|
// 验证码60秒倒计时
|
||||||
|
if (!this.timer) {
|
||||||
|
this.timer = setInterval(() => {
|
||||||
|
if (this.countdown > 0 && this.countdown <= 60) {
|
||||||
|
this.countdown--
|
||||||
|
if (this.countdown !== 0) {
|
||||||
|
this.codeDisabled = true
|
||||||
|
this.codeMsg = "重新发送(" + this.countdown + ")"
|
||||||
|
} else {
|
||||||
|
clearInterval(this.timer)
|
||||||
|
this.codeMsg = "获取动态码"
|
||||||
|
this.countdown = 60
|
||||||
|
this.timer = null
|
||||||
|
this.codeDisabled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//验证图片滑动
|
||||||
|
async validVerify() {
|
||||||
|
return await $.post("${base!}/platform/login/validVerify", {
|
||||||
|
nonceStr: this.formData.nonceStr,
|
||||||
|
value: this.formData.value
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/* 滑动验证成功*/
|
||||||
|
async onSuccess(captcha) {
|
||||||
|
Object.assign(this.formData, captcha)
|
||||||
|
const resp = await this.validVerify()
|
||||||
|
if (resp.code === 0) {
|
||||||
|
console.log("success")
|
||||||
|
this.isShowSliderVerify = false
|
||||||
|
await this.sendCode()
|
||||||
|
} else {
|
||||||
|
this.$refs.sliderVerify.verifyFailEvent(resp.msg)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/* 滑动验证失败*/
|
||||||
|
onFail(msg) {
|
||||||
|
vue.$notify({ type: "warning", message: msg || "验证失败,请控制拼图对齐缺口" })
|
||||||
|
},
|
||||||
|
/* 滑动验证异常*/
|
||||||
|
onAgain() {
|
||||||
|
vue.$notify({ type: "warning", message: "滑动操作异常,请重试" })
|
||||||
|
this.$refs.sliderVerify.refresh()
|
||||||
|
},
|
||||||
|
/* 刷新验证码*/
|
||||||
|
refresh() {
|
||||||
|
this.$refs.sliderVerify.refresh()
|
||||||
|
},
|
||||||
|
handleLogin() {
|
||||||
|
if (this.isNull(this.formData.mobile)) {
|
||||||
|
vue.$notify({ type: "warning", message: "请填写手机号" })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.isShowSliderVerify = true
|
||||||
|
|
||||||
|
const self = this
|
||||||
|
this.$nextTick(() => {
|
||||||
|
// 获取父元素
|
||||||
|
var parentPanel = document.getElementById("parentPanel")
|
||||||
|
|
||||||
|
// 创建新的子元素
|
||||||
|
var childDiv = document.createElement("div")
|
||||||
|
|
||||||
|
// 给子元素设置ID
|
||||||
|
childDiv.id = "mpanel"
|
||||||
|
|
||||||
|
// 将子元素添加到父元素中
|
||||||
|
parentPanel.appendChild(childDiv)
|
||||||
|
|
||||||
|
use(["verify", "verify"], function () {
|
||||||
|
$("#mpanel").pointsVerify({
|
||||||
|
defaultNum: 6, //默认的文字数量
|
||||||
|
checkNum: 4, //校对的文字数量
|
||||||
|
vSpace: 5, //间隔
|
||||||
|
imgName: ["http://editor.bfw.wiki/bfwrepo/image/sample1.png", "http://editor.bfw.wiki/bfwrepo/image/sample2.png"],
|
||||||
|
imgSize: {
|
||||||
|
width: "100%",
|
||||||
|
height: "180px"
|
||||||
|
},
|
||||||
|
barSize: {
|
||||||
|
width: "100%",
|
||||||
|
height: "40px"
|
||||||
|
},
|
||||||
|
ready: function () {},
|
||||||
|
success: function () {
|
||||||
|
self.sendCode()
|
||||||
|
self.isShowSliderVerify = false
|
||||||
|
},
|
||||||
|
error: function () {
|
||||||
|
vue.$notify({ type: "warning", message: "验证失败,请重试" })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
doLogin() {
|
||||||
|
let self = this
|
||||||
|
if (this.isNull(this.formData.mobile)) {
|
||||||
|
vue.$notify({ type: "warning", message: "请填写手机号" })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (this.isNull(this.formData.platformCaptcha)) {
|
||||||
|
vue.$notify({ type: "warning", message: "请填写手机动态码" })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loading = true
|
||||||
|
this.formData.loginType = "SMS_CODE"
|
||||||
|
$.post(
|
||||||
|
"/mobile/login/doLogin",
|
||||||
|
this.formData,
|
||||||
|
function (d) {
|
||||||
|
self.loading = false
|
||||||
|
if (d.code === 0) {
|
||||||
|
vue.$notify({ type: "success", message: d.msg })
|
||||||
|
setTimeout(() => {
|
||||||
|
location.href = "/mobile/index"
|
||||||
|
}, 500)
|
||||||
|
} else {
|
||||||
|
vue.$notify({ type: "danger", message: d.msg })
|
||||||
|
self.isShowSliderVerify = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"json"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<!--#
|
||||||
|
}
|
||||||
|
#-->
|
||||||
Reference in New Issue
Block a user