1.登录增强 2.用户表增加身份证字段 3.钉钉跳转修复
This commit is contained in:
1 parent
fff9b6e40f
commit
93b288ed9d
21 files changed
+256
-66
No files matched your search
+15
-4
@@ -131,29 +131,40 @@ public class ValidateCodeFilter extends OncePerRequestFilter {
|
||||
|
||||
String key = CacheConstants.DEFAULT_CODE_KEY + randomStr;
|
||||
if (Boolean.FALSE.equals(redisTemplate.hasKey(key))) {
|
||||
throw new ValidateCodeException(MsgUtils.getMessage(ErrorCodes.AUTH_CAPTCHA_INVALID));
|
||||
throw new ValidateCodeException(invalidCodeMessage(mobile));
|
||||
}
|
||||
|
||||
Object codeObj = redisTemplate.opsForValue().get(key);
|
||||
|
||||
if (codeObj == null) {
|
||||
throw new ValidateCodeException(MsgUtils.getMessage(ErrorCodes.AUTH_CAPTCHA_INVALID));
|
||||
throw new ValidateCodeException(invalidCodeMessage(mobile));
|
||||
}
|
||||
|
||||
String saveCode = codeObj.toString();
|
||||
if (StrUtil.isBlank(saveCode)) {
|
||||
redisTemplate.delete(key);
|
||||
throw new ValidateCodeException(MsgUtils.getMessage(ErrorCodes.AUTH_CAPTCHA_INVALID));
|
||||
throw new ValidateCodeException(invalidCodeMessage(mobile));
|
||||
}
|
||||
|
||||
if (!StrUtil.equals(saveCode, code)) {
|
||||
redisTemplate.delete(key);
|
||||
throw new ValidateCodeException(MsgUtils.getMessage(ErrorCodes.AUTH_CAPTCHA_INVALID));
|
||||
throw new ValidateCodeException(invalidCodeMessage(mobile));
|
||||
}
|
||||
|
||||
redisTemplate.delete(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 短信登录与图形验证码使用不同提示:已使用/过期的短信码对用户更友好。
|
||||
*/
|
||||
private String invalidCodeMessage(String mobile) {
|
||||
// mobile 参数形如 SMS@138xxxx
|
||||
if (StrUtil.isNotBlank(mobile) && StrUtil.contains(mobile, "SMS")) {
|
||||
return MsgUtils.getMessage(ErrorCodes.SYS_APP_SMS_CODE_INVALID);
|
||||
}
|
||||
return MsgUtils.getMessage(ErrorCodes.AUTH_CAPTCHA_INVALID);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否需要校验客户端,根据client 查询客户端配置
|
||||
*
|
||||
|
||||
+6
@@ -41,6 +41,12 @@ public class CanteenCategoryEntity extends Model<CanteenCategoryEntity> {
|
||||
@Schema(description="分类名称")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 分类英文名称
|
||||
*/
|
||||
@Schema(description = "分类英文名称")
|
||||
private String nameEn;
|
||||
|
||||
/**
|
||||
* 分类图
|
||||
*/
|
||||
|
||||
+12
@@ -39,6 +39,18 @@ public class CanteenSpuEntity extends Model<CanteenSpuEntity> {
|
||||
@Schema(description="商品名称")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 菜品英文名称
|
||||
*/
|
||||
@Schema(description = "菜品英文名称")
|
||||
private String nameEn;
|
||||
|
||||
/**
|
||||
* 套餐名(仅 spuType=2 时使用)
|
||||
*/
|
||||
@Schema(description = "套餐名")
|
||||
private String comboName;
|
||||
|
||||
/**
|
||||
* 商品简介
|
||||
*/
|
||||
|
||||
+24
@@ -24,6 +24,18 @@ public class ADCanteenSpuListVO {
|
||||
@Schema(description="商品名称")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 菜品英文名称
|
||||
*/
|
||||
@Schema(description = "菜品英文名称")
|
||||
private String nameEn;
|
||||
|
||||
/**
|
||||
* 套餐名(仅套餐时有值)
|
||||
*/
|
||||
@Schema(description = "套餐名")
|
||||
private String comboName;
|
||||
|
||||
/**
|
||||
* 商品简介
|
||||
*/
|
||||
@@ -43,6 +55,18 @@ public class ADCanteenSpuListVO {
|
||||
@Schema(description="商品分类编号")
|
||||
private Long categoryId;
|
||||
|
||||
/**
|
||||
* 分类名称
|
||||
*/
|
||||
@Schema(description = "分类名称")
|
||||
private String categoryName;
|
||||
|
||||
/**
|
||||
* 分类英文名称
|
||||
*/
|
||||
@Schema(description = "分类英文名称")
|
||||
private String categoryNameEn;
|
||||
|
||||
/**
|
||||
* 商品封面图
|
||||
*/
|
||||
|
||||
+15
@@ -36,6 +36,16 @@ public class DailyMenuAppVO {
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 菜品英文名称。
|
||||
*/
|
||||
private String nameEn;
|
||||
|
||||
/**
|
||||
* 套餐名(仅套餐时有值)。
|
||||
*/
|
||||
private String comboName;
|
||||
|
||||
/**
|
||||
* 商品销售价格,单位为分。
|
||||
*/
|
||||
@@ -56,6 +66,11 @@ public class DailyMenuAppVO {
|
||||
*/
|
||||
private String categoryName;
|
||||
|
||||
/**
|
||||
* 菜品分类英文名称;分类不存在或已删除时为空。
|
||||
*/
|
||||
private String categoryNameEn;
|
||||
|
||||
/**
|
||||
* 菜品封面图地址。
|
||||
*/
|
||||
|
||||
+18
-5
@@ -407,6 +407,8 @@ public class CanteenSpuServiceImpl extends ServiceImpl<CanteenSpuMapper, Canteen
|
||||
CanteenSpuEntity entity = canteenSpuEntities.get(i);
|
||||
item.setIntroduction(entity.getIntroduction());
|
||||
item.setDescription(entity.getDescription());
|
||||
item.setNameEn(entity.getNameEn());
|
||||
item.setComboName(entity.getComboName());
|
||||
int type = entity.getSpuType() == null ? 1 : entity.getSpuType();
|
||||
item.setSpuType(type);
|
||||
if (type == 2) {
|
||||
@@ -415,9 +417,13 @@ public class CanteenSpuServiceImpl extends ServiceImpl<CanteenSpuMapper, Canteen
|
||||
else {
|
||||
item.setComboItems(Collections.emptyList());
|
||||
}
|
||||
if (item.getCategoryId() != null && listMap.get(item.getCategoryId()) != null
|
||||
&& listMap.get(item.getCategoryId()).get(0).getCategoryType() != null) {
|
||||
item.setCategoryType(listMap.get(item.getCategoryId()).get(0).getCategoryType());
|
||||
if (item.getCategoryId() != null && listMap.get(item.getCategoryId()) != null) {
|
||||
CanteenCategoryEntity category = listMap.get(item.getCategoryId()).get(0);
|
||||
if (category.getCategoryType() != null) {
|
||||
item.setCategoryType(category.getCategoryType());
|
||||
}
|
||||
item.setCategoryName(category.getName());
|
||||
item.setCategoryNameEn(category.getNameEn());
|
||||
}
|
||||
}
|
||||
// 有每日菜谱则 stock=线下剩余,避免安卓仍展示 canteen_spu.stock
|
||||
@@ -434,6 +440,8 @@ public class CanteenSpuServiceImpl extends ServiceImpl<CanteenSpuMapper, Canteen
|
||||
ADCanteenSpuListVO vo = BeanUtils.toBean(detail, ADCanteenSpuListVO.class);
|
||||
vo.setIntroduction(detail.getIntroduction());
|
||||
vo.setDescription(detail.getDescription());
|
||||
vo.setNameEn(detail.getNameEn());
|
||||
vo.setComboName(detail.getComboName());
|
||||
int type = detail.getSpuType() == null ? 1 : detail.getSpuType();
|
||||
vo.setSpuType(type);
|
||||
if (type == 2) {
|
||||
@@ -444,8 +452,12 @@ public class CanteenSpuServiceImpl extends ServiceImpl<CanteenSpuMapper, Canteen
|
||||
}
|
||||
if (detail.getCategoryId() != null) {
|
||||
CanteenCategoryEntity category = canteenCategoryMapper.selectById(detail.getCategoryId());
|
||||
if (category != null && category.getCategoryType() != null) {
|
||||
vo.setCategoryType(category.getCategoryType());
|
||||
if (category != null) {
|
||||
if (category.getCategoryType() != null) {
|
||||
vo.setCategoryType(category.getCategoryType());
|
||||
}
|
||||
vo.setCategoryName(category.getName());
|
||||
vo.setCategoryNameEn(category.getNameEn());
|
||||
}
|
||||
}
|
||||
overlayDailyRemainOnAdVos(Collections.singletonList(vo), day, hourType, offline);
|
||||
@@ -763,6 +775,7 @@ public class CanteenSpuServiceImpl extends ServiceImpl<CanteenSpuMapper, Canteen
|
||||
}
|
||||
if (!Objects.equals(entity.getSpuType(), 2)) {
|
||||
entity.setComboItems(Collections.emptyList());
|
||||
entity.setComboName("");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -7,6 +7,7 @@
|
||||
<id property="id" column="id"/>
|
||||
<result property="parentId" column="parent_id"/>
|
||||
<result property="name" column="name"/>
|
||||
<result property="nameEn" column="name_en"/>
|
||||
<result property="picUrl" column="pic_url"/>
|
||||
<result property="sort" column="sort"/>
|
||||
<result property="status" column="status"/>
|
||||
|
||||
+19
@@ -27,10 +27,13 @@
|
||||
<result property="merchantId" column="merchant_id"/>
|
||||
<result property="spuId" column="spu_id"/>
|
||||
<result property="name" column="name"/>
|
||||
<result property="nameEn" column="name_en"/>
|
||||
<result property="comboName" column="combo_name"/>
|
||||
<result property="price" column="price"/>
|
||||
<result property="marketPrice" column="market_price"/>
|
||||
<result property="categoryId" column="category_id"/>
|
||||
<result property="categoryName" column="category_name"/>
|
||||
<result property="categoryNameEn" column="category_name_en"/>
|
||||
<result property="picUrl" column="pic_url"/>
|
||||
<result property="sliderPicUrls" column="slider_pic_urls"/>
|
||||
<result property="introduction" column="introduction"/>
|
||||
@@ -80,6 +83,8 @@
|
||||
t.merchant_id,
|
||||
sp.id AS spu_id,
|
||||
sp.name,
|
||||
sp.name_en,
|
||||
sp.combo_name,
|
||||
sp.price,
|
||||
sp.market_price,
|
||||
sp.pic_url,
|
||||
@@ -96,6 +101,7 @@
|
||||
sp.is_show,
|
||||
c.id AS category_id,
|
||||
c.name AS category_name,
|
||||
c.name_en AS category_name_en,
|
||||
IFNULL(sp.spu_type, 1) AS spu_type,
|
||||
t.hour_type,
|
||||
<!-- 数据权限拦截器会在当前查询外层按部门和创建人过滤,必须在临时结果集中透传这两个字段。 -->
|
||||
@@ -132,6 +138,8 @@
|
||||
t.merchant_id,
|
||||
sp.id AS spu_id,
|
||||
sp.name,
|
||||
sp.name_en,
|
||||
sp.combo_name,
|
||||
sp.price,
|
||||
sp.market_price,
|
||||
sp.pic_url,
|
||||
@@ -148,6 +156,7 @@
|
||||
sp.is_show,
|
||||
c.id AS category_id,
|
||||
c.name AS category_name,
|
||||
c.name_en AS category_name_en,
|
||||
IFNULL(sp.spu_type, 1) AS spu_type,
|
||||
t.hour_type
|
||||
FROM canteen_daily_menu t
|
||||
@@ -172,6 +181,8 @@
|
||||
t.merchant_id,
|
||||
sp.id AS spu_id,
|
||||
sp.name,
|
||||
sp.name_en,
|
||||
sp.combo_name,
|
||||
sp.price,
|
||||
sp.market_price,
|
||||
sp.pic_url,
|
||||
@@ -188,6 +199,7 @@
|
||||
sp.is_show,
|
||||
c.id AS category_id,
|
||||
c.name AS category_name,
|
||||
c.name_en AS category_name_en,
|
||||
IFNULL(sp.spu_type, 1) AS spu_type,
|
||||
t.hour_type,
|
||||
<!-- 数据权限拦截器会在当前查询外层按部门和创建人过滤,必须在临时结果集中透传这两个字段。 -->
|
||||
@@ -217,6 +229,8 @@
|
||||
m.hour_type,
|
||||
s.id as spu_id,
|
||||
s.`name`,
|
||||
s.name_en,
|
||||
s.combo_name,
|
||||
s.price,
|
||||
IFNULL(m.online_stock, 600) as stock,
|
||||
IFNULL(m.online_stock, 600) as online_stock,
|
||||
@@ -227,6 +241,8 @@
|
||||
s.sort,
|
||||
s.is_show,
|
||||
c.id as category_id,
|
||||
c.name as category_name,
|
||||
c.name_en as category_name_en,
|
||||
IFNULL(s.spu_type, 1) as spu_type
|
||||
FROM `canteen_daily_menu` m
|
||||
left JOIN canteen_spu s
|
||||
@@ -255,6 +271,8 @@
|
||||
m.merchant_id,
|
||||
s.id AS spu_id,
|
||||
s.name,
|
||||
s.name_en,
|
||||
s.combo_name,
|
||||
s.price,
|
||||
s.market_price,
|
||||
IFNULL(m.online_stock, 600) AS stock,
|
||||
@@ -271,6 +289,7 @@
|
||||
s.is_show,
|
||||
c.id AS category_id,
|
||||
c.name AS category_name,
|
||||
c.name_en AS category_name_en,
|
||||
IFNULL(s.spu_type, 1) AS spu_type
|
||||
FROM canteen_daily_menu m
|
||||
INNER JOIN canteen_spu s ON m.spu_id = s.id
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
<resultMap id="canteenSpuMap" type="com.bsd.pjcloud.canteen.entity.CanteenSpuEntity">
|
||||
<id property="id" column="id"/>
|
||||
<result property="name" column="name"/>
|
||||
<result property="nameEn" column="name_en"/>
|
||||
<result property="comboName" column="combo_name"/>
|
||||
<result property="introduction" column="introduction"/>
|
||||
<result property="description" column="description"/>
|
||||
<result property="categoryId" column="category_id"/>
|
||||
|
||||
@@ -357,7 +357,7 @@ hard.car.batch.same.user.mch=Batch cart must share user/merchant/type
|
||||
hard.car.save.fail=Failed to save cart products
|
||||
common.idempotent.retry=Duplicate request. Please try again later
|
||||
auth.captcha.empty=Verification code is required
|
||||
auth.captcha.invalid=Invalid verification code
|
||||
auth.captcha.invalid=Incorrect or expired verification code
|
||||
auth.wx.auth.fail=WeChat authorization failed: {0}
|
||||
auth.wx.openid.missing=WeChat authorization failed; user identifier not received
|
||||
auth.wx.auth.expired=WeChat authorization expired; please authorize again
|
||||
@@ -366,7 +366,7 @@ auth.apple.not.enabled=Apple login is not enabled
|
||||
auth.mini.app.login.fail=WeChat mini program login failed
|
||||
auth.social.auth.expired=Authorization expired; please authorize again
|
||||
sys.app.sms.send.fail=Failed to send SMS code; please try again later
|
||||
sys.app.sms.code.invalid=SMS code is invalid or expired
|
||||
sys.app.sms.code.invalid=Incorrect or expired verification code
|
||||
sys.user.password.same=New password must differ from old password
|
||||
sys.user.unbind.type.invalid=Unbind account type does not exist
|
||||
third.recharge.biz.id.invalid=Invalid recharge business ID
|
||||
|
||||
+2
-2
@@ -357,7 +357,7 @@ hard.car.batch.same.user.mch=批量购物车必须属于同一用户、商户和
|
||||
hard.car.save.fail=购物车商品保存失败
|
||||
common.idempotent.retry=重复请求,请稍后重试
|
||||
auth.captcha.empty=验证码不能为空
|
||||
auth.captcha.invalid=验证码不合法
|
||||
auth.captcha.invalid=验证码不正确或已过期
|
||||
auth.wx.auth.fail=微信授权失败:{0}
|
||||
auth.wx.openid.missing=微信授权失败,未获取到用户标识
|
||||
auth.wx.auth.expired=微信授权已过期,请重新授权
|
||||
@@ -366,7 +366,7 @@ auth.apple.not.enabled=未启用Apple登录
|
||||
auth.mini.app.login.fail=微信小程序登录失败
|
||||
auth.social.auth.expired=授权已过期,请重新授权
|
||||
sys.app.sms.send.fail=短信验证码发送失败,请稍后重试
|
||||
sys.app.sms.code.invalid=短信验证码错误或已过期
|
||||
sys.app.sms.code.invalid=验证码不正确或已过期
|
||||
sys.user.password.same=新旧密码不能相同
|
||||
sys.user.unbind.type.invalid=解绑账号类型不存在
|
||||
third.recharge.biz.id.invalid=充值业务id解析错误
|
||||
|
||||
+2
-2
@@ -357,7 +357,7 @@ hard.car.batch.same.user.mch=批量購物車必須屬於同一用戶、商戶和
|
||||
hard.car.save.fail=購物車商品保存失敗
|
||||
common.idempotent.retry=重複請求,請稍後重試
|
||||
auth.captcha.empty=驗證碼不能為空
|
||||
auth.captcha.invalid=驗證碼不合法
|
||||
auth.captcha.invalid=驗證碼不正確或已過期
|
||||
auth.wx.auth.fail=微信授權失敗:{0}
|
||||
auth.wx.openid.missing=微信授權失敗,未獲取到用戶標識
|
||||
auth.wx.auth.expired=微信授權已過期,請重新授權
|
||||
@@ -366,7 +366,7 @@ auth.apple.not.enabled=未啟用Apple登錄
|
||||
auth.mini.app.login.fail=微信小程序登錄失敗
|
||||
auth.social.auth.expired=授權已過期,請重新授權
|
||||
sys.app.sms.send.fail=短信驗證碼發送失敗,請稍後重試
|
||||
sys.app.sms.code.invalid=短信驗證碼錯誤或已過期
|
||||
sys.app.sms.code.invalid=驗證碼不正確或已過期
|
||||
sys.user.password.same=新舊密碼不能相同
|
||||
sys.user.unbind.type.invalid=解綁賬號類型不存在
|
||||
third.recharge.biz.id.invalid=充值業務id解析錯誤
|
||||
|
||||
+12
-2
@@ -3,6 +3,7 @@ package com.bsd.pjcloud.thirdparty.controller;
|
||||
import com.bsd.pjcloud.common.security.annotation.Inner;
|
||||
import com.bsd.pjcloud.thirdparty.service.SmsService;
|
||||
import com.bsd.pjcloud.thirdparty.utils.sms.AliyunSMS;
|
||||
import com.bsd.pjcloud.thirdparty.utils.sms.SmsHTTPSend;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@@ -17,6 +18,8 @@ public class SmsController {
|
||||
private final SmsService smsService;
|
||||
private final AliyunSMS aliyunSMS;
|
||||
|
||||
private final SmsHTTPSend smsHTTPSend;
|
||||
|
||||
// 简单发送
|
||||
@PostMapping("/sendMsg")
|
||||
public void sendSimpleMsg(@RequestParam String mobile,@RequestParam String templateId,@RequestParam("clientIp") String clientIp) {
|
||||
@@ -32,11 +35,18 @@ public class SmsController {
|
||||
smsService.sendSms(mobile, templateId, params,clientIp);
|
||||
}
|
||||
|
||||
// 阿里云发送验证码
|
||||
/**
|
||||
* 发送登录/注册验证码(联通短信通道)
|
||||
*/
|
||||
@PostMapping("/sendVerificationCode")
|
||||
@Inner(value = false)
|
||||
public void sendALiVerificationCode(@RequestParam("mobile") String mobile, @RequestParam("code") String code) {
|
||||
aliyunSMS.sendVerificationCode(mobile, code);
|
||||
String content = "您的验证码是" + code + ",5分钟内有效,仅用于完成本次验证。";
|
||||
Boolean ok = smsHTTPSend.smsSendByPost(content, mobile);
|
||||
if (!Boolean.TRUE.equals(ok)) {
|
||||
// 联通通道失败时回退阿里云,避免验证码完全发不出
|
||||
aliyunSMS.sendVerificationCode(mobile, code);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -191,11 +191,11 @@ LianTongSMS:
|
||||
#企业编号
|
||||
SP_CODE: '11122'
|
||||
#登录用户名
|
||||
LOGIN_NAME: ''
|
||||
LOGIN_NAME: 'zianxin'
|
||||
#登录用户密码
|
||||
PASSWORD: 'Aa123456'
|
||||
#签名id
|
||||
AUTOGRAPH_ID: ''
|
||||
AUTOGRAPH_ID: '13725'
|
||||
|
||||
|
||||
hikvision:
|
||||
|
||||
+18
-10
@@ -4,7 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 部门邀请注册请求
|
||||
* 部门邀请注册请求(手机号 + 短信验证码)
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "部门邀请注册")
|
||||
@@ -13,18 +13,26 @@ public class DeptInviteRegisterDTO {
|
||||
@Schema(description = "邀请 token", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String token;
|
||||
|
||||
@Schema(description = "账号(可与手机号相同)", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String username;
|
||||
|
||||
@Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String password;
|
||||
|
||||
@Schema(description = "姓名", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String name;
|
||||
|
||||
@Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String phone;
|
||||
|
||||
@Schema(description = "短信验证码", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String smsCode;
|
||||
|
||||
@Schema(description = "姓名(选填,默认用手机号脱敏)")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "身份证号(选填)")
|
||||
private String idCard;
|
||||
|
||||
@Schema(description = "性别 0未知 1男 2女")
|
||||
private Integer gender;
|
||||
|
||||
/** @deprecated 兼容旧客户端;新流程以手机号为账号 */
|
||||
@Schema(description = "账号(可选,默认手机号)")
|
||||
private String username;
|
||||
|
||||
/** @deprecated 兼容旧客户端;新流程自动生成密码 */
|
||||
@Schema(description = "密码(可选,未传则自动生成)")
|
||||
private String password;
|
||||
}
|
||||
+6
@@ -157,6 +157,12 @@ public class SysUser extends Model<SysUser> implements Serializable {
|
||||
@Schema(description = "手机号")
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 身份证号(选填)
|
||||
*/
|
||||
@Schema(description = "身份证号")
|
||||
private String idCard;
|
||||
|
||||
/**
|
||||
* 性别:0未知 1男 2女(骑手派单等)
|
||||
*/
|
||||
|
||||
+5
-1
@@ -550,11 +550,15 @@ public class SysUserController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 忘记密码-发送短信验证码
|
||||
* 忘记密码-发送短信验证码(仅已注册手机号)
|
||||
*/
|
||||
@Inner(value = false)
|
||||
@GetMapping("/forgot-password/sms-code")
|
||||
public R<Boolean> sendForgotPasswordSmsCode(@RequestParam("mobile") String mobile) {
|
||||
long count = userService.count(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getPhone, mobile));
|
||||
if (count <= 0) {
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_APP_PHONE_UNREGISTERED, mobile));
|
||||
}
|
||||
return sysMessageService.sendSmsCode(mobile);
|
||||
}
|
||||
|
||||
|
||||
+12
-1
@@ -63,12 +63,23 @@ public interface SysMessageService extends IService<SysMessageEntity> {
|
||||
|
||||
/**
|
||||
* 发送手机验证码
|
||||
* <p>未注册手机号也会发送;返回 data=true 表示该手机号已注册,false 表示未注册(可引导邀请注册)。
|
||||
*
|
||||
* @param mobile mobile
|
||||
* @return code
|
||||
* @return data=是否已注册
|
||||
*/
|
||||
R<Boolean> sendSmsCode(String mobile);
|
||||
|
||||
/**
|
||||
* 校验短信验证码(登录 Redis 键 SMS@mobile)
|
||||
*
|
||||
* @param mobile 手机号
|
||||
* @param code 验证码
|
||||
* @param consume 是否校验成功后删除
|
||||
* @return 是否通过
|
||||
*/
|
||||
boolean verifySmsCode(String mobile, String code, boolean consume);
|
||||
|
||||
/**
|
||||
* 发送短信
|
||||
*
|
||||
|
||||
+47
-25
@@ -29,6 +29,7 @@ import com.bsd.pjcloud.admin.mapper.SysUserMapper;
|
||||
import com.bsd.pjcloud.admin.mapper.SysUserRoleMapper;
|
||||
import com.bsd.pjcloud.admin.service.SysDeptInviteService;
|
||||
import com.bsd.pjcloud.admin.service.SysDeptService;
|
||||
import com.bsd.pjcloud.admin.service.SysMessageService;
|
||||
import com.bsd.pjcloud.admin.service.SysRoleService;
|
||||
import com.bsd.pjcloud.admin.service.SysUserIdentityService;
|
||||
import com.bsd.pjcloud.admin.utils.flow.FlowUtil;
|
||||
@@ -80,6 +81,7 @@ public class SysDeptInviteServiceImpl extends ServiceImpl<SysDeptInviteMapper, S
|
||||
private final RemoteMchService remoteMchService;
|
||||
private final RemoteWalletService remoteWalletService;
|
||||
private final FlowUtil flowUtil;
|
||||
private final SysMessageService sysMessageService;
|
||||
|
||||
/** 邀请码类型:6 位数字 / 8 位数字 / UUID(默认) */
|
||||
private static final String TOKEN_DIGIT6 = "DIGIT6";
|
||||
@@ -90,6 +92,9 @@ public class SysDeptInviteServiceImpl extends ServiceImpl<SysDeptInviteMapper, S
|
||||
/** 中国大陆手机号 */
|
||||
private static final Pattern PHONE_PATTERN = Pattern.compile(
|
||||
"^1(3\\d|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8\\d|9[0-35-9])\\d{8}$");
|
||||
/** 18 位身份证(含 X) */
|
||||
private static final Pattern ID_CARD_PATTERN = Pattern.compile(
|
||||
"^[1-9]\\d{5}(19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[\\dXx]$");
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@@ -285,39 +290,56 @@ public class SysDeptInviteServiceImpl extends ServiceImpl<SysDeptInviteMapper, S
|
||||
if (dto == null || StrUtil.isBlank(dto.getToken())) {
|
||||
return R.failed("邀请码无效");
|
||||
}
|
||||
if (StrUtil.isBlank(dto.getUsername()) || StrUtil.isBlank(dto.getPassword())
|
||||
|| StrUtil.isBlank(dto.getName()) || StrUtil.isBlank(dto.getPhone())) {
|
||||
return R.failed("请完整填写账号、密码、姓名、手机号");
|
||||
if (StrUtil.isBlank(dto.getPhone()) || StrUtil.isBlank(dto.getSmsCode())) {
|
||||
return R.failed("请填写手机号和验证码");
|
||||
}
|
||||
String username = dto.getUsername().trim();
|
||||
String password = dto.getPassword();
|
||||
String phone = dto.getPhone().trim();
|
||||
String usernameErr = validateUsername(username);
|
||||
if (usernameErr != null) {
|
||||
return R.failed(usernameErr);
|
||||
}
|
||||
String passwordErr = validateInvitePassword(password);
|
||||
if (passwordErr != null) {
|
||||
return R.failed(passwordErr);
|
||||
}
|
||||
String nameErr = validateInviteName(dto.getName());
|
||||
if (nameErr != null) {
|
||||
return R.failed(nameErr);
|
||||
}
|
||||
if (!PHONE_PATTERN.matcher(phone).matches()) {
|
||||
return R.failed("请输入正确的手机号");
|
||||
}
|
||||
if (!sysMessageService.verifySmsCode(phone, dto.getSmsCode().trim(), false)) {
|
||||
return R.failed("验证码错误或已过期");
|
||||
}
|
||||
|
||||
SysDeptInviteEntity invite = requireValidInvite(dto.getToken());
|
||||
boolean usernameExists = sysUserMapper.exists(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUsername, username));
|
||||
if (usernameExists) {
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_USER_USERNAME_EXISTING, username));
|
||||
}
|
||||
boolean phoneExists = sysUserMapper.exists(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getPhone, phone));
|
||||
if (phoneExists) {
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_USER_PHONE_EXISTING, phone));
|
||||
}
|
||||
|
||||
// 账号默认用手机号前缀 u,兼容旧客户端显式传 username/password
|
||||
String username = StrUtil.blankToDefault(StrUtil.trim(dto.getUsername()), "u" + phone);
|
||||
String usernameErr = validateUsername(username);
|
||||
if (usernameErr != null) {
|
||||
// 纯数字账号不符合「字母开头」规则时,强制用 u+手机号
|
||||
username = "u" + phone;
|
||||
}
|
||||
boolean usernameExists = sysUserMapper.exists(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUsername, username));
|
||||
if (usernameExists) {
|
||||
username = "u" + phone + RandomUtil.randomNumbers(4);
|
||||
}
|
||||
|
||||
String password = StrUtil.isNotBlank(dto.getPassword()) ? dto.getPassword()
|
||||
: (RandomUtil.randomNumbers(6) + RandomUtil.randomString("abcdef", 2) + "Aa1");
|
||||
if (StrUtil.isNotBlank(dto.getPassword())) {
|
||||
String passwordErr = validateInvitePassword(password);
|
||||
if (passwordErr != null) {
|
||||
return R.failed(passwordErr);
|
||||
}
|
||||
}
|
||||
|
||||
String displayName = StrUtil.blankToDefault(StrUtil.trim(dto.getName()),
|
||||
"用户" + phone.substring(Math.max(0, phone.length() - 4)));
|
||||
String nameErr = validateInviteName(displayName);
|
||||
if (nameErr != null) {
|
||||
displayName = "用户" + phone.substring(Math.max(0, phone.length() - 4));
|
||||
}
|
||||
|
||||
String idCard = StrUtil.trim(dto.getIdCard());
|
||||
if (StrUtil.isNotBlank(idCard) && !ID_CARD_PATTERN.matcher(idCard).matches()) {
|
||||
return R.failed("身份证号格式不正确");
|
||||
}
|
||||
|
||||
MchManageVo mch = resolveMerchantAlongUnitChain(invite.getDeptId());
|
||||
String attr = mch != null ? StrUtil.blankToDefault(mch.getMerchantAttr(), MerchantAttrEnum.NORMAL.getCode())
|
||||
: MerchantAttrEnum.NORMAL.getCode();
|
||||
@@ -327,11 +349,11 @@ public class SysDeptInviteServiceImpl extends ServiceImpl<SysDeptInviteMapper, S
|
||||
SysUser sysUser = new SysUser();
|
||||
sysUser.setUsername(username);
|
||||
sysUser.setPhone(phone);
|
||||
sysUser.setName(PersonNameUtils.normalize(dto.getName()));
|
||||
sysUser.setIdCard(StrUtil.blankToDefault(idCard, null));
|
||||
sysUser.setName(PersonNameUtils.normalize(displayName));
|
||||
sysUser.setNickname(sysUser.getName());
|
||||
sysUser.setGender(dto.getGender());
|
||||
sysUser.setGender(dto.getGender() == null ? 0 : dto.getGender());
|
||||
sysUser.setDeptId(invite.getDeptId());
|
||||
// 与后台「新增用户审批」一致:正常账号 + 审核中状态,并真正发起 ADD_USER_FLOW 写入 processId
|
||||
sysUser.setLockFlag(UserStateEnum.NORMAL.getCode());
|
||||
sysUser.setCreateBy(username);
|
||||
sysUser.setUpdateBy(username);
|
||||
@@ -340,7 +362,6 @@ public class SysDeptInviteServiceImpl extends ServiceImpl<SysDeptInviteMapper, S
|
||||
sysUser.setProcessStatus(needAudit ? TaskCheckStatusEnum.PADDING.getCode() : TaskCheckStatusEnum.RESULT.getCode());
|
||||
sysUser.setProcessTime(LocalDateTime.now());
|
||||
sysUser.setStaffingType(UserStaffingTypeEnum.NONE_STAFFING.getType());
|
||||
// 邀请注册已自设密码,无需强制改密;EXPIRE(9) 会被当成凭证过期无法登录
|
||||
sysUser.setPasswordExpireFlag(UserExpireEnum.NORMAL.getCode());
|
||||
sysUserMapper.insert(sysUser);
|
||||
|
||||
@@ -379,6 +400,7 @@ public class SysDeptInviteServiceImpl extends ServiceImpl<SysDeptInviteMapper, S
|
||||
log.error("|{}|创建用户钱包失败error:|{}|", TAG, e.getMessage());
|
||||
}
|
||||
});
|
||||
// 保留验证码供前端立即短信登录(登录时再消费)
|
||||
return R.ok(true, "注册成功");
|
||||
}
|
||||
|
||||
|
||||
+31
-10
@@ -122,6 +122,10 @@ public class SysMessageServiceImpl extends ServiceImpl<SysMessageMapper, SysMess
|
||||
private final FileTemplate fileTemplate;
|
||||
private final RemoterThirdPartySmsService remoterThirdPartySmsService;
|
||||
private static final int SMS_CODE_LENGTH = 6;
|
||||
/** 短信验证码有效期(秒) */
|
||||
private static final long SMS_CODE_TTL_SECONDS = 300L;
|
||||
/** 短信重发间隔(秒),与前端倒计时一致 */
|
||||
private static final long SMS_SEND_INTERVAL_SECONDS = 60L;
|
||||
|
||||
/**
|
||||
* 发送信息
|
||||
@@ -267,28 +271,29 @@ public class SysMessageServiceImpl extends ServiceImpl<SysMessageMapper, SysMess
|
||||
*/
|
||||
@Override
|
||||
public R<Boolean> sendSmsCode(String mobile) {
|
||||
List<SysUser> userList = userMapper.selectList(Wrappers.<SysUser>query().lambda().eq(SysUser::getPhone, mobile));
|
||||
|
||||
if (CollUtil.isEmpty(userList)) {
|
||||
log.info("手机号未注册:{}", mobile);
|
||||
return R.ok(Boolean.FALSE, MsgUtils.getMessage(ErrorCodes.SYS_APP_PHONE_UNREGISTERED, mobile));
|
||||
}
|
||||
boolean registered = CollUtil.isNotEmpty(
|
||||
userMapper.selectList(Wrappers.<SysUser>query().lambda().eq(SysUser::getPhone, mobile)));
|
||||
|
||||
String redisKey = CacheConstants.DEFAULT_CODE_KEY + LoginTypeEnum.SMS.getType() + StringPool.AT + mobile;
|
||||
String codeObj = redisTemplate.opsForValue().get(redisKey);
|
||||
|
||||
// 有未过期验证码时:仅限制 60 秒内不能重复发送;到期可覆盖重发(避免前端倒计时结束仍提示频繁)
|
||||
if (StrUtil.isNotBlank(codeObj)) {
|
||||
log.info("手机号验证码未过期:{},{}", mobile, codeObj);
|
||||
return R.ok(Boolean.FALSE, MsgUtils.getMessage(ErrorCodes.SYS_APP_SMS_OFTEN));
|
||||
Long ttl = redisTemplate.getExpire(redisKey, TimeUnit.SECONDS);
|
||||
if (ttl != null && ttl > SMS_CODE_TTL_SECONDS - SMS_SEND_INTERVAL_SECONDS) {
|
||||
log.info("手机号验证码发送过频:{},剩余有效期{}秒", mobile, ttl);
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_APP_SMS_OFTEN));
|
||||
}
|
||||
}
|
||||
|
||||
String code = RandomUtil.randomNumbers(SMS_CODE_LENGTH);
|
||||
log.info("手机号生成验证码成功:{},{}", mobile, code);
|
||||
redisTemplate.opsForValue().set(redisKey, code, SecurityConstants.CODE_TIME, TimeUnit.SECONDS);
|
||||
redisTemplate.opsForValue().set(redisKey, code, SMS_CODE_TTL_SECONDS, TimeUnit.SECONDS);
|
||||
|
||||
try {
|
||||
remoterThirdPartySmsService.sendVerificationCode(mobile, code);
|
||||
return R.ok(Boolean.TRUE);
|
||||
// data=是否已注册,便于移动端未注册时引导邀请注册
|
||||
return R.ok(registered);
|
||||
} catch (Exception e) {
|
||||
redisTemplate.delete(redisKey);
|
||||
log.error("发送短信验证码失败: mobile={}", mobile, e);
|
||||
@@ -296,6 +301,22 @@ public class SysMessageServiceImpl extends ServiceImpl<SysMessageMapper, SysMess
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verifySmsCode(String mobile, String code, boolean consume) {
|
||||
if (StrUtil.isBlank(mobile) || StrUtil.isBlank(code)) {
|
||||
return false;
|
||||
}
|
||||
String redisKey = CacheConstants.DEFAULT_CODE_KEY + LoginTypeEnum.SMS.getType() + StringPool.AT + mobile.trim();
|
||||
String saveCode = redisTemplate.opsForValue().get(redisKey);
|
||||
if (StrUtil.isBlank(saveCode) || !StrUtil.equals(saveCode, code.trim())) {
|
||||
return false;
|
||||
}
|
||||
if (consume) {
|
||||
redisTemplate.delete(redisKey);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送短信
|
||||
*
|
||||
|
||||
+5
@@ -637,6 +637,11 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
sysUser.setNickname(PersonNameUtils.normalize(userDto.getNickname()));
|
||||
sysUser.setName(PersonNameUtils.normalize(userDto.getName()));
|
||||
sysUser.setEmail(userDto.getEmail());
|
||||
// 身份证选填:传空串则清空
|
||||
if (userDto.getIdCard() != null) {
|
||||
String idCard = StrUtil.trim(userDto.getIdCard());
|
||||
sysUser.setIdCard(StrUtil.isBlank(idCard) ? "" : idCard);
|
||||
}
|
||||
// 个人资料:未传手机号时不修改(移动端手机号不可编辑)
|
||||
if (StrUtil.isNotBlank(userDto.getPhone()) && !userDto.getPhone().contains("*")) {
|
||||
sysUser.setPhone(userDto.getPhone());
|
||||
|
||||
Reference in new issue
Block a user