mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-28 18:23:51 +08:00
Merge pull request #1290 from xinnan-tech/manager-api-aly-message
阿里云短信发送功能,手机注册和找回密码接口
This commit is contained in:
@@ -28,6 +28,8 @@
|
|||||||
<captcha.version>1.6.2</captcha.version>
|
<captcha.version>1.6.2</captcha.version>
|
||||||
<guava.version>33.0.0-jre</guava.version>
|
<guava.version>33.0.0-jre</guava.version>
|
||||||
<liquibase-core.version>4.20.0</liquibase-core.version>
|
<liquibase-core.version>4.20.0</liquibase-core.version>
|
||||||
|
<aliyun-sms-version>4.1.0</aliyun-sms-version>
|
||||||
|
<okio-version>3.4.0</okio-version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -37,6 +39,7 @@
|
|||||||
<classifier>jakarta</classifier>
|
<classifier>jakarta</classifier>
|
||||||
<version>${shiro.version}</version>
|
<version>${shiro.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.shiro</groupId>
|
<groupId>org.apache.shiro</groupId>
|
||||||
<artifactId>shiro-spring</artifactId>
|
<artifactId>shiro-spring</artifactId>
|
||||||
@@ -201,6 +204,18 @@
|
|||||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- 阿里云短信sdk -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.aliyun</groupId>
|
||||||
|
<artifactId>dysmsapi20170525</artifactId>
|
||||||
|
<version>${aliyun-sms-version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- 阿里云短信sdk使用的okio:1.15.0版本有安全漏洞:GHSA-w33c-445m-f8w7 现在升级成3.4.0安全版本-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.okio</groupId>
|
||||||
|
<artifactId>okio</artifactId>
|
||||||
|
<version>${okio-version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<!-- 阿里云maven仓库 -->
|
<!-- 阿里云maven仓库 -->
|
||||||
|
|||||||
@@ -153,6 +153,46 @@ public interface Constant {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统短信
|
||||||
|
*/
|
||||||
|
enum SysMSMParam {
|
||||||
|
/**
|
||||||
|
* 阿里云授权keyID
|
||||||
|
*/
|
||||||
|
ALIYUN_SMS_ACCESS_KEY_ID("aliyun.sms.access_key_id"),
|
||||||
|
/**
|
||||||
|
* 阿里云授权密钥
|
||||||
|
*/
|
||||||
|
ALIYUN_SMS_ACCESS_KEY_SECRET("aliyun.sms.access_key_secret"),
|
||||||
|
/**
|
||||||
|
* 阿里云短信签名
|
||||||
|
*/
|
||||||
|
ALIYUN_SMS_SIGN_NAME("aliyun.sms.sign_name"),
|
||||||
|
/**
|
||||||
|
* 阿里云短信模板
|
||||||
|
*/
|
||||||
|
ALIYUN_SMS_SMS_CODE_TEMPLATE_CODE("aliyun.sms.sms_code_template_code"),
|
||||||
|
/**
|
||||||
|
* 单号码最大短信发送条数
|
||||||
|
*/
|
||||||
|
SYSTEM_SMS_MAX_SEND_COUNT("system.sms.max_send_count"),
|
||||||
|
/**
|
||||||
|
* 是否开启手机注册
|
||||||
|
*/
|
||||||
|
SYSTEM_ENABLE_MOBILE_REGISTER("system.enable_mobile_register");
|
||||||
|
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
SysMSMParam(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据状态
|
* 数据状态
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ public interface ErrorCode {
|
|||||||
int ACCOUNT_DISABLE = 10005;
|
int ACCOUNT_DISABLE = 10005;
|
||||||
int IDENTIFIER_NOT_NULL = 10006;
|
int IDENTIFIER_NOT_NULL = 10006;
|
||||||
int CAPTCHA_ERROR = 10007;
|
int CAPTCHA_ERROR = 10007;
|
||||||
int SUB_MENU_EXIST = 10008;
|
int PHONE_NOT_NULL = 10008;
|
||||||
int PASSWORD_ERROR = 10009;
|
int PASSWORD_ERROR = 10009;
|
||||||
|
|
||||||
int SUPERIOR_DEPT_ERROR = 10011;
|
int SUPERIOR_DEPT_ERROR = 10011;
|
||||||
|
|||||||
@@ -117,4 +117,26 @@ public class RedisKeys {
|
|||||||
public static String getAgentAudioIdKey(String uuid) {
|
public static String getAgentAudioIdKey(String uuid) {
|
||||||
return "agent:audio:id:" + uuid;
|
return "agent:audio:id:" + uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取短信验证码的缓存key
|
||||||
|
*/
|
||||||
|
public static String getSMSValidateCodeKey(String phone) {
|
||||||
|
return "sms:Validate:Code:" + phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取短信验证码最后发送时间的缓存key
|
||||||
|
*/
|
||||||
|
public static String getSMSLastSendTimeKey(String phone) {
|
||||||
|
return "sms:Validate:Code:" + phone + ":last_send_time";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取短信验证码今日发送次数的缓存key
|
||||||
|
*/
|
||||||
|
public static String getSMSTodayCountKey(String phone) {
|
||||||
|
return "sms:Validate:Code:" + phone + ":today_count";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package xiaozhi.common.validator;
|
|||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
|
import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
|
||||||
import org.springframework.context.i18n.LocaleContextHolder;
|
import org.springframework.context.i18n.LocaleContextHolder;
|
||||||
@@ -45,4 +46,32 @@ public class ValidatorUtils {
|
|||||||
throw new RenException(constraint.getMessage());
|
throw new RenException(constraint.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 国际手机号正则表达式
|
||||||
|
* 要求必须带国际区号,格式:+[国家代码][手机号]
|
||||||
|
* 例如:
|
||||||
|
* - +8613800138000
|
||||||
|
* - +12345678900
|
||||||
|
* - +447123456789
|
||||||
|
*/
|
||||||
|
private static final String INTERNATIONAL_PHONE_REGEX = "^\\+[1-9]\\d{0,3}[1-9]\\d{4,14}$";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验手机号是否有效
|
||||||
|
* 要求必须带国际区号,格式:+[国家代码][手机号]
|
||||||
|
* 例如:+8613800138000
|
||||||
|
*
|
||||||
|
* @param phone 手机号
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static boolean isValidPhone(String phone) {
|
||||||
|
if (phone == null || phone.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证必须带国际区号的手机号格式
|
||||||
|
Pattern pattern = Pattern.compile(INTERNATIONAL_PHONE_REGEX);
|
||||||
|
return pattern.matcher(phone).matches();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -80,6 +80,7 @@ public class ShiroConfig {
|
|||||||
filterMap.put("/doc.html", "anon");
|
filterMap.put("/doc.html", "anon");
|
||||||
filterMap.put("/favicon.ico", "anon");
|
filterMap.put("/favicon.ico", "anon");
|
||||||
filterMap.put("/user/captcha", "anon");
|
filterMap.put("/user/captcha", "anon");
|
||||||
|
filterMap.put("/user/smsVerification", "anon");
|
||||||
filterMap.put("/user/login", "anon");
|
filterMap.put("/user/login", "anon");
|
||||||
filterMap.put("/user/pub-config", "anon");
|
filterMap.put("/user/pub-config", "anon");
|
||||||
filterMap.put("/user/register", "anon");
|
filterMap.put("/user/register", "anon");
|
||||||
|
|||||||
+88
-8
@@ -2,6 +2,7 @@ package xiaozhi.modules.security.controller;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
@@ -24,13 +25,18 @@ import xiaozhi.common.utils.Result;
|
|||||||
import xiaozhi.common.validator.AssertUtils;
|
import xiaozhi.common.validator.AssertUtils;
|
||||||
import xiaozhi.common.validator.ValidatorUtils;
|
import xiaozhi.common.validator.ValidatorUtils;
|
||||||
import xiaozhi.modules.security.dto.LoginDTO;
|
import xiaozhi.modules.security.dto.LoginDTO;
|
||||||
|
import xiaozhi.modules.security.dto.SmsVerificationDTO;
|
||||||
import xiaozhi.modules.security.password.PasswordUtils;
|
import xiaozhi.modules.security.password.PasswordUtils;
|
||||||
import xiaozhi.modules.security.service.CaptchaService;
|
import xiaozhi.modules.security.service.CaptchaService;
|
||||||
import xiaozhi.modules.security.service.SysUserTokenService;
|
import xiaozhi.modules.security.service.SysUserTokenService;
|
||||||
import xiaozhi.modules.security.user.SecurityUser;
|
import xiaozhi.modules.security.user.SecurityUser;
|
||||||
import xiaozhi.modules.sys.dto.PasswordDTO;
|
import xiaozhi.modules.sys.dto.PasswordDTO;
|
||||||
|
import xiaozhi.modules.sys.dto.RetrievePasswordDTO;
|
||||||
import xiaozhi.modules.sys.dto.SysUserDTO;
|
import xiaozhi.modules.sys.dto.SysUserDTO;
|
||||||
|
import xiaozhi.modules.sys.service.SysDictDataService;
|
||||||
|
import xiaozhi.modules.sys.service.SysParamsService;
|
||||||
import xiaozhi.modules.sys.service.SysUserService;
|
import xiaozhi.modules.sys.service.SysUserService;
|
||||||
|
import xiaozhi.modules.sys.vo.SysDictDataItem;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录控制层
|
* 登录控制层
|
||||||
@@ -43,24 +49,43 @@ public class LoginController {
|
|||||||
private final SysUserService sysUserService;
|
private final SysUserService sysUserService;
|
||||||
private final SysUserTokenService sysUserTokenService;
|
private final SysUserTokenService sysUserTokenService;
|
||||||
private final CaptchaService captchaService;
|
private final CaptchaService captchaService;
|
||||||
|
private final SysParamsService sysParamsService;
|
||||||
|
private final SysDictDataService sysDictDataService;
|
||||||
|
|
||||||
@GetMapping("/captcha")
|
@GetMapping("/captcha")
|
||||||
@Operation(summary = "验证码")
|
@Operation(summary = "验证码")
|
||||||
public void captcha(HttpServletResponse response, String uuid) throws IOException {
|
public void captcha(HttpServletResponse response, String uuid) throws IOException {
|
||||||
// uuid不能为空
|
// uuid不能为空
|
||||||
AssertUtils.isBlank(uuid, ErrorCode.IDENTIFIER_NOT_NULL);
|
AssertUtils.isBlank(uuid, ErrorCode.IDENTIFIER_NOT_NULL);
|
||||||
|
|
||||||
// 生成验证码
|
// 生成验证码
|
||||||
captchaService.create(response, uuid);
|
captchaService.create(response, uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/smsVerification")
|
||||||
|
@Operation(summary = "短信验证码")
|
||||||
|
public Result<Void> smsVerification(@RequestBody SmsVerificationDTO dto) {
|
||||||
|
// 验证图形验证码
|
||||||
|
boolean validate = captchaService.validate(dto.getCaptchaId(), dto.getCaptcha(), true);
|
||||||
|
if (!validate) {
|
||||||
|
throw new RenException("图形验证码错误");
|
||||||
|
}
|
||||||
|
Boolean isMobileRegister = sysParamsService
|
||||||
|
.getValueObject(Constant.SysMSMParam.SYSTEM_ENABLE_MOBILE_REGISTER.getValue(), Boolean.class);
|
||||||
|
if (!isMobileRegister) {
|
||||||
|
throw new RenException("没有开启手机注册,没法使用短信验证码功能");
|
||||||
|
}
|
||||||
|
// 发送短信验证码
|
||||||
|
captchaService.sendSMSValidateCode(dto.getPhone());
|
||||||
|
return new Result<>();
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
@Operation(summary = "登录")
|
@Operation(summary = "登录")
|
||||||
public Result<TokenDTO> login(@RequestBody LoginDTO login) {
|
public Result<TokenDTO> login(@RequestBody LoginDTO login) {
|
||||||
// 验证是否正确输入验证码
|
// 验证是否正确输入验证码
|
||||||
boolean validate = captchaService.validate(login.getCaptchaId(), login.getCaptcha());
|
boolean validate = captchaService.validate(login.getCaptchaId(), login.getCaptcha(), true);
|
||||||
if (!validate) {
|
if (!validate) {
|
||||||
throw new RenException("验证码错误,请重新获取");
|
throw new RenException("图形验证码错误,请重新获取");
|
||||||
}
|
}
|
||||||
// 按照用户名获取用户
|
// 按照用户名获取用户
|
||||||
SysUserDTO userDTO = sysUserService.getByUsername(login.getUsername());
|
SysUserDTO userDTO = sysUserService.getByUsername(login.getUsername());
|
||||||
@@ -81,11 +106,29 @@ public class LoginController {
|
|||||||
if (!sysUserService.getAllowUserRegister()) {
|
if (!sysUserService.getAllowUserRegister()) {
|
||||||
throw new RenException("当前不允许普通用户注册");
|
throw new RenException("当前不允许普通用户注册");
|
||||||
}
|
}
|
||||||
// 验证是否正确输入验证码
|
// 是否开启手机注册
|
||||||
boolean validate = captchaService.validate(login.getCaptchaId(), login.getCaptcha());
|
Boolean isMobileRegister = sysParamsService
|
||||||
if (!validate) {
|
.getValueObject(Constant.SysMSMParam.SYSTEM_ENABLE_MOBILE_REGISTER.getValue(), Boolean.class);
|
||||||
throw new RenException("验证码错误,请重新获取");
|
boolean validate;
|
||||||
|
if (isMobileRegister) {
|
||||||
|
// 验证用户是否是手机号码
|
||||||
|
boolean validPhone = ValidatorUtils.isValidPhone(login.getUsername());
|
||||||
|
if (!validPhone) {
|
||||||
|
throw new RenException("用户名不是手机号码,请重新输入");
|
||||||
|
}
|
||||||
|
// 验证短信验证码是否正常
|
||||||
|
validate = captchaService.validateSMSValidateCode(login.getUsername(), login.getMobileCaptcha(), false);
|
||||||
|
if (!validate) {
|
||||||
|
throw new RenException("手机验证码错误,请重新获取");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 验证是否正确输入验证码
|
||||||
|
validate = captchaService.validate(login.getCaptchaId(), login.getCaptcha(), true);
|
||||||
|
if (!validate) {
|
||||||
|
throw new RenException("图形验证码错误,请重新获取");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 按照用户名获取用户
|
// 按照用户名获取用户
|
||||||
SysUserDTO userDTO = sysUserService.getByUsername(login.getUsername());
|
SysUserDTO userDTO = sysUserService.getByUsername(login.getUsername());
|
||||||
if (userDTO != null) {
|
if (userDTO != null) {
|
||||||
@@ -96,7 +139,6 @@ public class LoginController {
|
|||||||
userDTO.setPassword(login.getPassword());
|
userDTO.setPassword(login.getPassword());
|
||||||
sysUserService.save(userDTO);
|
sysUserService.save(userDTO);
|
||||||
return new Result<>();
|
return new Result<>();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/info")
|
@GetMapping("/info")
|
||||||
@@ -118,12 +160,50 @@ public class LoginController {
|
|||||||
return new Result<>();
|
return new Result<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PutMapping("/retrieve-password")
|
||||||
|
@Operation(summary = "找回密码")
|
||||||
|
public Result<?> retrievePassword(@RequestBody RetrievePasswordDTO dto) {
|
||||||
|
// 是否开启手机注册
|
||||||
|
Boolean isMobileRegister = sysParamsService
|
||||||
|
.getValueObject(Constant.SysMSMParam.SYSTEM_ENABLE_MOBILE_REGISTER.getValue(), Boolean.class);
|
||||||
|
if (!isMobileRegister) {
|
||||||
|
throw new RenException("没有开启手机注册,没法使用找回密码功能");
|
||||||
|
}
|
||||||
|
// 判断非空
|
||||||
|
ValidatorUtils.validateEntity(dto);
|
||||||
|
// 验证用户是否是手机号码
|
||||||
|
boolean validPhone = ValidatorUtils.isValidPhone(dto.getPhone());
|
||||||
|
if (!validPhone) {
|
||||||
|
throw new RenException("用户名不是手机号码,无法提供找回密码服务");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按照用户名获取用户
|
||||||
|
SysUserDTO userDTO = sysUserService.getByUsername(dto.getPhone());
|
||||||
|
if (userDTO == null) {
|
||||||
|
throw new RenException("用户名或验证码错误");
|
||||||
|
}
|
||||||
|
// 验证短信验证码是否正常
|
||||||
|
boolean validate = captchaService.validateSMSValidateCode(dto.getPhone(), dto.getCode());
|
||||||
|
// 判断是否通过验证
|
||||||
|
if (!validate) {
|
||||||
|
throw new RenException("用户名或验证码错误");
|
||||||
|
}
|
||||||
|
|
||||||
|
sysUserService.changePasswordDirectly(userDTO.getId(), dto.getPassword());
|
||||||
|
return new Result<>();
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/pub-config")
|
@GetMapping("/pub-config")
|
||||||
@Operation(summary = "公共配置")
|
@Operation(summary = "公共配置")
|
||||||
public Result<Map<String, Object>> pubConfig() {
|
public Result<Map<String, Object>> pubConfig() {
|
||||||
Map<String, Object> config = new HashMap<>();
|
Map<String, Object> config = new HashMap<>();
|
||||||
|
config.put("enableMobileRegister", sysParamsService
|
||||||
|
.getValueObject(Constant.SysMSMParam.SYSTEM_ENABLE_MOBILE_REGISTER.getValue(), Boolean.class));
|
||||||
config.put("version", Constant.VERSION);
|
config.put("version", Constant.VERSION);
|
||||||
config.put("allowUserRegister", sysUserService.getAllowUserRegister());
|
config.put("allowUserRegister", sysUserService.getAllowUserRegister());
|
||||||
|
List<SysDictDataItem> list = sysDictDataService.getDictDataByType("MOBILE_AREA");
|
||||||
|
config.put("mobileAreaList", list);
|
||||||
|
|
||||||
return new Result<Map<String, Object>>().ok(config);
|
return new Result<Map<String, Object>>().ok(config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,6 +25,9 @@ public class LoginDTO implements Serializable {
|
|||||||
@NotBlank(message = "{sysuser.captcha.require}")
|
@NotBlank(message = "{sysuser.captcha.require}")
|
||||||
private String captcha;
|
private String captcha;
|
||||||
|
|
||||||
|
@Schema(description = "手机验证码")
|
||||||
|
private String mobileCaptcha;
|
||||||
|
|
||||||
@Schema(description = "唯一标识")
|
@Schema(description = "唯一标识")
|
||||||
@NotBlank(message = "{sysuser.uuid.require}")
|
@NotBlank(message = "{sysuser.uuid.require}")
|
||||||
private String captchaId;
|
private String captchaId;
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package xiaozhi.modules.security.dto;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 短信验证码请求DTO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Schema(description = "短信验证码请求")
|
||||||
|
public class SmsVerificationDTO implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Schema(description = "手机号码")
|
||||||
|
@NotBlank(message = "{sysuser.username.require}")
|
||||||
|
private String phone;
|
||||||
|
|
||||||
|
@Schema(description = "验证码")
|
||||||
|
@NotBlank(message = "{sysuser.captcha.require}")
|
||||||
|
private String captcha;
|
||||||
|
|
||||||
|
@Schema(description = "唯一标识")
|
||||||
|
@NotBlank(message = "{sysuser.uuid.require}")
|
||||||
|
private String captchaId;
|
||||||
|
}
|
||||||
+21
-3
@@ -19,9 +19,27 @@ public interface CaptchaService {
|
|||||||
/**
|
/**
|
||||||
* 验证码效验
|
* 验证码效验
|
||||||
*
|
*
|
||||||
* @param uuid uuid
|
* @param uuid uuid
|
||||||
* @param code 验证码
|
* @param code 验证码
|
||||||
|
* @param delete 是否删除验证码
|
||||||
* @return true:成功 false:失败
|
* @return true:成功 false:失败
|
||||||
*/
|
*/
|
||||||
boolean validate(String uuid, String code);
|
boolean validate(String uuid, String code, Boolean delete);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送短信验证码
|
||||||
|
*
|
||||||
|
* @param phone 手机
|
||||||
|
*/
|
||||||
|
void sendSMSValidateCode(String phone);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证短信验证码
|
||||||
|
*
|
||||||
|
* @param phone 手机
|
||||||
|
* @param code 验证码
|
||||||
|
* @param delete 是否删除验证码
|
||||||
|
* @return true:成功 false:失败
|
||||||
|
*/
|
||||||
|
boolean validateSMSValidateCode(String phone, String code, Boolean delete);
|
||||||
}
|
}
|
||||||
|
|||||||
+90
-4
@@ -1,6 +1,7 @@
|
|||||||
package xiaozhi.modules.security.service.impl;
|
package xiaozhi.modules.security.service.impl;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Random;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
@@ -14,9 +15,13 @@ import com.wf.captcha.base.Captcha;
|
|||||||
|
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import xiaozhi.common.constant.Constant;
|
||||||
|
import xiaozhi.common.exception.RenException;
|
||||||
import xiaozhi.common.redis.RedisKeys;
|
import xiaozhi.common.redis.RedisKeys;
|
||||||
import xiaozhi.common.redis.RedisUtils;
|
import xiaozhi.common.redis.RedisUtils;
|
||||||
import xiaozhi.modules.security.service.CaptchaService;
|
import xiaozhi.modules.security.service.CaptchaService;
|
||||||
|
import xiaozhi.modules.sms.service.SmsService;
|
||||||
|
import xiaozhi.modules.sys.service.SysParamsService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验证码
|
* 验证码
|
||||||
@@ -25,6 +30,10 @@ import xiaozhi.modules.security.service.CaptchaService;
|
|||||||
public class CaptchaServiceImpl implements CaptchaService {
|
public class CaptchaServiceImpl implements CaptchaService {
|
||||||
@Resource
|
@Resource
|
||||||
private RedisUtils redisUtils;
|
private RedisUtils redisUtils;
|
||||||
|
@Resource
|
||||||
|
private SmsService smsService;
|
||||||
|
@Resource
|
||||||
|
private SysParamsService sysParamsService;
|
||||||
@Value("${renren.redis.open}")
|
@Value("${renren.redis.open}")
|
||||||
private boolean open;
|
private boolean open;
|
||||||
/**
|
/**
|
||||||
@@ -51,12 +60,12 @@ public class CaptchaServiceImpl implements CaptchaService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean validate(String uuid, String code) {
|
public boolean validate(String uuid, String code, Boolean delete) {
|
||||||
if (StringUtils.isBlank(code)) {
|
if (StringUtils.isBlank(code)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// 获取验证码
|
// 获取验证码
|
||||||
String captcha = getCache(uuid);
|
String captcha = getCache(uuid, delete);
|
||||||
|
|
||||||
// 效验成功
|
// 效验成功
|
||||||
if (code.equalsIgnoreCase(captcha)) {
|
if (code.equalsIgnoreCase(captcha)) {
|
||||||
@@ -66,21 +75,98 @@ public class CaptchaServiceImpl implements CaptchaService {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendSMSValidateCode(String phone) {
|
||||||
|
// 检查发送间隔
|
||||||
|
String lastSendTimeKey = RedisKeys.getSMSLastSendTimeKey(phone);
|
||||||
|
String lastSendTime = (String) redisUtils.get(lastSendTimeKey);
|
||||||
|
if (lastSendTime != null) {
|
||||||
|
long lastSendTimeLong = Long.parseLong(lastSendTime);
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
long timeDiff = currentTime - lastSendTimeLong;
|
||||||
|
if (timeDiff < 60000) {
|
||||||
|
throw new RenException("发送太频繁,请" + (60000 - timeDiff) / 1000 + "秒后再试");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查今日发送次数
|
||||||
|
String todayCountKey = RedisKeys.getSMSTodayCountKey(phone);
|
||||||
|
Integer todayCount = (Integer) redisUtils.get(todayCountKey);
|
||||||
|
if (todayCount == null) {
|
||||||
|
todayCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取最大发送次数限制
|
||||||
|
Integer maxSendCount = sysParamsService.getValueObject(
|
||||||
|
Constant.SysMSMParam.SYSTEM_SMS_MAX_SEND_COUNT.getValue(),
|
||||||
|
Integer.class);
|
||||||
|
if (maxSendCount == null) {
|
||||||
|
maxSendCount = 5; // 默认值
|
||||||
|
}
|
||||||
|
|
||||||
|
if (todayCount >= maxSendCount) {
|
||||||
|
throw new RenException("今日发送次数已达上限");
|
||||||
|
}
|
||||||
|
|
||||||
|
String key = RedisKeys.getSMSValidateCodeKey(phone);
|
||||||
|
String validateCodes = generateValidateCode(6);
|
||||||
|
|
||||||
|
// 设置验证码
|
||||||
|
setCache(key, validateCodes);
|
||||||
|
|
||||||
|
// 设置最后发送时间(60秒)
|
||||||
|
redisUtils.set(lastSendTimeKey, String.valueOf(System.currentTimeMillis()), 60);
|
||||||
|
|
||||||
|
// 更新今日发送次数
|
||||||
|
if (todayCount == 0) {
|
||||||
|
// 如果是今天第一次发送,设置24小时过期
|
||||||
|
redisUtils.set(todayCountKey, 1, RedisUtils.DEFAULT_EXPIRE);
|
||||||
|
} else {
|
||||||
|
redisUtils.set(todayCountKey, todayCount + 1, RedisUtils.DEFAULT_EXPIRE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送验证码短信
|
||||||
|
smsService.sendVerificationCodeSms(phone, validateCodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean validateSMSValidateCode(String phone, String code, Boolean delete) {
|
||||||
|
String key = RedisKeys.getSMSValidateCodeKey(phone);
|
||||||
|
return validate(key, code, delete);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成指定数量的随机数验证码
|
||||||
|
*
|
||||||
|
* @param length 数量
|
||||||
|
* @return 随机码
|
||||||
|
*/
|
||||||
|
private String generateValidateCode(Integer length) {
|
||||||
|
String chars = "0123456789"; // 字符范围可以自定义:数字
|
||||||
|
Random random = new Random();
|
||||||
|
StringBuilder code = new StringBuilder();
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
code.append(chars.charAt(random.nextInt(chars.length())));
|
||||||
|
}
|
||||||
|
return code.toString();
|
||||||
|
}
|
||||||
|
|
||||||
private void setCache(String key, String value) {
|
private void setCache(String key, String value) {
|
||||||
if (open) {
|
if (open) {
|
||||||
key = RedisKeys.getCaptchaKey(key);
|
key = RedisKeys.getCaptchaKey(key);
|
||||||
|
// 设置5分钟过期
|
||||||
redisUtils.set(key, value, 300);
|
redisUtils.set(key, value, 300);
|
||||||
} else {
|
} else {
|
||||||
localCache.put(key, value);
|
localCache.put(key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getCache(String key) {
|
private String getCache(String key, Boolean delete) {
|
||||||
if (open) {
|
if (open) {
|
||||||
key = RedisKeys.getCaptchaKey(key);
|
key = RedisKeys.getCaptchaKey(key);
|
||||||
String captcha = (String) redisUtils.get(key);
|
String captcha = (String) redisUtils.get(key);
|
||||||
// 删除验证码
|
// 删除验证码
|
||||||
if (captcha != null) {
|
if (captcha != null && delete) {
|
||||||
redisUtils.delete(key);
|
redisUtils.delete(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package xiaozhi.modules.sms.service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 短信服务的方法定义接口
|
||||||
|
*
|
||||||
|
* @author zjy
|
||||||
|
* @since 2025-05-12
|
||||||
|
*/
|
||||||
|
public interface SmsService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送验证码短信
|
||||||
|
* @param phone 手机号码
|
||||||
|
* @param VerificationCode 验证码
|
||||||
|
*/
|
||||||
|
void sendVerificationCodeSms(String phone, String VerificationCode) ;
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package xiaozhi.modules.sms.service.imp;
|
||||||
|
|
||||||
|
import com.aliyun.dysmsapi20170525.Client;
|
||||||
|
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
|
||||||
|
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
|
||||||
|
import com.aliyun.teaopenapi.models.Config;
|
||||||
|
import com.aliyun.teautil.models.RuntimeOptions;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import xiaozhi.common.constant.Constant;
|
||||||
|
import xiaozhi.common.exception.RenException;
|
||||||
|
import xiaozhi.modules.sms.service.SmsService;
|
||||||
|
import xiaozhi.modules.sys.service.SysParamsService;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Slf4j
|
||||||
|
public class ALiYunSmsService implements SmsService {
|
||||||
|
private final SysParamsService sysParamsService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendVerificationCodeSms(String phone, String VerificationCode) {
|
||||||
|
Client client = createClient();
|
||||||
|
String SignName = sysParamsService.getValue(Constant.SysMSMParam
|
||||||
|
.ALIYUN_SMS_SIGN_NAME.getValue(),true);
|
||||||
|
String TemplateCode = sysParamsService.getValue(Constant.SysMSMParam
|
||||||
|
.ALIYUN_SMS_SMS_CODE_TEMPLATE_CODE.getValue(),true);
|
||||||
|
try {
|
||||||
|
SendSmsRequest sendSmsRequest = new SendSmsRequest()
|
||||||
|
.setSignName(SignName)
|
||||||
|
.setTemplateCode(TemplateCode)
|
||||||
|
.setPhoneNumbers(phone)
|
||||||
|
.setTemplateParam(String.format("{\"code\":\"%s\"}", VerificationCode));
|
||||||
|
RuntimeOptions runtime = new RuntimeOptions();
|
||||||
|
// 复制代码运行请自行打印 API 的返回值
|
||||||
|
SendSmsResponse sendSmsResponse = client.sendSmsWithOptions(sendSmsRequest, runtime);
|
||||||
|
log.info("发送短信响应的requestID: {}", sendSmsResponse.getBody().getRequestId());
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 错误 message
|
||||||
|
log.error(e.getMessage());
|
||||||
|
throw new RenException("短信发送失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建阿里云连接
|
||||||
|
* @return 返回连接对象
|
||||||
|
*/
|
||||||
|
private Client createClient(){
|
||||||
|
String ACCESS_KEY_ID = sysParamsService.getValue(Constant.SysMSMParam
|
||||||
|
.ALIYUN_SMS_ACCESS_KEY_ID.getValue(),true);
|
||||||
|
String ACCESS_KEY_SECRET = sysParamsService.getValue(Constant.SysMSMParam
|
||||||
|
.ALIYUN_SMS_ACCESS_KEY_SECRET.getValue(),true);
|
||||||
|
try {
|
||||||
|
Config config = new Config()
|
||||||
|
.setAccessKeyId(ACCESS_KEY_ID)
|
||||||
|
.setAccessKeySecret(ACCESS_KEY_SECRET);
|
||||||
|
// 配置 Endpoint。中国站请使用dysmsapi.aliyuncs.com
|
||||||
|
config.endpoint = "dysmsapi.aliyuncs.com";
|
||||||
|
return new Client(config);
|
||||||
|
}catch (Exception e){
|
||||||
|
// 错误 message
|
||||||
|
log.error(e.getMessage());
|
||||||
|
throw new RenException("短信连接建立失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package xiaozhi.modules.sys.dto;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 找回密码DTO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Schema(description = "找回密码")
|
||||||
|
public class RetrievePasswordDTO implements Serializable {
|
||||||
|
|
||||||
|
@Schema(description = "手机号码")
|
||||||
|
@NotBlank(message = "{sysuser.password.require}")
|
||||||
|
private String phone;
|
||||||
|
|
||||||
|
@Schema(description = "验证码")
|
||||||
|
@NotBlank(message = "{sysuser.password.require}")
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
@Schema(description = "新密码")
|
||||||
|
@NotBlank(message = "{sysuser.password.require}")
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
-- 添加手机短信注册功能的需要的参数
|
||||||
|
delete from sys_params where id in (601, 602, 610, 611, 612, 613);
|
||||||
|
INSERT INTO sys_params
|
||||||
|
(id, param_code, param_value, value_type, param_type, remark, creator, create_date, updater, update_date)
|
||||||
|
VALUES
|
||||||
|
(601, 'system.enable_mobile_register', 'false', 'boolean', 1, '是否开启手机注册', NULL, NULL, NULL, NULL),
|
||||||
|
(602, 'system.sms.max_send_count', '10', 'number', 1, '单号码单日最大短信发送条数', NULL, NULL, NULL, NULL),
|
||||||
|
(610, 'aliyun.sms.access_key_id', '', 'string', 1, '阿里云平台access_key', NULL, NULL, NULL, NULL),
|
||||||
|
(611, 'aliyun.sms.access_key_secret', '', 'string', 1, '阿里云平台access_key_secret', NULL, NULL, NULL, NULL),
|
||||||
|
(612, 'aliyun.sms.sign_name', '', 'string', 1, '阿里云短信签名', NULL, NULL, NULL, NULL),
|
||||||
|
(613, 'aliyun.sms.sms_code_template_code', '', 'string', 1, '阿里云短信模板', NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
-- 增加手机区域字典
|
||||||
|
-- 插入固件类型字典类型
|
||||||
|
delete from `sys_dict_type` where `id` = 102;
|
||||||
|
INSERT INTO `sys_dict_type` (`id`, `dict_type`, `dict_name`, `remark`, `sort`, `creator`, `create_date`, `updater`, `update_date`) VALUES
|
||||||
|
(102, 'MOBILE_AREA', '手机区域', '手机区域字典', 0, 1, NOW(), 1, NOW());
|
||||||
|
|
||||||
|
-- 插入固件类型字典数据
|
||||||
|
delete from `sys_dict_data` where `dict_type_id` = 102;
|
||||||
|
INSERT INTO `sys_dict_data` (`id`, `dict_type_id`, `dict_label`, `dict_value`, `remark`, `sort`, `creator`, `create_date`, `updater`, `update_date`) VALUES
|
||||||
|
(102001, 102, '中国大陆', '+86', '中国大陆', 1, 1, NOW(), 1, NOW()),
|
||||||
|
(102002, 102, '中国香港', '+852', '中国香港', 2, 1, NOW(), 1, NOW()),
|
||||||
|
(102003, 102, '中国澳门', '+853', '中国澳门', 3, 1, NOW(), 1, NOW()),
|
||||||
|
(102004, 102, '中国台湾', '+886', '中国台湾', 4, 1, NOW(), 1, NOW()),
|
||||||
|
(102005, 102, '美国/加拿大', '+1', '美国/加拿大', 5, 1, NOW(), 1, NOW()),
|
||||||
|
(102006, 102, '英国', '+44', '英国', 6, 1, NOW(), 1, NOW()),
|
||||||
|
(102007, 102, '法国', '+33', '法国', 7, 1, NOW(), 1, NOW()),
|
||||||
|
(102008, 102, '意大利', '+39', '意大利', 8, 1, NOW(), 1, NOW()),
|
||||||
|
(102009, 102, '德国', '+49', '德国', 9, 1, NOW(), 1, NOW()),
|
||||||
|
(102010, 102, '波兰', '+48', '波兰', 10, 1, NOW(), 1, NOW()),
|
||||||
|
(102011, 102, '瑞士', '+41', '瑞士', 11, 1, NOW(), 1, NOW()),
|
||||||
|
(102012, 102, '西班牙', '+34', '西班牙', 12, 1, NOW(), 1, NOW()),
|
||||||
|
(102013, 102, '丹麦', '+45', '丹麦', 13, 1, NOW(), 1, NOW()),
|
||||||
|
(102014, 102, '马来西亚', '+60', '马来西亚', 14, 1, NOW(), 1, NOW()),
|
||||||
|
(102015, 102, '澳大利亚', '+61', '澳大利亚', 15, 1, NOW(), 1, NOW()),
|
||||||
|
(102016, 102, '印度尼西亚', '+62', '印度尼西亚', 16, 1, NOW(), 1, NOW()),
|
||||||
|
(102017, 102, '菲律宾', '+63', '菲律宾', 17, 1, NOW(), 1, NOW()),
|
||||||
|
(102018, 102, '新西兰', '+64', '新西兰', 18, 1, NOW(), 1, NOW()),
|
||||||
|
(102019, 102, '新加坡', '+65', '新加坡', 19, 1, NOW(), 1, NOW()),
|
||||||
|
(102020, 102, '泰国', '+66', '泰国', 20, 1, NOW(), 1, NOW()),
|
||||||
|
(102021, 102, '日本', '+81', '日本', 21, 1, NOW(), 1, NOW()),
|
||||||
|
(102022, 102, '韩国', '+82', '韩国', 22, 1, NOW(), 1, NOW()),
|
||||||
|
(102023, 102, '越南', '+84', '越南', 23, 1, NOW(), 1, NOW()),
|
||||||
|
(102024, 102, '印度', '+91', '印度', 24, 1, NOW(), 1, NOW()),
|
||||||
|
(102025, 102, '巴基斯坦', '+92', '巴基斯坦', 25, 1, NOW(), 1, NOW()),
|
||||||
|
(102026, 102, '尼日利亚', '+234', '尼日利亚', 26, 1, NOW(), 1, NOW()),
|
||||||
|
(102027, 102, '孟加拉国', '+880', '孟加拉国', 27, 1, NOW(), 1, NOW()),
|
||||||
|
(102028, 102, '沙特阿拉伯', '+966', '沙特阿拉伯', 28, 1, NOW(), 1, NOW()),
|
||||||
|
(102029, 102, '阿联酋', '+971', '阿联酋', 29, 1, NOW(), 1, NOW()),
|
||||||
|
(102030, 102, '巴西', '+55', '巴西', 30, 1, NOW(), 1, NOW()),
|
||||||
|
(102031, 102, '墨西哥', '+52', '墨西哥', 31, 1, NOW(), 1, NOW()),
|
||||||
|
(102032, 102, '智利', '+56', '智利', 32, 1, NOW(), 1, NOW()),
|
||||||
|
(102033, 102, '阿根廷', '+54', '阿根廷', 33, 1, NOW(), 1, NOW()),
|
||||||
|
(102034, 102, '埃及', '+20', '埃及', 34, 1, NOW(), 1, NOW()),
|
||||||
|
(102035, 102, '南非', '+27', '南非', 35, 1, NOW(), 1, NOW()),
|
||||||
|
(102036, 102, '肯尼亚', '+254', '肯尼亚', 36, 1, NOW(), 1, NOW()),
|
||||||
|
(102037, 102, '坦桑尼亚', '+255', '坦桑尼亚', 37, 1, NOW(), 1, NOW()),
|
||||||
|
(102038, 102, '哈萨克斯坦', '+7', '哈萨克斯坦', 38, 1, NOW(), 1, NOW());
|
||||||
@@ -114,6 +114,13 @@ databaseChangeLog:
|
|||||||
- sqlFile:
|
- sqlFile:
|
||||||
encoding: utf8
|
encoding: utf8
|
||||||
path: classpath:db/changelog/202505091409.sql
|
path: classpath:db/changelog/202505091409.sql
|
||||||
|
- changeSet:
|
||||||
|
id: 202505141132
|
||||||
|
author: zjy
|
||||||
|
changes:
|
||||||
|
- sqlFile:
|
||||||
|
encoding: utf8
|
||||||
|
path: classpath:db/changelog/202505141132.sql
|
||||||
- changeSet:
|
- changeSet:
|
||||||
id: 202505091555
|
id: 202505091555
|
||||||
author: whosmyqueen
|
author: whosmyqueen
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
10005=\u8D26\u53F7\u5DF2\u88AB\u505C\u7528
|
10005=\u8D26\u53F7\u5DF2\u88AB\u505C\u7528
|
||||||
10006=\u552F\u4E00\u6807\u8BC6\u4E0D\u80FD\u4E3A\u7A7A
|
10006=\u552F\u4E00\u6807\u8BC6\u4E0D\u80FD\u4E3A\u7A7A
|
||||||
10007=\u9A8C\u8BC1\u7801\u4E0D\u6B63\u786E
|
10007=\u9A8C\u8BC1\u7801\u4E0D\u6B63\u786E
|
||||||
|
10008=\u624B\u673A\u53F7\u7801\u4E0D\u53EF\u4EE5\u4E3A\u7A7A
|
||||||
10009=\u539F\u5BC6\u7801\u4E0D\u6B63\u786E
|
10009=\u539F\u5BC6\u7801\u4E0D\u6B63\u786E
|
||||||
10010=\u8D26\u53F7\u6216\u5BC6\u7801\u4E0D\u6B63\u786E,\u60A8\u8FD8\u6709\u53EF\u4EE5\u5C1D\u8BD5{0}\u6B21
|
10010=\u8D26\u53F7\u6216\u5BC6\u7801\u4E0D\u6B63\u786E,\u60A8\u8FD8\u6709\u53EF\u4EE5\u5C1D\u8BD5{0}\u6B21
|
||||||
10011=\u4E0A\u7EA7\u90E8\u95E8\u9009\u62E9\u9519\u8BEF
|
10011=\u4E0A\u7EA7\u90E8\u95E8\u9009\u62E9\u9519\u8BEF
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package xiaozhi.modules.sys;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
import xiaozhi.modules.security.controller.LoginController;
|
||||||
|
import xiaozhi.modules.security.dto.LoginDTO;
|
||||||
|
import xiaozhi.modules.sys.dto.RetrievePasswordDTO;
|
||||||
|
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@SpringBootTest
|
||||||
|
@ActiveProfiles("dev")
|
||||||
|
class loginControllerTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
LoginController loginController;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRegister() {
|
||||||
|
LoginDTO loginDTO = new LoginDTO();
|
||||||
|
loginDTO.setUsername("手机号码");
|
||||||
|
loginDTO.setPassword("密码");
|
||||||
|
loginDTO.setCaptcha("123456");
|
||||||
|
loginController.register(loginDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSmsVerification(){
|
||||||
|
try {
|
||||||
|
loginController.smsVerification("手机号码");
|
||||||
|
}catch (Exception e){
|
||||||
|
System.out.println(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRetrievePassword(){
|
||||||
|
try {
|
||||||
|
RetrievePasswordDTO retrievePasswordDTO = new RetrievePasswordDTO();
|
||||||
|
retrievePasswordDTO.setCode("123456");
|
||||||
|
retrievePasswordDTO.setPhone("手机号码");
|
||||||
|
retrievePasswordDTO.setPassword("密码");
|
||||||
|
loginController.retrievePassword(retrievePasswordDTO);
|
||||||
|
}catch (Exception e){
|
||||||
|
System.out.println(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -20,6 +20,7 @@ function sendRequest() {
|
|||||||
return {
|
return {
|
||||||
_sucCallback: null,
|
_sucCallback: null,
|
||||||
_failCallback: null,
|
_failCallback: null,
|
||||||
|
_networkFailCallback: null,
|
||||||
_method: 'GET',
|
_method: 'GET',
|
||||||
_data: {},
|
_data: {},
|
||||||
_header: { 'content-type': 'application/json; charset=utf-8' },
|
_header: { 'content-type': 'application/json; charset=utf-8' },
|
||||||
@@ -36,7 +37,7 @@ function sendRequest() {
|
|||||||
headers: this._header,
|
headers: this._header,
|
||||||
responseType: this._responseType
|
responseType: this._responseType
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
const error = httpHandlerError(res, this._failCallback);
|
const error = httpHandlerError(res, this._failCallback, this._networkFailCallback);
|
||||||
if (error) {
|
if (error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -47,7 +48,7 @@ function sendRequest() {
|
|||||||
}).catch((res) => {
|
}).catch((res) => {
|
||||||
// 打印失败响应
|
// 打印失败响应
|
||||||
console.log('catch', res)
|
console.log('catch', res)
|
||||||
httpHandlerError(res, this._failCallback)
|
httpHandlerError(res, this._failCallback, this._networkFailCallback)
|
||||||
})
|
})
|
||||||
return this
|
return this
|
||||||
},
|
},
|
||||||
@@ -59,6 +60,10 @@ function sendRequest() {
|
|||||||
this._failCallback = callback
|
this._failCallback = callback
|
||||||
return this
|
return this
|
||||||
},
|
},
|
||||||
|
'networkFail'(callback) {
|
||||||
|
this._networkFailCallback = callback
|
||||||
|
return this
|
||||||
|
},
|
||||||
'url'(url) {
|
'url'(url) {
|
||||||
if (url) {
|
if (url) {
|
||||||
url = url.replaceAll('$', '/')
|
url = url.replaceAll('$', '/')
|
||||||
@@ -95,11 +100,11 @@ function sendRequest() {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Info 请求完成后返回信息
|
* Info 请求完成后返回信息
|
||||||
* callBack 回调函数
|
* failCallback 回调函数
|
||||||
* errTip 自定义错误信息
|
* networkFailCallback 回调函数
|
||||||
*/
|
*/
|
||||||
// 在错误处理函数中添加日志
|
// 在错误处理函数中添加日志
|
||||||
function httpHandlerError(info, callBack) {
|
function httpHandlerError(info, failCallback, networkFailCallback) {
|
||||||
|
|
||||||
/** 请求成功,退出该函数 可以根据项目需求来判断是否请求成功。这里判断的是status为200的时候是成功 */
|
/** 请求成功,退出该函数 可以根据项目需求来判断是否请求成功。这里判断的是status为200的时候是成功 */
|
||||||
let networkError = false
|
let networkError = false
|
||||||
@@ -111,12 +116,16 @@ function httpHandlerError(info, callBack) {
|
|||||||
goToPage(Constant.PAGE.LOGIN, true);
|
goToPage(Constant.PAGE.LOGIN, true);
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
showDanger(info.data.msg)
|
if (failCallback) {
|
||||||
|
failCallback(info)
|
||||||
|
} else {
|
||||||
|
showDanger(info.data.msg)
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (callBack) {
|
if (networkFailCallback) {
|
||||||
callBack(info)
|
networkFailCallback(info)
|
||||||
} else {
|
} else {
|
||||||
showDanger(`网络请求出现了错误【${info.status}】`)
|
showDanger(`网络请求出现了错误【${info.status}】`)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res)
|
callback(res)
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('请求失败:', err)
|
console.error('请求失败:', err)
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.getUserList(callback)
|
this.getUserList(callback)
|
||||||
@@ -34,7 +34,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res)
|
callback(res)
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('删除失败:', err)
|
console.error('删除失败:', err)
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.deleteUser(id, callback)
|
this.deleteUser(id, callback)
|
||||||
@@ -50,7 +50,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res)
|
callback(res)
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('重置密码失败:', err)
|
console.error('重置密码失败:', err)
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.resetUserPassword(id, callback)
|
this.resetUserPassword(id, callback)
|
||||||
@@ -72,7 +72,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res)
|
callback(res)
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('获取参数列表失败:', err)
|
console.error('获取参数列表失败:', err)
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.getParamsList(params, callback)
|
this.getParamsList(params, callback)
|
||||||
@@ -89,7 +89,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res)
|
callback(res)
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('添加参数失败:', err)
|
console.error('添加参数失败:', err)
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.addParam(data, callback)
|
this.addParam(data, callback)
|
||||||
@@ -106,7 +106,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res)
|
callback(res)
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('更新参数失败:', err)
|
console.error('更新参数失败:', err)
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.updateParam(data, callback)
|
this.updateParam(data, callback)
|
||||||
@@ -123,7 +123,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('删除参数失败:', err)
|
console.error('删除参数失败:', err)
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.deleteParam(ids, callback)
|
this.deleteParam(ids, callback)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail(() => {
|
.networkFail(() => {
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.getAgentList(callback);
|
this.getAgentList(callback);
|
||||||
});
|
});
|
||||||
@@ -28,7 +28,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail(() => {
|
.networkFail(() => {
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.addAgent(agentName, callback);
|
this.addAgent(agentName, callback);
|
||||||
});
|
});
|
||||||
@@ -43,7 +43,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail(() => {
|
.networkFail(() => {
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.deleteAgent(agentId, callback);
|
this.deleteAgent(agentId, callback);
|
||||||
});
|
});
|
||||||
@@ -58,7 +58,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('获取配置失败:', err);
|
console.error('获取配置失败:', err);
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.getDeviceConfig(agentId, callback);
|
this.getDeviceConfig(agentId, callback);
|
||||||
@@ -75,7 +75,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail(() => {
|
.networkFail(() => {
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.updateAgentConfig(agentId, configData, callback);
|
this.updateAgentConfig(agentId, configData, callback);
|
||||||
});
|
});
|
||||||
@@ -90,7 +90,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('获取模板失败:', err);
|
console.error('获取模板失败:', err);
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.getAgentTemplate(callback);
|
this.getAgentTemplate(callback);
|
||||||
@@ -107,7 +107,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail(() => {
|
.networkFail(() => {
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.getAgentSessions(agentId, params, callback);
|
this.getAgentSessions(agentId, params, callback);
|
||||||
});
|
});
|
||||||
@@ -122,7 +122,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail(() => {
|
.networkFail(() => {
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.getAgentChatHistory(agentId, sessionId, callback);
|
this.getAgentChatHistory(agentId, sessionId, callback);
|
||||||
});
|
});
|
||||||
@@ -137,7 +137,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail(() => {
|
.networkFail(() => {
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.getAudioId(audioId, callback);
|
this.getAudioId(audioId, callback);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('获取设备列表失败:', err);
|
console.error('获取设备列表失败:', err);
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.getAgentBindDevices(agentId, callback);
|
this.getAgentBindDevices(agentId, callback);
|
||||||
@@ -28,7 +28,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('解绑设备失败:', err);
|
console.error('解绑设备失败:', err);
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.unbindDevice(device_id, callback);
|
this.unbindDevice(device_id, callback);
|
||||||
@@ -44,7 +44,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('绑定设备失败:', err);
|
console.error('绑定设备失败:', err);
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.bindDevice(agentId, deviceCode, callback);
|
this.bindDevice(agentId, deviceCode, callback);
|
||||||
@@ -59,7 +59,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res)
|
callback(res)
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('更新OTA状态失败:', err)
|
console.error('更新OTA状态失败:', err)
|
||||||
this.$message.error(err.msg || '更新OTA状态失败')
|
this.$message.error(err.msg || '更新OTA状态失败')
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res)
|
callback(res)
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('获取字典类型列表失败:', err)
|
console.error('获取字典类型列表失败:', err)
|
||||||
this.$message.error(err.msg || '获取字典类型列表失败')
|
this.$message.error(err.msg || '获取字典类型列表失败')
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
@@ -36,7 +36,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res)
|
callback(res)
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('获取字典类型详情失败:', err)
|
console.error('获取字典类型详情失败:', err)
|
||||||
this.$message.error(err.msg || '获取字典类型详情失败')
|
this.$message.error(err.msg || '获取字典类型详情失败')
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
@@ -55,7 +55,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res)
|
callback(res)
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('新增字典类型失败:', err)
|
console.error('新增字典类型失败:', err)
|
||||||
this.$message.error(err.msg || '新增字典类型失败')
|
this.$message.error(err.msg || '新增字典类型失败')
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
@@ -74,7 +74,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res)
|
callback(res)
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('更新字典类型失败:', err)
|
console.error('更新字典类型失败:', err)
|
||||||
this.$message.error(err.msg || '更新字典类型失败')
|
this.$message.error(err.msg || '更新字典类型失败')
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
@@ -93,7 +93,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res)
|
callback(res)
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('删除字典类型失败:', err)
|
console.error('删除字典类型失败:', err)
|
||||||
this.$message.error(err.msg || '删除字典类型失败')
|
this.$message.error(err.msg || '删除字典类型失败')
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
@@ -119,7 +119,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res)
|
callback(res)
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('获取字典数据列表失败:', err)
|
console.error('获取字典数据列表失败:', err)
|
||||||
this.$message.error(err.msg || '获取字典数据列表失败')
|
this.$message.error(err.msg || '获取字典数据列表失败')
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
@@ -137,7 +137,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res)
|
callback(res)
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('获取字典数据详情失败:', err)
|
console.error('获取字典数据详情失败:', err)
|
||||||
this.$message.error(err.msg || '获取字典数据详情失败')
|
this.$message.error(err.msg || '获取字典数据详情失败')
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
@@ -156,7 +156,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res)
|
callback(res)
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('新增字典数据失败:', err)
|
console.error('新增字典数据失败:', err)
|
||||||
this.$message.error(err.msg || '新增字典数据失败')
|
this.$message.error(err.msg || '新增字典数据失败')
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
@@ -175,7 +175,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res)
|
callback(res)
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('更新字典数据失败:', err)
|
console.error('更新字典数据失败:', err)
|
||||||
this.$message.error(err.msg || '更新字典数据失败')
|
this.$message.error(err.msg || '更新字典数据失败')
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
@@ -194,7 +194,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res)
|
callback(res)
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('删除字典数据失败:', err)
|
console.error('删除字典数据失败:', err)
|
||||||
this.$message.error(err.msg || '删除字典数据失败')
|
this.$message.error(err.msg || '删除字典数据失败')
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
@@ -217,7 +217,7 @@ export default {
|
|||||||
reject(new Error(res.data?.msg || '获取字典数据列表失败'))
|
reject(new Error(res.data?.msg || '获取字典数据列表失败'))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('获取字典数据列表失败:', err)
|
console.error('获取字典数据列表失败:', err)
|
||||||
reject(err)
|
reject(err)
|
||||||
}).send()
|
}).send()
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res)
|
callback(res)
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('获取模型列表失败:', err)
|
console.error('获取模型列表失败:', err)
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.getModelList(params, callback)
|
this.getModelList(params, callback)
|
||||||
@@ -34,7 +34,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res.data?.data || [])
|
callback(res.data?.data || [])
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('获取供应器列表失败:', err)
|
console.error('获取供应器列表失败:', err)
|
||||||
this.$message.error('获取供应器列表失败')
|
this.$message.error('获取供应器列表失败')
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
@@ -65,7 +65,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res)
|
callback(res)
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('新增模型失败:', err)
|
console.error('新增模型失败:', err)
|
||||||
this.$message.error(err.msg || '新增模型失败')
|
this.$message.error(err.msg || '新增模型失败')
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
@@ -82,7 +82,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res)
|
callback(res)
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('删除模型失败:', err)
|
console.error('删除模型失败:', err)
|
||||||
this.$message.error(err.msg || '删除模型失败')
|
this.$message.error(err.msg || '删除模型失败')
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
@@ -100,7 +100,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail(() => {
|
.networkFail(() => {
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.getModelNames(modelType, modelName, callback);
|
this.getModelNames(modelType, modelName, callback);
|
||||||
});
|
});
|
||||||
@@ -118,7 +118,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail(() => {
|
.networkFail(() => {
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.getModelVoices(modelId, voiceName, callback);
|
this.getModelVoices(modelId, voiceName, callback);
|
||||||
});
|
});
|
||||||
@@ -133,7 +133,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res)
|
callback(res)
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('获取模型配置失败:', err)
|
console.error('获取模型配置失败:', err)
|
||||||
this.$message.error(err.msg || '获取模型配置失败')
|
this.$message.error(err.msg || '获取模型配置失败')
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
@@ -150,7 +150,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res)
|
callback(res)
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('更新模型状态失败:', err)
|
console.error('更新模型状态失败:', err)
|
||||||
this.$message.error(err.msg || '更新模型状态失败')
|
this.$message.error(err.msg || '更新模型状态失败')
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
@@ -173,7 +173,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('更新模型失败:', err);
|
console.error('更新模型失败:', err);
|
||||||
this.$message.error(err.msg || '更新模型失败');
|
this.$message.error(err.msg || '更新模型失败');
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
@@ -190,7 +190,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res)
|
callback(res)
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('设置默认模型失败:', err)
|
console.error('设置默认模型失败:', err)
|
||||||
this.$message.error(err.msg || '设置默认模型失败')
|
this.$message.error(err.msg || '设置默认模型失败')
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
@@ -219,7 +219,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
this.$message.error(err.msg || '获取供应器列表失败');
|
this.$message.error(err.msg || '获取供应器列表失败');
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.getModelProviders(params, callback);
|
this.getModelProviders(params, callback);
|
||||||
@@ -249,7 +249,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('新增模型供应器失败:', err)
|
console.error('新增模型供应器失败:', err)
|
||||||
this.$message.error(err.msg || '新增模型供应器失败')
|
this.$message.error(err.msg || '新增模型供应器失败')
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
@@ -281,7 +281,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
this.$message.error(err.msg || '更新模型供应器失败')
|
this.$message.error(err.msg || '更新模型供应器失败')
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.updateModelProvider(params, callback);
|
this.updateModelProvider(params, callback);
|
||||||
@@ -298,7 +298,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
this.$message.error(err.msg || '删除模型供应器失败')
|
this.$message.error(err.msg || '删除模型供应器失败')
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.deleteModelProviderByIds(ids, callback)
|
this.deleteModelProviderByIds(ids, callback)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('获取OTA固件列表失败:', err);
|
console.error('获取OTA固件列表失败:', err);
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.getOtaList(params, callback);
|
this.getOtaList(params, callback);
|
||||||
@@ -28,7 +28,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('获取OTA固件信息失败:', err);
|
console.error('获取OTA固件信息失败:', err);
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.getOtaInfo(id, callback);
|
this.getOtaInfo(id, callback);
|
||||||
@@ -45,7 +45,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('保存OTA固件信息失败:', err);
|
console.error('保存OTA固件信息失败:', err);
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.saveOta(entity, callback);
|
this.saveOta(entity, callback);
|
||||||
@@ -62,7 +62,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('更新OTA固件信息失败:', err);
|
console.error('更新OTA固件信息失败:', err);
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.updateOta(id, entity, callback);
|
this.updateOta(id, entity, callback);
|
||||||
@@ -78,7 +78,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('删除OTA固件失败:', err);
|
console.error('删除OTA固件失败:', err);
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.deleteOta(id, callback);
|
this.deleteOta(id, callback);
|
||||||
@@ -97,7 +97,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('上传固件文件失败:', err);
|
console.error('上传固件文件失败:', err);
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.uploadFirmware(file, callback);
|
this.uploadFirmware(file, callback);
|
||||||
@@ -113,7 +113,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('获取下载链接失败:', err);
|
console.error('获取下载链接失败:', err);
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.getDownloadUrl(id, callback);
|
this.getDownloadUrl(id, callback);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {getServiceUrl} from '../api';
|
import { getServiceUrl } from '../api';
|
||||||
import RequestService from '../httpRequest';
|
import RequestService from '../httpRequest';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -18,7 +18,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res.data || []);
|
callback(res.data || []);
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('获取音色列表失败:', err);
|
console.error('获取音色列表失败:', err);
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.getVoiceList(params, callback);
|
this.getVoiceList(params, callback);
|
||||||
@@ -42,7 +42,7 @@ export default {
|
|||||||
.success((res) => {
|
.success((res) => {
|
||||||
callback(res.data);
|
callback(res.data);
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('保存音色失败:', err);
|
console.error('保存音色失败:', err);
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.saveVoice(params, callback);
|
this.saveVoice(params, callback);
|
||||||
@@ -59,7 +59,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('删除音色失败:', err);
|
console.error('删除音色失败:', err);
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.deleteVoice(ids, callback);
|
this.deleteVoice(ids, callback);
|
||||||
@@ -82,7 +82,7 @@ export default {
|
|||||||
.success((res) => {
|
.success((res) => {
|
||||||
callback(res.data);
|
callback(res.data);
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('修改音色失败:', err);
|
console.error('修改音色失败:', err);
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.updateVoice(params, callback);
|
this.updateVoice(params, callback);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import RequestService from '../httpRequest'
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
// 登录
|
// 登录
|
||||||
login(loginForm, callback) {
|
login(loginForm, callback, failCallback) {
|
||||||
RequestService.sendRequest()
|
RequestService.sendRequest()
|
||||||
.url(`${getServiceUrl()}/user/login`)
|
.url(`${getServiceUrl()}/user/login`)
|
||||||
.method('POST')
|
.method('POST')
|
||||||
@@ -13,7 +13,11 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res)
|
callback(res)
|
||||||
})
|
})
|
||||||
.fail(() => {
|
.fail((err) => {
|
||||||
|
RequestService.clearRequestTime()
|
||||||
|
failCallback(err)
|
||||||
|
})
|
||||||
|
.networkFail(() => {
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.login(loginForm, callback)
|
this.login(loginForm, callback)
|
||||||
})
|
})
|
||||||
@@ -34,12 +38,32 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail((err) => { // 添加错误参数
|
.networkFail((err) => { // 添加错误参数
|
||||||
|
|
||||||
}).send()
|
}).send()
|
||||||
},
|
},
|
||||||
|
// 发送短信验证码
|
||||||
|
sendSmsVerification(data, callback, failCallback) {
|
||||||
|
RequestService.sendRequest()
|
||||||
|
.url(`${getServiceUrl()}/user/smsVerification`)
|
||||||
|
.method('POST')
|
||||||
|
.data(data)
|
||||||
|
.success((res) => {
|
||||||
|
RequestService.clearRequestTime()
|
||||||
|
callback(res)
|
||||||
|
})
|
||||||
|
.fail((err) => {
|
||||||
|
RequestService.clearRequestTime()
|
||||||
|
failCallback(err)
|
||||||
|
})
|
||||||
|
.networkFail(() => {
|
||||||
|
RequestService.reAjaxFun(() => {
|
||||||
|
this.sendSmsVerification(data, callback, failCallback)
|
||||||
|
})
|
||||||
|
}).send()
|
||||||
|
},
|
||||||
// 注册账号
|
// 注册账号
|
||||||
register(registerForm, callback) {
|
register(registerForm, callback, failCallback) {
|
||||||
RequestService.sendRequest()
|
RequestService.sendRequest()
|
||||||
.url(`${getServiceUrl()}/user/register`)
|
.url(`${getServiceUrl()}/user/register`)
|
||||||
.method('POST')
|
.method('POST')
|
||||||
@@ -48,7 +72,14 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res)
|
callback(res)
|
||||||
})
|
})
|
||||||
.fail(() => {
|
.fail((err) => {
|
||||||
|
RequestService.clearRequestTime()
|
||||||
|
failCallback(err)
|
||||||
|
})
|
||||||
|
.networkFail(() => {
|
||||||
|
RequestService.reAjaxFun(() => {
|
||||||
|
this.register(registerForm, callback, failCallback)
|
||||||
|
})
|
||||||
}).send()
|
}).send()
|
||||||
},
|
},
|
||||||
// 保存设备配置
|
// 保存设备配置
|
||||||
@@ -61,7 +92,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('保存配置失败:', err);
|
console.error('保存配置失败:', err);
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.saveDeviceConfig(device_id, configData, callback);
|
this.saveDeviceConfig(device_id, configData, callback);
|
||||||
@@ -77,7 +108,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res)
|
callback(res)
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('接口请求失败:', err)
|
console.error('接口请求失败:', err)
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.getUserInfo(callback)
|
this.getUserInfo(callback)
|
||||||
@@ -97,7 +128,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
successCallback(res);
|
successCallback(res);
|
||||||
})
|
})
|
||||||
.fail((error) => {
|
.networkFail((error) => {
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.changePassword(oldPassword, newPassword, successCallback, errorCallback);
|
this.changePassword(oldPassword, newPassword, successCallback, errorCallback);
|
||||||
});
|
});
|
||||||
@@ -115,7 +146,7 @@ export default {
|
|||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
successCallback(res);
|
successCallback(res);
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('修改用户状态失败:', err)
|
console.error('修改用户状态失败:', err)
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.changeUserStatus(status, userIds)
|
this.changeUserStatus(status, userIds)
|
||||||
@@ -131,7 +162,7 @@ export default {
|
|||||||
RequestService.clearRequestTime();
|
RequestService.clearRequestTime();
|
||||||
callback(res);
|
callback(res);
|
||||||
})
|
})
|
||||||
.fail((err) => {
|
.networkFail((err) => {
|
||||||
console.error('获取公共配置失败:', err);
|
console.error('获取公共配置失败:', err);
|
||||||
RequestService.reAjaxFun(() => {
|
RequestService.reAjaxFun(() => {
|
||||||
this.getPubConfig(callback);
|
this.getPubConfig(callback);
|
||||||
|
|||||||
@@ -136,3 +136,67 @@ export function getUUID() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证手机号格式
|
||||||
|
* @param {string} mobile 手机号
|
||||||
|
* @param {string} areaCode 区号
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function validateMobile(mobile, areaCode) {
|
||||||
|
// 移除所有非数字字符
|
||||||
|
const cleanMobile = mobile.replace(/\D/g, '');
|
||||||
|
|
||||||
|
// 根据不同区号使用不同的验证规则
|
||||||
|
switch (areaCode) {
|
||||||
|
case '+86': // 中国大陆
|
||||||
|
return /^1[3-9]\d{9}$/.test(cleanMobile);
|
||||||
|
case '+852': // 中国香港
|
||||||
|
return /^[569]\d{7}$/.test(cleanMobile);
|
||||||
|
case '+853': // 中国澳门
|
||||||
|
return /^6\d{7}$/.test(cleanMobile);
|
||||||
|
case '+886': // 中国台湾
|
||||||
|
return /^9\d{8}$/.test(cleanMobile);
|
||||||
|
case '+1': // 美国/加拿大
|
||||||
|
return /^[2-9]\d{9}$/.test(cleanMobile);
|
||||||
|
case '+44': // 英国
|
||||||
|
return /^7[1-9]\d{8}$/.test(cleanMobile);
|
||||||
|
case '+81': // 日本
|
||||||
|
return /^[7890]\d{8}$/.test(cleanMobile);
|
||||||
|
case '+82': // 韩国
|
||||||
|
return /^1[0-9]\d{7}$/.test(cleanMobile);
|
||||||
|
case '+65': // 新加坡
|
||||||
|
return /^[89]\d{7}$/.test(cleanMobile);
|
||||||
|
case '+61': // 澳大利亚
|
||||||
|
return /^[4578]\d{8}$/.test(cleanMobile);
|
||||||
|
case '+49': // 德国
|
||||||
|
return /^1[5-7]\d{8}$/.test(cleanMobile);
|
||||||
|
case '+33': // 法国
|
||||||
|
return /^[67]\d{8}$/.test(cleanMobile);
|
||||||
|
case '+39': // 意大利
|
||||||
|
return /^3[0-9]\d{8}$/.test(cleanMobile);
|
||||||
|
case '+34': // 西班牙
|
||||||
|
return /^[6-9]\d{8}$/.test(cleanMobile);
|
||||||
|
case '+55': // 巴西
|
||||||
|
return /^[1-9]\d{10}$/.test(cleanMobile);
|
||||||
|
case '+91': // 印度
|
||||||
|
return /^[6-9]\d{9}$/.test(cleanMobile);
|
||||||
|
case '+971': // 阿联酋
|
||||||
|
return /^[5]\d{8}$/.test(cleanMobile);
|
||||||
|
case '+966': // 沙特阿拉伯
|
||||||
|
return /^[5]\d{8}$/.test(cleanMobile);
|
||||||
|
case '+880': // 孟加拉国
|
||||||
|
return /^1[3-9]\d{8}$/.test(cleanMobile);
|
||||||
|
case '+234': // 尼日利亚
|
||||||
|
return /^[789]\d{9}$/.test(cleanMobile);
|
||||||
|
case '+254': // 肯尼亚
|
||||||
|
return /^[17]\d{8}$/.test(cleanMobile);
|
||||||
|
case '+255': // 坦桑尼亚
|
||||||
|
return /^[67]\d{8}$/.test(cleanMobile);
|
||||||
|
case '+7': // 哈萨克斯坦
|
||||||
|
return /^[67]\d{9}$/.test(cleanMobile);
|
||||||
|
default:
|
||||||
|
// 其他国际号码:至少5位,最多15位
|
||||||
|
return /^\d{5,15}$/.test(cleanMobile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,8 +48,7 @@
|
|||||||
<el-table ref="dictDataTable" :data="dictDataList" style="width: 100%"
|
<el-table ref="dictDataTable" :data="dictDataList" style="width: 100%"
|
||||||
v-loading="dictDataLoading" element-loading-text="拼命加载中"
|
v-loading="dictDataLoading" element-loading-text="拼命加载中"
|
||||||
element-loading-spinner="el-icon-loading"
|
element-loading-spinner="el-icon-loading"
|
||||||
element-loading-background="rgba(255, 255, 255, 0.7)"
|
element-loading-background="rgba(255, 255, 255, 0.7)" class="data-table"
|
||||||
class="data-table"
|
|
||||||
header-row-class-name="table-header">
|
header-row-class-name="table-header">
|
||||||
<el-table-column label="选择" align="center" width="55">
|
<el-table-column label="选择" align="center" width="55">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
@@ -546,6 +545,7 @@ export default {
|
|||||||
|
|
||||||
:deep(.el-table__body-wrapper) {
|
:deep(.el-table__body-wrapper) {
|
||||||
max-height: calc(var(--table-max-height) - 40px);
|
max-height: calc(var(--table-max-height) - 40px);
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-table__body) {
|
:deep(.el-table__body) {
|
||||||
|
|||||||
@@ -66,20 +66,7 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
line-height: 35px;
|
line-height: 35px;
|
||||||
margin: 35px 15px 15px;
|
margin: 15px 30px 15px 30px;
|
||||||
}
|
|
||||||
|
|
||||||
.code-send {
|
|
||||||
width: 70px;
|
|
||||||
height: 32px;
|
|
||||||
border-radius: 10px;
|
|
||||||
background: #e6ebff;
|
|
||||||
line-height: 32px;
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 14px;
|
|
||||||
color: #5778ff;
|
|
||||||
flex-shrink: 0;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-box {
|
.input-box {
|
||||||
|
|||||||
@@ -20,10 +20,27 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="padding: 0 30px;">
|
<div style="padding: 0 30px;">
|
||||||
<div class="input-box">
|
<!-- 用户名登录 -->
|
||||||
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/username.png" />
|
<template v-if="!isMobileLogin">
|
||||||
<el-input v-model="form.username" placeholder="请输入用户名" />
|
<div class="input-box">
|
||||||
</div>
|
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/username.png" />
|
||||||
|
<el-input v-model="form.username" placeholder="请输入用户名" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 手机号登录 -->
|
||||||
|
<template v-else>
|
||||||
|
<div class="input-box">
|
||||||
|
<div style="display: flex; align-items: center; width: 100%;">
|
||||||
|
<el-select v-model="form.areaCode" style="width: 220px; margin-right: 10px;">
|
||||||
|
<el-option v-for="item in mobileAreaList" :key="item.key" :label="`${item.name} (${item.key})`"
|
||||||
|
:value="item.key" />
|
||||||
|
</el-select>
|
||||||
|
<el-input v-model="form.mobile" placeholder="请输入手机号码" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<div class="input-box">
|
<div class="input-box">
|
||||||
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/password.png" />
|
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/password.png" />
|
||||||
<el-input v-model="form.password" placeholder="请输入密码" type="password" />
|
<el-input v-model="form.password" placeholder="请输入密码" type="password" />
|
||||||
@@ -42,6 +59,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="login-btn" @click="login">登录</div>
|
<div class="login-btn" @click="login">登录</div>
|
||||||
|
|
||||||
|
<!-- 登录方式切换按钮 -->
|
||||||
|
<div class="login-type-container">
|
||||||
|
<el-tooltip content="手机号码登录" placement="bottom">
|
||||||
|
<el-button :type="isMobileLogin ? 'primary' : 'default'" icon="el-icon-mobile" circle
|
||||||
|
@click="switchLoginType('mobile')"></el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip content="用户名登录" placement="bottom">
|
||||||
|
<el-button :type="!isMobileLogin ? 'primary' : 'default'" icon="el-icon-user" circle
|
||||||
|
@click="switchLoginType('username')"></el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div style="font-size: 14px;color: #979db1;">
|
<div style="font-size: 14px;color: #979db1;">
|
||||||
登录即同意
|
登录即同意
|
||||||
<div style="display: inline-block;color: #5778FF;cursor: pointer;">《用户协议》</div>
|
<div style="display: inline-block;color: #5778FF;cursor: pointer;">《用户协议》</div>
|
||||||
@@ -60,7 +90,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import Api from '@/apis/api';
|
import Api from '@/apis/api';
|
||||||
import VersionFooter from '@/components/VersionFooter.vue';
|
import VersionFooter from '@/components/VersionFooter.vue';
|
||||||
import { getUUID, goToPage, showDanger, showSuccess } from '@/utils';
|
import { getUUID, goToPage, showDanger, showSuccess, validateMobile } from '@/utils';
|
||||||
import { mapState } from 'vuex';
|
import { mapState } from 'vuex';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -70,7 +100,9 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState({
|
...mapState({
|
||||||
allowUserRegister: state => state.pubConfig.allowUserRegister
|
allowUserRegister: state => state.pubConfig.allowUserRegister,
|
||||||
|
enableMobileRegister: state => state.pubConfig.enableMobileRegister,
|
||||||
|
mobileAreaList: state => state.pubConfig.mobileAreaList
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@@ -80,15 +112,21 @@ export default {
|
|||||||
username: '',
|
username: '',
|
||||||
password: '',
|
password: '',
|
||||||
captcha: '',
|
captcha: '',
|
||||||
captchaId: ''
|
captchaId: '',
|
||||||
|
areaCode: '+86',
|
||||||
|
mobile: ''
|
||||||
},
|
},
|
||||||
captchaUuid: '',
|
captchaUuid: '',
|
||||||
captchaUrl: ''
|
captchaUrl: '',
|
||||||
|
isMobileLogin: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.fetchCaptcha();
|
this.fetchCaptcha();
|
||||||
this.$store.dispatch('fetchPubConfig');
|
this.$store.dispatch('fetchPubConfig').then(() => {
|
||||||
|
// 根据配置决定默认登录方式
|
||||||
|
this.isMobileLogin = this.enableMobileRegister;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
fetchCaptcha() {
|
fetchCaptcha() {
|
||||||
@@ -110,6 +148,17 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 切换登录方式
|
||||||
|
switchLoginType(type) {
|
||||||
|
this.isMobileLogin = type === 'mobile';
|
||||||
|
// 清空表单
|
||||||
|
this.form.username = '';
|
||||||
|
this.form.mobile = '';
|
||||||
|
this.form.password = '';
|
||||||
|
this.form.captcha = '';
|
||||||
|
this.fetchCaptcha();
|
||||||
|
},
|
||||||
|
|
||||||
// 封装输入验证逻辑
|
// 封装输入验证逻辑
|
||||||
validateInput(input, message) {
|
validateInput(input, message) {
|
||||||
if (!input.trim()) {
|
if (!input.trim()) {
|
||||||
@@ -120,10 +169,21 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async login() {
|
async login() {
|
||||||
// 验证用户名
|
if (this.isMobileLogin) {
|
||||||
if (!this.validateInput(this.form.username, '用户名不能为空')) {
|
// 手机号登录验证
|
||||||
return;
|
if (!validateMobile(this.form.mobile, this.form.areaCode)) {
|
||||||
|
showDanger('请输入正确的手机号码');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 拼接手机号作为用户名
|
||||||
|
this.form.username = this.form.areaCode + this.form.mobile;
|
||||||
|
} else {
|
||||||
|
// 用户名登录验证
|
||||||
|
if (!this.validateInput(this.form.username, '用户名不能为空')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证密码
|
// 验证密码
|
||||||
if (!this.validateInput(this.form.password, '密码不能为空')) {
|
if (!this.validateInput(this.form.password, '密码不能为空')) {
|
||||||
return;
|
return;
|
||||||
@@ -135,12 +195,12 @@ export default {
|
|||||||
|
|
||||||
this.form.captchaId = this.captchaUuid
|
this.form.captchaId = this.captchaUuid
|
||||||
Api.user.login(this.form, ({ data }) => {
|
Api.user.login(this.form, ({ data }) => {
|
||||||
if (data.code === 0) {
|
showSuccess('登录成功!');
|
||||||
showSuccess('登录成功!');
|
this.$store.commit('setToken', JSON.stringify(data.data));
|
||||||
this.$store.commit('setToken', JSON.stringify(data.data));
|
goToPage('/home');
|
||||||
goToPage('/home');
|
}, (err) => {
|
||||||
} else {
|
if (err.data != null && err.data.msg != null && err.data.msg.indexOf('图形验证码') > -1) {
|
||||||
showDanger(data.msg || '登录失败');
|
this.fetchCaptcha()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -157,4 +217,25 @@ export default {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import './auth.scss'; // 添加这行引用</style>
|
@import './auth.scss';
|
||||||
|
|
||||||
|
.login-type-container {
|
||||||
|
margin: 10px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-button--primary) {
|
||||||
|
background-color: #5778ff;
|
||||||
|
border-color: #5778ff;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
background-color: #4a6ae8;
|
||||||
|
border-color: #4a6ae8;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background-color: #3d5cd6;
|
||||||
|
border-color: #3d5cd6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -23,38 +23,78 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="padding: 0 30px;">
|
<div style="padding: 0 30px;">
|
||||||
<!-- 用户名输入框 -->
|
<form @submit.prevent="register">
|
||||||
<div class="input-box">
|
<!-- 用户名/手机号输入框 -->
|
||||||
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/username.png" />
|
<div class="input-box" v-if="!enableMobileRegister">
|
||||||
<el-input v-model="form.username" placeholder="请输入用户名" />
|
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/username.png" />
|
||||||
</div>
|
<el-input v-model="form.username" placeholder="请输入用户名" />
|
||||||
|
|
||||||
<!-- 密码输入框 -->
|
|
||||||
<div class="input-box">
|
|
||||||
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/password.png" />
|
|
||||||
<el-input v-model="form.password" placeholder="请输入密码" type="password" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 新增确认密码 -->
|
|
||||||
<div class="input-box">
|
|
||||||
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/password.png" />
|
|
||||||
<el-input v-model="form.confirmPassword" placeholder="请确认密码" type="password" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 验证码部分保持相同 -->
|
|
||||||
<div style="display: flex; align-items: center; margin-top: 20px; width: 100%; gap: 10px;">
|
|
||||||
<div class="input-box" style="width: calc(100% - 130px); margin-top: 0;">
|
|
||||||
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/shield.png" />
|
|
||||||
<el-input v-model="form.captcha" placeholder="请输入验证码" style="flex: 1;" />
|
|
||||||
</div>
|
</div>
|
||||||
<img loading="lazy" v-if="captchaUrl" :src="captchaUrl" alt="验证码"
|
|
||||||
style="width: 150px; height: 40px; cursor: pointer;" @click="fetchCaptcha" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 修改底部链接 -->
|
<!-- 手机号注册部分 -->
|
||||||
<div style="font-weight: 400;font-size: 14px;text-align: left;color: #5778ff;margin-top: 20px;">
|
<template v-if="enableMobileRegister">
|
||||||
<div style="cursor: pointer;" @click="goToLogin">已有账号?立即登录</div>
|
<div class="input-box">
|
||||||
</div>
|
<div style="display: flex; align-items: center; width: 100%;">
|
||||||
|
<el-select v-model="form.areaCode" style="width: 220px; margin-right: 10px;">
|
||||||
|
<el-option v-for="item in mobileAreaList" :key="item.key" :label="`${item.name} (${item.key})`"
|
||||||
|
:value="item.key" />
|
||||||
|
</el-select>
|
||||||
|
<el-input v-model="form.mobile" placeholder="请输入手机号码" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="display: flex; align-items: center; margin-top: 20px; width: 100%; gap: 10px;">
|
||||||
|
<div class="input-box" style="width: calc(100% - 130px); margin-top: 0;">
|
||||||
|
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/shield.png" />
|
||||||
|
<el-input v-model="form.captcha" placeholder="请输入验证码" style="flex: 1;" />
|
||||||
|
</div>
|
||||||
|
<img loading="lazy" v-if="captchaUrl" :src="captchaUrl" alt="验证码"
|
||||||
|
style="width: 150px; height: 40px; cursor: pointer;" @click="fetchCaptcha" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 手机验证码 -->
|
||||||
|
|
||||||
|
<div style="display: flex; align-items: center; margin-top: 20px; width: 100%; gap: 10px;">
|
||||||
|
<div class="input-box" style="width: calc(100% - 130px); margin-top: 0;">
|
||||||
|
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/phone.png" />
|
||||||
|
<el-input v-model="form.mobileCaptcha" placeholder="请输入手机验证码" style="flex: 1;" maxlength="6" />
|
||||||
|
</div>
|
||||||
|
<el-button type="primary" class="send-captcha-btn" :disabled="!canSendMobileCaptcha"
|
||||||
|
@click="sendMobileCaptcha">
|
||||||
|
<span>
|
||||||
|
{{ countdown > 0 ? `${countdown}秒后重试` : '发送验证码' }}
|
||||||
|
</span>
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 密码输入框 -->
|
||||||
|
<div class="input-box">
|
||||||
|
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/password.png" />
|
||||||
|
<el-input v-model="form.password" placeholder="请输入密码" type="password" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 新增确认密码 -->
|
||||||
|
<div class="input-box">
|
||||||
|
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/password.png" />
|
||||||
|
<el-input v-model="form.confirmPassword" placeholder="请确认密码" type="password" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 验证码部分保持相同 -->
|
||||||
|
<div v-if="!enableMobileRegister"
|
||||||
|
style="display: flex; align-items: center; margin-top: 20px; width: 100%; gap: 10px;">
|
||||||
|
<div class="input-box" style="width: calc(100% - 130px); margin-top: 0;">
|
||||||
|
<img loading="lazy" alt="" class="input-icon" src="@/assets/login/shield.png" />
|
||||||
|
<el-input v-model="form.captcha" placeholder="请输入验证码" style="flex: 1;" />
|
||||||
|
</div>
|
||||||
|
<img loading="lazy" v-if="captchaUrl" :src="captchaUrl" alt="验证码"
|
||||||
|
style="width: 150px; height: 40px; cursor: pointer;" @click="fetchCaptcha" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 修改底部链接 -->
|
||||||
|
<div style="font-weight: 400;font-size: 14px;text-align: left;color: #5778ff;margin-top: 20px;">
|
||||||
|
<div style="cursor: pointer;" @click="goToLogin">已有账号?立即登录</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 修改按钮文本 -->
|
<!-- 修改按钮文本 -->
|
||||||
@@ -81,7 +121,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import Api from '@/apis/api';
|
import Api from '@/apis/api';
|
||||||
import VersionFooter from '@/components/VersionFooter.vue';
|
import VersionFooter from '@/components/VersionFooter.vue';
|
||||||
import { getUUID, goToPage, showDanger, showSuccess } from '@/utils';
|
import { getUUID, goToPage, showDanger, showSuccess, validateMobile } from '@/utils';
|
||||||
import { mapState } from 'vuex';
|
import { mapState } from 'vuex';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -91,8 +131,13 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState({
|
...mapState({
|
||||||
allowUserRegister: state => state.pubConfig.allowUserRegister
|
allowUserRegister: state => state.pubConfig.allowUserRegister,
|
||||||
})
|
enableMobileRegister: state => state.pubConfig.enableMobileRegister,
|
||||||
|
mobileAreaList: state => state.pubConfig.mobileAreaList
|
||||||
|
}),
|
||||||
|
canSendMobileCaptcha() {
|
||||||
|
return this.countdown === 0 && validateMobile(this.form.mobile, this.form.areaCode);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -101,9 +146,14 @@ export default {
|
|||||||
password: '',
|
password: '',
|
||||||
confirmPassword: '',
|
confirmPassword: '',
|
||||||
captcha: '',
|
captcha: '',
|
||||||
captchaId: ''
|
captchaId: '',
|
||||||
|
areaCode: '+86',
|
||||||
|
mobile: '',
|
||||||
|
mobileCaptcha: ''
|
||||||
},
|
},
|
||||||
captchaUrl: ''
|
captchaUrl: '',
|
||||||
|
countdown: 0,
|
||||||
|
timer: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@@ -141,12 +191,69 @@ export default {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
// 注册逻辑
|
|
||||||
register() {
|
// 发送手机验证码
|
||||||
// 验证用户名
|
sendMobileCaptcha() {
|
||||||
if (!this.validateInput(this.form.username, '用户名不能为空')) {
|
if (!validateMobile(this.form.mobile, this.form.areaCode)) {
|
||||||
|
showDanger('请输入正确的手机号码');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 验证图形验证码
|
||||||
|
if (!this.validateInput(this.form.captcha, '请输入图形验证码')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除可能存在的旧定时器
|
||||||
|
if (this.timer) {
|
||||||
|
clearInterval(this.timer);
|
||||||
|
this.timer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始倒计时
|
||||||
|
this.countdown = 60;
|
||||||
|
this.timer = setInterval(() => {
|
||||||
|
if (this.countdown > 0) {
|
||||||
|
this.countdown--;
|
||||||
|
} else {
|
||||||
|
clearInterval(this.timer);
|
||||||
|
this.timer = null;
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
// 调用发送验证码接口
|
||||||
|
Api.user.sendSmsVerification({
|
||||||
|
phone: this.form.areaCode + this.form.mobile,
|
||||||
|
captcha: this.form.captcha,
|
||||||
|
captchaId: this.form.captchaId
|
||||||
|
}, (res) => {
|
||||||
|
showSuccess('验证码发送成功');
|
||||||
|
}, (err) => {
|
||||||
|
showDanger(err.data.msg || '验证码发送失败');
|
||||||
|
this.countdown = 0;
|
||||||
|
this.fetchCaptcha();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// 注册逻辑
|
||||||
|
register() {
|
||||||
|
if (this.enableMobileRegister) {
|
||||||
|
// 手机号注册验证
|
||||||
|
if (!validateMobile(this.form.mobile, this.form.areaCode)) {
|
||||||
|
showDanger('请输入正确的手机号码');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!this.form.mobileCaptcha) {
|
||||||
|
showDanger('请输入手机验证码');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 用户名注册验证
|
||||||
|
if (!this.validateInput(this.form.username, '用户名不能为空')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 验证密码
|
// 验证密码
|
||||||
if (!this.validateInput(this.form.password, '密码不能为空')) {
|
if (!this.validateInput(this.form.password, '密码不能为空')) {
|
||||||
return;
|
return;
|
||||||
@@ -160,26 +267,50 @@ export default {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.enableMobileRegister) {
|
||||||
|
this.form.username = this.form.areaCode + this.form.mobile
|
||||||
|
}
|
||||||
|
|
||||||
Api.user.register(this.form, ({ data }) => {
|
Api.user.register(this.form, ({ data }) => {
|
||||||
if (data.code === 0) {
|
showSuccess('注册成功!')
|
||||||
showSuccess('注册成功!')
|
goToPage('/login')
|
||||||
goToPage('/login')
|
}, (err) => {
|
||||||
} else {
|
showDanger(err.data.msg || '注册失败')
|
||||||
showDanger(data.msg || '注册失败')
|
if (err.data != null && err.data.msg != null && err.data.msg.indexOf('图形验证码') > -1) {
|
||||||
this.fetchCaptcha()
|
this.fetchCaptcha()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
setTimeout(() => {
|
|
||||||
this.fetchCaptcha()
|
|
||||||
}, 1000)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
goToLogin() {
|
goToLogin() {
|
||||||
goToPage('/login')
|
goToPage('/login')
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
if (this.timer) {
|
||||||
|
clearInterval(this.timer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import './auth.scss'; // 修改为导入新建的SCSS文件</style>
|
@import './auth.scss';
|
||||||
|
|
||||||
|
.send-captcha-btn {
|
||||||
|
margin-right: -5px;
|
||||||
|
min-width: 100px;
|
||||||
|
height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
background: rgb(87, 120, 255);
|
||||||
|
border: none;
|
||||||
|
padding: 0px;
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
background: #c0c4cc;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user