From 5ad0473e03d8c00146d9d3311a0294631bb75ce7 Mon Sep 17 00:00:00 2001 From: wwb <782276617@qq.com> Date: Sun, 8 Dec 2024 20:45:23 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=BF=98=E8=AE=B0=E5=AF=86?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../util/validation/ValidationUtils.java | 9 + .../framework/common/validation/Email.java | 28 ++ .../common/validation/EmailValidator.java | 25 ++ .../module/system/api/mail/MailCodeApi.java | 43 +++ .../api/mail/dto/code/MailCodeSendReqDTO.java | 4 +- .../api/mail/dto/code/MailCodeUseReqDTO.java | 3 +- .../system/enums/mail/MailSceneEnum.java | 8 +- .../system/api/mail/MailCodeApiImpl.java | 44 +++ .../controller/admin/auth/AuthController.java | 21 ++ .../admin/auth/vo/AuthLoginReqVO.java | 4 +- .../admin/auth/vo/AuthMailModifyPwdReqVO.java | 37 +++ .../admin/auth/vo/AuthMailSendReqVO.java | 33 +++ .../system/convert/auth/AuthConvert.java | 6 + .../dal/dataobject/mail/MailCodeDO.java | 65 +++++ .../system/dal/mysql/mail/MailCodeMapper.java | 29 ++ .../system/service/auth/AdminAuthService.java | 10 + .../service/auth/AdminAuthServiceImpl.java | 50 ++++ .../system/service/mail/MailCodeService.java | 6 +- .../service/mail/MailCodeServiceImpl.java | 61 ++-- .../service/mail/MailTemplateServiceImpl.java | 9 +- .../system/service/user/AdminUserService.java | 11 + .../service/user/AdminUserServiceImpl.java | 5 + .../src/main/resources/application.yaml | 4 +- .../hangtag-ui-front/src/api/login/index.ts | 23 ++ hangtag-ui/hangtag-ui-front/src/locales/en.ts | 9 +- .../hangtag-ui-front/src/locales/zh-CN.ts | 5 +- .../src/views/Login/Login.vue | 8 +- .../Login/components/ForgetPasswordForm.vue | 262 ++++++++++++++++++ .../src/views/Login/components/LoginForm.vue | 6 +- .../src/views/Login/components/index.ts | 3 +- 30 files changed, 780 insertions(+), 51 deletions(-) create mode 100644 hangtag-framework/hangtag-common/src/main/java/cn/hangtag/framework/common/validation/Email.java create mode 100644 hangtag-framework/hangtag-common/src/main/java/cn/hangtag/framework/common/validation/EmailValidator.java create mode 100644 hangtag-module-system/hangtag-module-system-api/src/main/java/cn/hangtag/module/system/api/mail/MailCodeApi.java create mode 100644 hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/api/mail/MailCodeApiImpl.java create mode 100644 hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/controller/admin/auth/vo/AuthMailModifyPwdReqVO.java create mode 100644 hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/controller/admin/auth/vo/AuthMailSendReqVO.java create mode 100644 hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/dal/dataobject/mail/MailCodeDO.java create mode 100644 hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/dal/mysql/mail/MailCodeMapper.java create mode 100644 hangtag-ui/hangtag-ui-front/src/views/Login/components/ForgetPasswordForm.vue diff --git a/hangtag-framework/hangtag-common/src/main/java/cn/hangtag/framework/common/util/validation/ValidationUtils.java b/hangtag-framework/hangtag-common/src/main/java/cn/hangtag/framework/common/util/validation/ValidationUtils.java index fdb573f..a82b2ab 100644 --- a/hangtag-framework/hangtag-common/src/main/java/cn/hangtag/framework/common/util/validation/ValidationUtils.java +++ b/hangtag-framework/hangtag-common/src/main/java/cn/hangtag/framework/common/util/validation/ValidationUtils.java @@ -24,11 +24,20 @@ public class ValidationUtils { private static final Pattern PATTERN_XML_NCNAME = Pattern.compile("[a-zA-Z_][\\-_.0-9_a-zA-Z$]*"); + private static final Pattern PATTERN_EMAIL = Pattern.compile("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"); + public static boolean isMobile(String mobile) { return StringUtils.hasText(mobile) && PATTERN_MOBILE.matcher(mobile).matches(); } + public static boolean isEmail(String email) { + + return StringUtils.hasText(email) + && PATTERN_EMAIL.matcher(email).matches(); + } + + public static boolean isURL(String url) { return StringUtils.hasText(url) && PATTERN_URL.matcher(url).matches(); diff --git a/hangtag-framework/hangtag-common/src/main/java/cn/hangtag/framework/common/validation/Email.java b/hangtag-framework/hangtag-common/src/main/java/cn/hangtag/framework/common/validation/Email.java new file mode 100644 index 0000000..fecb755 --- /dev/null +++ b/hangtag-framework/hangtag-common/src/main/java/cn/hangtag/framework/common/validation/Email.java @@ -0,0 +1,28 @@ +package cn.hangtag.framework.common.validation; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.*; + +@Target({ + ElementType.METHOD, + ElementType.FIELD, + ElementType.ANNOTATION_TYPE, + ElementType.CONSTRUCTOR, + ElementType.PARAMETER, + ElementType.TYPE_USE +}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Constraint( + validatedBy = EmailValidator.class +) +public @interface Email { + + String message() default "邮箱格式不正确"; + + Class[] groups() default {}; + + Class[] payload() default {}; + +} diff --git a/hangtag-framework/hangtag-common/src/main/java/cn/hangtag/framework/common/validation/EmailValidator.java b/hangtag-framework/hangtag-common/src/main/java/cn/hangtag/framework/common/validation/EmailValidator.java new file mode 100644 index 0000000..367aa1e --- /dev/null +++ b/hangtag-framework/hangtag-common/src/main/java/cn/hangtag/framework/common/validation/EmailValidator.java @@ -0,0 +1,25 @@ +package cn.hangtag.framework.common.validation; + +import cn.hangtag.framework.common.util.validation.ValidationUtils; +import cn.hutool.core.util.StrUtil; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +public class EmailValidator implements ConstraintValidator { + + @Override + public void initialize(Email annotation) { + } + + @Override + public boolean isValid(String value, ConstraintValidatorContext context) { + // 如果手机号为空,默认不校验,即校验通过 + if (StrUtil.isEmpty(value)) { + return true; + } + // 校验手机 + return ValidationUtils.isEmail(value); + } + +} diff --git a/hangtag-module-system/hangtag-module-system-api/src/main/java/cn/hangtag/module/system/api/mail/MailCodeApi.java b/hangtag-module-system/hangtag-module-system-api/src/main/java/cn/hangtag/module/system/api/mail/MailCodeApi.java new file mode 100644 index 0000000..34be135 --- /dev/null +++ b/hangtag-module-system/hangtag-module-system-api/src/main/java/cn/hangtag/module/system/api/mail/MailCodeApi.java @@ -0,0 +1,43 @@ +package cn.hangtag.module.system.api.mail; + +import cn.hangtag.framework.common.exception.ServiceException; +import cn.hangtag.module.system.api.mail.dto.code.MailCodeSendReqDTO; +import cn.hangtag.module.system.api.mail.dto.code.MailCodeUseReqDTO; +import cn.hangtag.module.system.api.mail.dto.code.MailCodeValidateReqDTO; +import cn.hangtag.module.system.api.sms.dto.code.SmsCodeSendReqDTO; +import cn.hangtag.module.system.api.sms.dto.code.SmsCodeUseReqDTO; +import cn.hangtag.module.system.api.sms.dto.code.SmsCodeValidateReqDTO; + +import javax.validation.Valid; + +/** + * 短信验证码 API 接口 + * + * @author 芋道源码 + */ +public interface MailCodeApi { + + /** + * 创建邮箱验证码,并进行发送 + * + * @param reqDTO 发送请求 + */ + void sendMailCode(@Valid MailCodeSendReqDTO reqDTO); + + /** + * 验证邮箱验证码,并进行使用 + * 如果正确,则将验证码标记成已使用 + * 如果错误,则抛出 {@link ServiceException} 异常 + * + * @param reqDTO 使用请求 + */ + void useMailCode(@Valid MailCodeUseReqDTO reqDTO); + + /** + * 检查验证码是否有效 + * + * @param reqDTO 校验请求 + */ + void validateMailCode(@Valid MailCodeValidateReqDTO reqDTO); + +} diff --git a/hangtag-module-system/hangtag-module-system-api/src/main/java/cn/hangtag/module/system/api/mail/dto/code/MailCodeSendReqDTO.java b/hangtag-module-system/hangtag-module-system-api/src/main/java/cn/hangtag/module/system/api/mail/dto/code/MailCodeSendReqDTO.java index f2de4df..a184806 100644 --- a/hangtag-module-system/hangtag-module-system-api/src/main/java/cn/hangtag/module/system/api/mail/dto/code/MailCodeSendReqDTO.java +++ b/hangtag-module-system/hangtag-module-system-api/src/main/java/cn/hangtag/module/system/api/mail/dto/code/MailCodeSendReqDTO.java @@ -1,7 +1,7 @@ package cn.hangtag.module.system.api.mail.dto.code; +import cn.hangtag.framework.common.validation.Email; import cn.hangtag.framework.common.validation.InEnum; -import cn.hangtag.framework.common.validation.Mobile; import cn.hangtag.module.system.enums.mail.MailSceneEnum; import lombok.Data; @@ -19,7 +19,7 @@ public class MailCodeSendReqDTO { /** * 邮箱 */ - @Mobile + @Email @NotEmpty(message = "邮箱不能为空") private String mail; /** diff --git a/hangtag-module-system/hangtag-module-system-api/src/main/java/cn/hangtag/module/system/api/mail/dto/code/MailCodeUseReqDTO.java b/hangtag-module-system/hangtag-module-system-api/src/main/java/cn/hangtag/module/system/api/mail/dto/code/MailCodeUseReqDTO.java index b12378f..c40deb9 100644 --- a/hangtag-module-system/hangtag-module-system-api/src/main/java/cn/hangtag/module/system/api/mail/dto/code/MailCodeUseReqDTO.java +++ b/hangtag-module-system/hangtag-module-system-api/src/main/java/cn/hangtag/module/system/api/mail/dto/code/MailCodeUseReqDTO.java @@ -1,5 +1,6 @@ package cn.hangtag.module.system.api.mail.dto.code; +import cn.hangtag.framework.common.validation.Email; import cn.hangtag.framework.common.validation.InEnum; import cn.hangtag.framework.common.validation.Mobile; import cn.hangtag.module.system.enums.sms.SmsSceneEnum; @@ -19,7 +20,7 @@ public class MailCodeUseReqDTO { /** * 邮箱 */ - @Mobile + @Email @NotEmpty(message = "邮箱不能为空") private String mail; /** diff --git a/hangtag-module-system/hangtag-module-system-api/src/main/java/cn/hangtag/module/system/enums/mail/MailSceneEnum.java b/hangtag-module-system/hangtag-module-system-api/src/main/java/cn/hangtag/module/system/enums/mail/MailSceneEnum.java index 00f8a95..36e1163 100644 --- a/hangtag-module-system/hangtag-module-system-api/src/main/java/cn/hangtag/module/system/enums/mail/MailSceneEnum.java +++ b/hangtag-module-system/hangtag-module-system-api/src/main/java/cn/hangtag/module/system/enums/mail/MailSceneEnum.java @@ -8,7 +8,7 @@ import lombok.Getter; import java.util.Arrays; /** - * 用户短信验证码发送场景的枚举 + * 用户邮箱验证码发送场景的枚举 * * @author 芋道源码 */ @@ -16,12 +16,12 @@ import java.util.Arrays; @AllArgsConstructor public enum MailSceneEnum implements IntArrayValuable { - MEMBER_LOGIN(1, "user-sms-login", "会员用户 - 邮箱登陆"), - MEMBER_UPDATE_MOBILE(2, "user-update-mobile", "会员用户 - 修改手机"), + MEMBER_LOGIN(1, "user-mail-login", "会员用户 - 邮箱登陆"), + MEMBER_UPDATE_MOBILE(2, "user-update-mail", "会员用户 - 修改手机"), MEMBER_UPDATE_PASSWORD(3, "user-update-password", "会员用户 - 修改密码"), MEMBER_RESET_PASSWORD(4, "user-reset-password", "会员用户 - 忘记密码"), - ADMIN_MEMBER_LOGIN(21, "admin-sms-login", "后台用户 - 邮箱登录"); + ADMIN_MEMBER_LOGIN(21, "admin-mail-login", "后台用户 - 邮箱登录"); public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(MailSceneEnum::getScene).toArray(); diff --git a/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/api/mail/MailCodeApiImpl.java b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/api/mail/MailCodeApiImpl.java new file mode 100644 index 0000000..8b6b3c4 --- /dev/null +++ b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/api/mail/MailCodeApiImpl.java @@ -0,0 +1,44 @@ +package cn.hangtag.module.system.api.mail; + +import cn.hangtag.module.system.api.mail.dto.code.MailCodeSendReqDTO; +import cn.hangtag.module.system.api.mail.dto.code.MailCodeUseReqDTO; +import cn.hangtag.module.system.api.mail.dto.code.MailCodeValidateReqDTO; +import cn.hangtag.module.system.api.sms.SmsCodeApi; +import cn.hangtag.module.system.api.sms.dto.code.SmsCodeSendReqDTO; +import cn.hangtag.module.system.api.sms.dto.code.SmsCodeUseReqDTO; +import cn.hangtag.module.system.api.sms.dto.code.SmsCodeValidateReqDTO; +import cn.hangtag.module.system.service.mail.MailCodeService; +import cn.hangtag.module.system.service.sms.SmsCodeService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +/** + * 短信验证码 API 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class MailCodeApiImpl implements MailCodeApi { + + @Resource + private MailCodeService mailCodeService; + + @Override + public void sendMailCode(MailCodeSendReqDTO reqDTO) { + mailCodeService.sendMailCode(reqDTO); + } + + @Override + public void useMailCode(MailCodeUseReqDTO reqDTO) { + mailCodeService.useMailCode(reqDTO); + } + + @Override + public void validateMailCode(MailCodeValidateReqDTO reqDTO) { + mailCodeService.validateMailCode(reqDTO); + } + +} diff --git a/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/controller/admin/auth/AuthController.java b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/controller/admin/auth/AuthController.java index e3c4ea6..e5a1f39 100644 --- a/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/controller/admin/auth/AuthController.java +++ b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/controller/admin/auth/AuthController.java @@ -146,6 +146,27 @@ public class AuthController { return success(true); } + + // ========== 邮箱相关 ========== + + @PostMapping("/send-mail-code") + @PermitAll + @Operation(summary = "发送邮箱验证码") + public CommonResult sendForgetPasswordEmailCode(@RequestBody @Valid AuthMailSendReqVO reqVO) { + authService.sendMailCode(reqVO); + return success(true); + } + + @PostMapping("/mail-modifypwd") + @PermitAll + @Operation(summary = "使用邮箱验证码修改密码") + public CommonResult smsLogin(@RequestBody @Valid AuthMailModifyPwdReqVO reqVO) { + authService.mailResetPwd(reqVO); + return success(true); + } + + + // ========== 社交登录相关 ========== @GetMapping("/social-auth-redirect") diff --git a/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/controller/admin/auth/vo/AuthLoginReqVO.java b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/controller/admin/auth/vo/AuthLoginReqVO.java index 2cb5522..8a02415 100644 --- a/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/controller/admin/auth/vo/AuthLoginReqVO.java +++ b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/controller/admin/auth/vo/AuthLoginReqVO.java @@ -23,8 +23,8 @@ public class AuthLoginReqVO { @Schema(description = "账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "hangtagyuanma") @NotEmpty(message = "登录账号不能为空") - @Length(min = 4, max = 16, message = "账号长度为 4-16 位") - @Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母") + //@Length(min = 4, max = 16, message = "账号长度为 4-16 位") + //@Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母") private String username; @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "buzhidao") diff --git a/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/controller/admin/auth/vo/AuthMailModifyPwdReqVO.java b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/controller/admin/auth/vo/AuthMailModifyPwdReqVO.java new file mode 100644 index 0000000..c634816 --- /dev/null +++ b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/controller/admin/auth/vo/AuthMailModifyPwdReqVO.java @@ -0,0 +1,37 @@ +package cn.hangtag.module.system.controller.admin.auth.vo; + +import cn.hangtag.framework.common.validation.Email; +import cn.hangtag.framework.common.validation.Mobile; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; + +@Schema(description = "管理后台 - 邮箱验证码的重置密码 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthMailModifyPwdReqVO { + + @Schema(description = "邮箱账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "xxxxx@qq.com") + @NotEmpty(message = "邮箱账号不能为空") + @Email + private String mail; + + @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "xxxxx@qq.com") + @NotEmpty(message = "密码不能为空") + private String password; + + @Schema(description = "确认密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "xxxxx@qq.com") + @NotEmpty(message = "确认密码不能为空") + private String checkpassword; + + @Schema(description = "短信验证码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotEmpty(message = "验证码不能为空") + private String code; + +} diff --git a/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/controller/admin/auth/vo/AuthMailSendReqVO.java b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/controller/admin/auth/vo/AuthMailSendReqVO.java new file mode 100644 index 0000000..853c96c --- /dev/null +++ b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/controller/admin/auth/vo/AuthMailSendReqVO.java @@ -0,0 +1,33 @@ +package cn.hangtag.module.system.controller.admin.auth.vo; + +import cn.hangtag.framework.common.validation.Email; +import cn.hangtag.framework.common.validation.InEnum; +import cn.hangtag.framework.common.validation.Mobile; +import cn.hangtag.module.system.enums.mail.MailSceneEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 发送手机验证码 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class AuthMailSendReqVO { + + @Schema(description = "邮箱账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "xxxxx@qq.com") + @NotEmpty(message = "邮箱账号不能为空") + @Email + private String mail; + + @Schema(description = "邮箱场景", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "发送场景不能为空") + @InEnum(MailSceneEnum.class) + private Integer scene; + +} diff --git a/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/convert/auth/AuthConvert.java b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/convert/auth/AuthConvert.java index 940b665..b1ac883 100644 --- a/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/convert/auth/AuthConvert.java +++ b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/convert/auth/AuthConvert.java @@ -1,5 +1,7 @@ package cn.hangtag.module.system.convert.auth; +import cn.hangtag.module.system.api.mail.dto.code.MailCodeSendReqDTO; +import cn.hangtag.module.system.api.mail.dto.code.MailCodeUseReqDTO; import cn.hutool.core.collection.CollUtil; import cn.hangtag.framework.common.util.object.BeanUtils; import cn.hangtag.module.system.api.sms.dto.code.SmsCodeSendReqDTO; @@ -85,4 +87,8 @@ public interface AuthConvert { SmsCodeUseReqDTO convert(AuthSmsLoginReqVO reqVO, Integer scene, String usedIp); + MailCodeSendReqDTO convert(AuthMailSendReqVO reqVO); + + MailCodeUseReqDTO convert(AuthMailModifyPwdReqVO reqVO, Integer scene, String usedIp); + } diff --git a/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/dal/dataobject/mail/MailCodeDO.java b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/dal/dataobject/mail/MailCodeDO.java new file mode 100644 index 0000000..f0c70ce --- /dev/null +++ b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/dal/dataobject/mail/MailCodeDO.java @@ -0,0 +1,65 @@ +package cn.hangtag.module.system.dal.dataobject.mail; + +import cn.hangtag.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 邮箱验证码 DO + * + * idx_mobile 索引:基于 {@link #mobile} 字段 + * + * @author 芋道源码 + */ +@TableName("system_mail_code") +@KeySequence("system_mail_code_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MailCodeDO extends BaseDO { + + /** + * 编号 + */ + private Long id; + /** + * 邮箱号 + */ + private String mail; + /** + * 验证码 + */ + private String code; + /** + * 发送场景 + * + * 枚举 {@link MailCodeDO} + */ + private Integer scene; + /** + * 创建 IP + */ + private String createIp; + /** + * 今日发送的第几条 + */ + private Integer todayIndex; + /** + * 是否使用 + */ + private Boolean used; + /** + * 使用时间 + */ + private LocalDateTime usedTime; + /** + * 使用 IP + */ + private String usedIp; + +} diff --git a/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/dal/mysql/mail/MailCodeMapper.java b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/dal/mysql/mail/MailCodeMapper.java new file mode 100644 index 0000000..7a64ee4 --- /dev/null +++ b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/dal/mysql/mail/MailCodeMapper.java @@ -0,0 +1,29 @@ +package cn.hangtag.module.system.dal.mysql.mail; + +import cn.hangtag.framework.mybatis.core.mapper.BaseMapperX; +import cn.hangtag.framework.mybatis.core.query.QueryWrapperX; +import cn.hangtag.module.system.dal.dataobject.mail.MailCodeDO; +import cn.hangtag.module.system.dal.dataobject.sms.SmsCodeDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface MailCodeMapper extends BaseMapperX { + + /** + * 获得手机号的最后一个手机验证码 + * + * @param mail 手机号 + * @param scene 发送场景,选填 + * @param code 验证码 选填 + * @return 手机验证码 + */ + default MailCodeDO selectLastByMail(String mail, String code, Integer scene) { + return selectOne(new QueryWrapperX() + .eq("mail", mail) + .eqIfPresent("scene", scene) + .eqIfPresent("code", code) + .orderByDesc("id") + .limitN(1)); + } + +} diff --git a/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/auth/AdminAuthService.java b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/auth/AdminAuthService.java index a03f502..a2b2e0b 100644 --- a/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/auth/AdminAuthService.java +++ b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/auth/AdminAuthService.java @@ -70,4 +70,14 @@ public interface AdminAuthService { */ AuthLoginRespVO refreshToken(String refreshToken); + + /** + * 邮箱验证码发送 + * + * @param reqVO 发送请求 + */ + void sendMailCode(AuthMailSendReqVO reqVO); + + + boolean mailResetPwd(AuthMailModifyPwdReqVO reqVO); } diff --git a/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/auth/AdminAuthServiceImpl.java b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/auth/AdminAuthServiceImpl.java index 81a594a..4b38f26 100644 --- a/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/auth/AdminAuthServiceImpl.java +++ b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/auth/AdminAuthServiceImpl.java @@ -1,5 +1,8 @@ package cn.hangtag.module.system.service.auth; +import cn.hangtag.module.system.api.mail.MailCodeApi; +import cn.hangtag.module.system.dal.mysql.user.AdminUserMapper; +import cn.hangtag.module.system.enums.mail.MailSceneEnum; import cn.hutool.core.util.ObjectUtil; import cn.hangtag.framework.common.enums.CommonStatusEnum; import cn.hangtag.framework.common.enums.UserTypeEnum; @@ -29,6 +32,7 @@ import com.xingyuv.captcha.model.vo.CaptchaVO; import com.xingyuv.captcha.service.CaptchaService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import javax.annotation.Resource; @@ -64,6 +68,13 @@ public class AdminAuthServiceImpl implements AdminAuthService { private CaptchaService captchaService; @Resource private SmsCodeApi smsCodeApi; + @Resource + private MailCodeApi mailCodeApi; + @Resource + private PasswordEncoder passwordEncoder; + @Resource + private AdminUserMapper userMapper; + /** * 验证码的开关,默认为 true @@ -247,4 +258,43 @@ public class AdminAuthServiceImpl implements AdminAuthService { return UserTypeEnum.ADMIN; } + + @Override + public void sendMailCode(AuthMailSendReqVO reqVO) { + // 登录场景,验证是否存在 + if (userService.getUserByMail(reqVO.getMail()) == null) { + throw exception(MAIL_ACCOUNT_NOT_EXISTS); + } + // 发送验证码 + mailCodeApi.sendMailCode(AuthConvert.INSTANCE.convert(reqVO).setCreateIp(getClientIP())); + } + + @Override + public boolean mailResetPwd(AuthMailModifyPwdReqVO reqVO) { + // 校验验证码 + mailCodeApi.useMailCode(AuthConvert.INSTANCE.convert(reqVO, MailSceneEnum.MEMBER_RESET_PASSWORD.getScene(), getClientIP())); + + // 获得用户信息 + AdminUserDO user = userService.getUserByMail(reqVO.getMail()); + if (user == null) { + throw exception(USER_NOT_EXISTS); + } + // 执行更新 + user.setPassword(encodePassword(reqVO.getPassword())); // 加密密码 + int i = userMapper.updateById(user); + return true; + } + + + /** + * 对密码进行加密 + * + * @param password 密码 + * @return 加密后的密码 + */ + private String encodePassword(String password) { + return passwordEncoder.encode(password); + } + + } diff --git a/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/mail/MailCodeService.java b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/mail/MailCodeService.java index 712edef..9935349 100644 --- a/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/mail/MailCodeService.java +++ b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/mail/MailCodeService.java @@ -2,6 +2,8 @@ package cn.hangtag.module.system.service.mail; import cn.hangtag.framework.common.exception.ServiceException; import cn.hangtag.module.system.api.mail.dto.code.MailCodeSendReqDTO; +import cn.hangtag.module.system.api.mail.dto.code.MailCodeUseReqDTO; +import cn.hangtag.module.system.api.mail.dto.code.MailCodeValidateReqDTO; import cn.hangtag.module.system.api.sms.dto.code.SmsCodeUseReqDTO; import cn.hangtag.module.system.api.sms.dto.code.SmsCodeValidateReqDTO; @@ -28,13 +30,13 @@ public interface MailCodeService { * * @param reqDTO 使用请求 */ - void useMailCode(@Valid SmsCodeUseReqDTO reqDTO); + void useMailCode(@Valid MailCodeUseReqDTO reqDTO); /** * 检查验证码是否有效 * * @param reqDTO 校验请求 */ - void validateMailCode(@Valid SmsCodeValidateReqDTO reqDTO); + void validateMailCode(@Valid MailCodeValidateReqDTO reqDTO); } diff --git a/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/mail/MailCodeServiceImpl.java b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/mail/MailCodeServiceImpl.java index 69eda20..c26c7e5 100644 --- a/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/mail/MailCodeServiceImpl.java +++ b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/mail/MailCodeServiceImpl.java @@ -1,13 +1,14 @@ package cn.hangtag.module.system.service.mail; import cn.hangtag.module.system.api.mail.dto.code.MailCodeSendReqDTO; -import cn.hangtag.module.system.api.sms.dto.code.SmsCodeUseReqDTO; -import cn.hangtag.module.system.api.sms.dto.code.SmsCodeValidateReqDTO; +import cn.hangtag.module.system.api.mail.dto.code.MailCodeUseReqDTO; +import cn.hangtag.module.system.api.mail.dto.code.MailCodeValidateReqDTO; +import cn.hangtag.module.system.dal.dataobject.mail.MailCodeDO; import cn.hangtag.module.system.dal.dataobject.sms.SmsCodeDO; -import cn.hangtag.module.system.dal.mysql.sms.SmsCodeMapper; +import cn.hangtag.module.system.dal.mysql.mail.MailCodeMapper; +import cn.hangtag.module.system.enums.mail.MailSceneEnum; import cn.hangtag.module.system.enums.sms.SmsSceneEnum; import cn.hangtag.module.system.framework.sms.config.SmsCodeProperties; -import cn.hangtag.module.system.service.sms.SmsCodeService; import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.map.MapUtil; @@ -16,6 +17,7 @@ import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import java.time.LocalDateTime; +import java.util.LinkedHashMap; import static cn.hangtag.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.hangtag.framework.common.util.date.DateUtils.isToday; @@ -35,32 +37,39 @@ public class MailCodeServiceImpl implements MailCodeService { private SmsCodeProperties smsCodeProperties; @Resource - private SmsCodeMapper smsCodeMapper; + private MailCodeMapper mailCodeMapper; @Resource private MailSendService mailSendService; @Override public void sendMailCode(MailCodeSendReqDTO reqDTO) { - SmsSceneEnum sceneEnum = SmsSceneEnum.getCodeByScene(reqDTO.getScene()); + MailSceneEnum sceneEnum = MailSceneEnum.getCodeByScene(reqDTO.getScene()); Assert.notNull(sceneEnum, "验证码场景({}) 查找不到配置", reqDTO.getScene()); // 创建验证码 String code = createMailCode(reqDTO.getMail(), reqDTO.getScene(), reqDTO.getCreateIp()); + + LinkedHashMap params = new LinkedHashMap<>(); + params.put("key1",reqDTO.getMail()); + params.put("key2",reqDTO.getMail()); + params.put("key3",code); + String templateCode = sceneEnum.getTemplateCode(); + // 发送验证码 mailSendService.sendSingleMail(reqDTO.getMail(), null, null, - sceneEnum.getTemplateCode(), MapUtil.of("code", code)); + sceneEnum.getTemplateCode(), params); } private String createMailCode(String mobile, Integer scene, String ip) { // 校验是否可以发送验证码,不用筛选场景 - SmsCodeDO lastSmsCode = smsCodeMapper.selectLastByMobile(mobile, null, null); - if (lastSmsCode != null) { - if (LocalDateTimeUtil.between(lastSmsCode.getCreateTime(), LocalDateTime.now()).toMillis() + MailCodeDO lastMailCode = mailCodeMapper.selectLastByMail(mobile, null, null); + if (lastMailCode != null) { + if (LocalDateTimeUtil.between(lastMailCode.getCreateTime(), LocalDateTime.now()).toMillis() < smsCodeProperties.getSendFrequency().toMillis()) { // 发送过于频繁 throw exception(SMS_CODE_SEND_TOO_FAST); } - if (isToday(lastSmsCode.getCreateTime()) && // 必须是今天,才能计算超过当天的上限 - lastSmsCode.getTodayIndex() >= smsCodeProperties.getSendMaximumQuantityPerDay()) { // 超过当天发送的上限。 + if (isToday(lastMailCode.getCreateTime()) && // 必须是今天,才能计算超过当天的上限 + lastMailCode.getTodayIndex() >= smsCodeProperties.getSendMaximumQuantityPerDay()) { // 超过当天发送的上限。 throw exception(SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY); } // TODO 芋艿:提升,每个 IP 每天可发送数量 @@ -70,44 +79,44 @@ public class MailCodeServiceImpl implements MailCodeService { // 创建验证码记录 String code = String.format("%0" + smsCodeProperties.getEndCode().toString().length() + "d", randomInt(smsCodeProperties.getBeginCode(), smsCodeProperties.getEndCode() + 1)); - SmsCodeDO newSmsCode = SmsCodeDO.builder().mobile(mobile).code(code).scene(scene) - .todayIndex(lastSmsCode != null && isToday(lastSmsCode.getCreateTime()) ? lastSmsCode.getTodayIndex() + 1 : 1) + MailCodeDO newSmsCode = MailCodeDO.builder().mail(mobile).code(code).scene(scene) + .todayIndex(lastMailCode != null && isToday(lastMailCode.getCreateTime()) ? lastMailCode.getTodayIndex() + 1 : 1) .createIp(ip).used(false).build(); - smsCodeMapper.insert(newSmsCode); + mailCodeMapper.insert(newSmsCode); return code; } @Override - public void useMailCode(SmsCodeUseReqDTO reqDTO) { + public void useMailCode(MailCodeUseReqDTO reqDTO) { // 检测验证码是否有效 - SmsCodeDO lastSmsCode = validateMailCode0(reqDTO.getMobile(), reqDTO.getCode(), reqDTO.getScene()); + MailCodeDO lastMailCode = validateMailCode0(reqDTO.getMail(), reqDTO.getCode(), reqDTO.getScene()); // 使用验证码 - smsCodeMapper.updateById(SmsCodeDO.builder().id(lastSmsCode.getId()) + mailCodeMapper.updateById(MailCodeDO.builder().id(lastMailCode.getId()) .used(true).usedTime(LocalDateTime.now()).usedIp(reqDTO.getUsedIp()).build()); } @Override - public void validateMailCode(SmsCodeValidateReqDTO reqDTO) { - validateMailCode0(reqDTO.getMobile(), reqDTO.getCode(), reqDTO.getScene()); + public void validateMailCode(MailCodeValidateReqDTO reqDTO) { + validateMailCode0(reqDTO.getMail(), reqDTO.getCode(), reqDTO.getScene()); } - private SmsCodeDO validateMailCode0(String mobile, String code, Integer scene) { + private MailCodeDO validateMailCode0(String mobile, String code, Integer scene) { // 校验验证码 - SmsCodeDO lastSmsCode = smsCodeMapper.selectLastByMobile(mobile, code, scene); + MailCodeDO lastMailCode = mailCodeMapper.selectLastByMail(mobile, code, scene); // 若验证码不存在,抛出异常 - if (lastSmsCode == null) { + if (lastMailCode == null) { throw exception(SMS_CODE_NOT_FOUND); } // 超过时间 - if (LocalDateTimeUtil.between(lastSmsCode.getCreateTime(), LocalDateTime.now()).toMillis() + if (LocalDateTimeUtil.between(lastMailCode.getCreateTime(), LocalDateTime.now()).toMillis() >= smsCodeProperties.getExpireTimes().toMillis()) { // 验证码已过期 throw exception(SMS_CODE_EXPIRED); } // 判断验证码是否已被使用 - if (Boolean.TRUE.equals(lastSmsCode.getUsed())) { + if (Boolean.TRUE.equals(lastMailCode.getUsed())) { throw exception(SMS_CODE_USED); } - return lastSmsCode; + return lastMailCode; } } diff --git a/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/mail/MailTemplateServiceImpl.java b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/mail/MailTemplateServiceImpl.java index e5a7c8f..eaf12ba 100644 --- a/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/mail/MailTemplateServiceImpl.java +++ b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/mail/MailTemplateServiceImpl.java @@ -12,6 +12,7 @@ import cn.hangtag.module.system.dal.mysql.mail.MailTemplateMapper; import cn.hangtag.module.system.dal.redis.RedisKeyConstants; import com.google.common.annotations.VisibleForTesting; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; @@ -41,7 +42,7 @@ public class MailTemplateServiceImpl implements MailTemplateService { /** * 正则表达式,匹配 {} 中的变量 */ - private static final Pattern PATTERN_PARAMS = Pattern.compile("\\{(.*?)}"); + private static final Pattern PATTERN_PARAMS = Pattern.compile("\\{\\{(.*?)}}"); @Resource private MailTemplateMapper mailTemplateMapper; @@ -122,6 +123,12 @@ public class MailTemplateServiceImpl implements MailTemplateService { @Override public String formatMailTemplateContent(String content, Map params) { + if(StringUtils.isNotBlank(content)){ +/* content = content.replaceFirst("

", "").replace("

", ""); + content = content.replaceAll("<", "<").replaceAll(">", ">"); + content = content.replaceAll(" ", "");*/ + content = content.replaceAll("\\{\\{", "{").replaceAll("}}","}"); + } return StrUtil.format(content, params); } diff --git a/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/user/AdminUserService.java b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/user/AdminUserService.java index 79430fa..98105ec 100644 --- a/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/user/AdminUserService.java +++ b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/user/AdminUserService.java @@ -201,4 +201,15 @@ public interface AdminUserService { */ boolean isPasswordMatch(String rawPassword, String encodedPassword); + + + /** + * 通过邮箱号获取用户 + * + * @param mail 邮箱号 + * @return 用户对象信息 + */ + AdminUserDO getUserByMail(String mail); + + } diff --git a/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/user/AdminUserServiceImpl.java b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/user/AdminUserServiceImpl.java index 8df27eb..abba5c1 100644 --- a/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/user/AdminUserServiceImpl.java +++ b/hangtag-module-system/hangtag-module-system-biz/src/main/java/cn/hangtag/module/system/service/user/AdminUserServiceImpl.java @@ -496,6 +496,11 @@ public class AdminUserServiceImpl implements AdminUserService { return passwordEncoder.matches(rawPassword, encodedPassword); } + @Override + public AdminUserDO getUserByMail(String mail) { + return userMapper.selectByEmail(mail); + } + /** * 对密码进行加密 * diff --git a/hangtag-server/src/main/resources/application.yaml b/hangtag-server/src/main/resources/application.yaml index 24291a7..4f7234f 100644 --- a/hangtag-server/src/main/resources/application.yaml +++ b/hangtag-server/src/main/resources/application.yaml @@ -251,8 +251,8 @@ hangtag: expire-times: 10m send-frequency: 1m send-maximum-quantity-per-day: 10 - begin-code: 9999 # 这里配置 9999 的原因是,测试方便。 - end-code: 9999 # 这里配置 9999 的原因是,测试方便。 + begin-code: 000001 # 这里配置 9999 的原因是,测试方便。 + end-code: 999999 # 这里配置 9999 的原因是,测试方便。 trade: order: app-id: 1 # 商户编号 diff --git a/hangtag-ui/hangtag-ui-front/src/api/login/index.ts b/hangtag-ui/hangtag-ui-front/src/api/login/index.ts index ef86563..062c31f 100644 --- a/hangtag-ui/hangtag-ui-front/src/api/login/index.ts +++ b/hangtag-ui/hangtag-ui-front/src/api/login/index.ts @@ -12,6 +12,19 @@ export interface SmsLoginVO { code: string } +export interface MailCodeVO { + mail: string + scene: number +} + + +export interface MailModifyPwdVO { + mail: string + password: string + checkpassword: string + code: string +} + // 登录 export const login = (data: UserLoginVO) => { return request.post({ url: '/system/auth/login', data }) @@ -47,6 +60,16 @@ export const sendSmsCode = (data: SmsCodeVO) => { return request.post({ url: '/system/auth/send-sms-code', data }) } +//获取邮箱登录验证码 +export const sendMailCode = (data: MailCodeVO) => { + return request.post({ url: '/system/auth/send-mail-code', data }) +} + +// 邮箱码修改密码 +export const mailModifyPwd = (data: MailModifyPwdVO) => { + return request.post({ url: '/system/auth/mail-modifypwd', data }) +} + // 短信验证码登录 export const smsLogin = (data: SmsLoginVO) => { return request.post({ url: '/system/auth/sms-login', data }) diff --git a/hangtag-ui/hangtag-ui-front/src/locales/en.ts b/hangtag-ui/hangtag-ui-front/src/locales/en.ts index 98056c8..d2e14e2 100644 --- a/hangtag-ui/hangtag-ui-front/src/locales/en.ts +++ b/hangtag-ui/hangtag-ui-front/src/locales/en.ts @@ -114,7 +114,7 @@ export default { }, login: { welcome: 'Welcome to the system', - message: 'Backstage management system', + message: '', tenantname: 'TenantName', username: 'Username', password: 'Password', @@ -133,14 +133,17 @@ export default { codePlaceholder: 'Please Enter Verification Code', mobileTitle: 'Mobile sign in', mobileNumber: 'Mobile Number', - mobileNumberPlaceholder: 'Plaease Enter Mobile Number', + mobileNumberPlaceholder: 'Plaease Enter Mobile Code', + emailNumberPlaceholder: 'Plaease Enter Email Code', backLogin: 'back', getSmsCode: 'Get SMS Code', + getMailCode: 'Get Mail Code', btnMobile: 'Mobile sign in', btnQRCode: 'QR code sign in', qrcode: 'Scan the QR code to log in', btnRegister: 'Sign up', - SmsSendMsg: 'code has been sent' + SmsSendMsg: 'code has been sent', + pwdResetSuccess: 'password reset success' }, captcha: { verification: 'Please complete security verification', diff --git a/hangtag-ui/hangtag-ui-front/src/locales/zh-CN.ts b/hangtag-ui/hangtag-ui-front/src/locales/zh-CN.ts index ee2b41b..83f53bf 100644 --- a/hangtag-ui/hangtag-ui-front/src/locales/zh-CN.ts +++ b/hangtag-ui/hangtag-ui-front/src/locales/zh-CN.ts @@ -134,13 +134,16 @@ export default { mobileTitle: '手机登录', mobileNumber: '手机号码', mobileNumberPlaceholder: '请输入手机号码', + emailNumberPlaceholder: '请输入邮箱号码', backLogin: '返回', getSmsCode: '获取验证码', + getMailCode: '获取验证码', btnMobile: '手机登录', btnQRCode: '二维码登录', qrcode: '扫描二维码登录', btnRegister: '注册', - SmsSendMsg: '验证码已发送' + SmsSendMsg: '验证码已发送', + pwdResetSuccess: '密码重置成功' }, captcha: { verification: '请完成安全验证', diff --git a/hangtag-ui/hangtag-ui-front/src/views/Login/Login.vue b/hangtag-ui/hangtag-ui-front/src/views/Login/Login.vue index 904394f..1a2bb33 100644 --- a/hangtag-ui/hangtag-ui-front/src/views/Login/Login.vue +++ b/hangtag-ui/hangtag-ui-front/src/views/Login/Login.vue @@ -29,7 +29,7 @@
+ +
@@ -70,7 +72,7 @@ import { useAppStore } from '@/store/modules/app' import { ThemeSwitch } from '@/layout/components/ThemeSwitch' import { LocaleDropdown } from '@/layout/components/LocaleDropdown' -import { LoginForm, MobileForm, QrCodeForm, RegisterForm, SSOLoginVue } from './components' +import { LoginForm, MobileForm, ForgetPasswordForm, QrCodeForm, RegisterForm, SSOLoginVue } from './components' defineOptions({ name: 'Login' }) diff --git a/hangtag-ui/hangtag-ui-front/src/views/Login/components/ForgetPasswordForm.vue b/hangtag-ui/hangtag-ui-front/src/views/Login/components/ForgetPasswordForm.vue new file mode 100644 index 0000000..c3a8103 --- /dev/null +++ b/hangtag-ui/hangtag-ui-front/src/views/Login/components/ForgetPasswordForm.vue @@ -0,0 +1,262 @@ + + + + diff --git a/hangtag-ui/hangtag-ui-front/src/views/Login/components/LoginForm.vue b/hangtag-ui/hangtag-ui-front/src/views/Login/components/LoginForm.vue index 172aa96..c7fcb4d 100644 --- a/hangtag-ui/hangtag-ui-front/src/views/Login/components/LoginForm.vue +++ b/hangtag-ui/hangtag-ui-front/src/views/Login/components/LoginForm.vue @@ -58,9 +58,9 @@ {{ t('login.remember') }} - + + {{ t('login.forgetPassword') }} + diff --git a/hangtag-ui/hangtag-ui-front/src/views/Login/components/index.ts b/hangtag-ui/hangtag-ui-front/src/views/Login/components/index.ts index 204ad73..6b34ed1 100644 --- a/hangtag-ui/hangtag-ui-front/src/views/Login/components/index.ts +++ b/hangtag-ui/hangtag-ui-front/src/views/Login/components/index.ts @@ -1,8 +1,9 @@ import LoginForm from './LoginForm.vue' import MobileForm from './MobileForm.vue' +import ForgetPasswordForm from './ForgetPasswordForm.vue' import LoginFormTitle from './LoginFormTitle.vue' import RegisterForm from './RegisterForm.vue' import QrCodeForm from './QrCodeForm.vue' import SSOLoginVue from './SSOLogin.vue' -export { LoginForm, MobileForm, LoginFormTitle, RegisterForm, QrCodeForm, SSOLoginVue } +export { LoginForm, MobileForm, ForgetPasswordForm, LoginFormTitle, RegisterForm, QrCodeForm, SSOLoginVue }