|
|
@@ -583,6 +583,179 @@ public class KwfDriverService {
|
|
|
return HttpResult.ok(result.getMsg(), driver);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 司机自助注册。
|
|
|
+ * <p>
|
|
|
+ * 面向司机端注册页,无需登录态。整体流程参照 {@link #add(KwfDriverDto)},但差异如下:
|
|
|
+ * <ul>
|
|
|
+ * <li>必须校验短信验证码(类型:{@link DictEnum#SMS_REGISTER})</li>
|
|
|
+ * <li>手机号、身份证号全局唯一,已存在则直接返回业务错误</li>
|
|
|
+ * <li>所属物流企业由前端传入 entId,不依赖 {@link LoginUserHolder}</li>
|
|
|
+ * <li>注册后认证状态为「临时」({@link Global#NUMERICAL_TWO}),待后续补全证件</li>
|
|
|
+ * <li>同步创建 system 用户并绑定司机角色({@link #registerUserEdit(DriverRegisterDto, Long)})</li>
|
|
|
+ * </ul>
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param params 注册入参(物流企业、姓名、身份证号、手机号、短信验证码)
|
|
|
+ * @return 注册成功返回司机档案;校验失败返回对应错误信息
|
|
|
+ */
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public HttpResult register(DriverRegisterDto params) {
|
|
|
+ log.info("司机自助注册开始,entId={}, phone={}, name={}, idcard={}",
|
|
|
+ params.getEntId(), maskPhone(params.getPhone()), params.getName(), maskIdcard(params.getIdcard()));
|
|
|
+
|
|
|
+ // 1. 校验短信验证码(失败抛 SystemException,触发事务回滚)
|
|
|
+ validateRegisterCaptcha(params.getPhone(), params.getCaptcha());
|
|
|
+ log.info("司机自助注册短信验证码校验通过,phone={}", maskPhone(params.getPhone()));
|
|
|
+
|
|
|
+ // 2. 校验所属物流企业是否存在
|
|
|
+ EntCacheResDto entCache = remoteSystemService.queryEntCacheById(params.getEntId());
|
|
|
+ if (entCache == null) {
|
|
|
+ log.warn("司机自助注册失败,所属物流企业不存在,entId={}, phone={}", params.getEntId(), maskPhone(params.getPhone()));
|
|
|
+ return HttpResult.error("所属物流公司不存在");
|
|
|
+ }
|
|
|
+ log.info("司机自助注册物流企业校验通过,entId={}, firmName={}", params.getEntId(), entCache.getFirmName());
|
|
|
+
|
|
|
+ // 3. 校验手机号唯一性
|
|
|
+ List<KwfDriver> phoneDrivers = driverDao.findDriver(new HashMap<String, Object>() {{
|
|
|
+ put("phone", params.getPhone());
|
|
|
+ }});
|
|
|
+ if (CollectionUtils.isNotEmpty(phoneDrivers)) {
|
|
|
+ log.warn("司机自助注册失败,手机号已存在,phone={}, existDriverId={}",
|
|
|
+ maskPhone(params.getPhone()), phoneDrivers.get(Global.NUMERICAL_ZERO).getId());
|
|
|
+ return HttpResult.error("电话号码已存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 校验身份证号唯一性
|
|
|
+ List<KwfDriver> idcardDrivers = driverDao.findDriver(new HashMap<String, Object>() {{
|
|
|
+ put("idcard", params.getIdcard());
|
|
|
+ }});
|
|
|
+ if (CollectionUtils.isNotEmpty(idcardDrivers)) {
|
|
|
+ log.warn("司机自助注册失败,身份证号已存在,idcard={}, existDriverId={}",
|
|
|
+ maskIdcard(params.getIdcard()), idcardDrivers.get(Global.NUMERICAL_ZERO).getId());
|
|
|
+ return HttpResult.error("身份证号已存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5. 构建司机档案(默认密码规则与后台新增司机一致:手机号 + MD5(手机号))
|
|
|
+ KwfDriver driver = new KwfDriver();
|
|
|
+ driver.setName(params.getName());
|
|
|
+ driver.setPhone(params.getPhone());
|
|
|
+ driver.setIdcard(params.getIdcard());
|
|
|
+ driver.setEntId(params.getEntId());
|
|
|
+ driver.setAuthStatus(Global.NUMERICAL_TWO);
|
|
|
+ String salt = PasswordUtils.generateSalt();
|
|
|
+ String md5 = PasswordUtils.md5(params.getPhone());
|
|
|
+ driver.setPassword(PasswordUtils.entryptPassword(params.getPhone() + md5, salt));
|
|
|
+ driver.setSalt(salt);
|
|
|
+ driver.setBusinessStatus(Global.NO);
|
|
|
+ driver.setStatus(Global.NO);
|
|
|
+
|
|
|
+
|
|
|
+ // 6. 落库司机主表
|
|
|
+ if (driverDao.insert(driver) <= 0) {
|
|
|
+ log.error("司机自助注册失败,司机档案入库失败,phone={}, entId={}", maskPhone(params.getPhone()), params.getEntId());
|
|
|
+ return HttpResult.error("司机注册失败");
|
|
|
+ }
|
|
|
+ log.info("司机自助注册司机档案入库成功,driverId={}, phone={}, entId={}",
|
|
|
+ driver.getId(), maskPhone(params.getPhone()), params.getEntId());
|
|
|
+
|
|
|
+ // 7. 建立司机与企业关联关系
|
|
|
+ driverEntEdit(driver);
|
|
|
+ log.info("司机自助注册企业关联完成,driverId={}, entId={}", driver.getId(), params.getEntId());
|
|
|
+
|
|
|
+ // 8. 同步 system 用户及司机角色
|
|
|
+ registerUserEdit(params, driver.getId());
|
|
|
+ log.info("司机自助注册系统用户同步完成,driverId={}, phone={}", driver.getId(), maskPhone(params.getPhone()));
|
|
|
+
|
|
|
+ // 9. 注册成功后清除验证码,防止重复使用
|
|
|
+ String captchaKey = StringUtils.format(RedisConstant.MESSAGE_SMS_VERIFY_CODE_VALUE_KEY,
|
|
|
+ DictEnum.SMS_REGISTER.getValue(), params.getPhone());
|
|
|
+ RedissonUtils.delete(captchaKey);
|
|
|
+
|
|
|
+ log.info("司机自助注册成功,driverId={}, phone={}, entId={}, firmName={}",
|
|
|
+ driver.getId(), maskPhone(params.getPhone()), params.getEntId(), entCache.getFirmName());
|
|
|
+ return HttpResult.ok("注册成功", driver);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 校验司机注册短信验证码。
|
|
|
+ * <p>验证码存储在 Redis,key 规则与 {@link DictEnum#SMS_REGISTER} 及手机号关联。</p>
|
|
|
+ *
|
|
|
+ * @param phone 注册手机号
|
|
|
+ * @param captcha 用户输入的验证码
|
|
|
+ */
|
|
|
+ private void validateRegisterCaptcha(String phone, String captcha) {
|
|
|
+ String key = StringUtils.format(RedisConstant.MESSAGE_SMS_VERIFY_CODE_VALUE_KEY,
|
|
|
+ DictEnum.SMS_REGISTER.getValue(), phone);
|
|
|
+ String smsCaptcha = RedissonUtils.getString(key);
|
|
|
+ if (StringUtils.isBlank(smsCaptcha)) {
|
|
|
+ log.warn("司机自助注册验证码已过期或不存在,phone={}", maskPhone(phone));
|
|
|
+ throw new SystemException(HttpStatus.UN_LOGIN_CODE, "验证码已过期,请重新获取!");
|
|
|
+ }
|
|
|
+ if (!captcha.equals(smsCaptcha)) {
|
|
|
+ log.warn("司机自助注册验证码错误,phone={}", maskPhone(phone));
|
|
|
+ throw new SystemException(HttpStatus.UN_LOGIN_CODE, "验证码错误");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 司机注册后同步 system 用户信息。
|
|
|
+ * <p>
|
|
|
+ * 调用远程 {@link RemoteUserService#saveUser(KwsUserReqDto)}:
|
|
|
+ * 按手机号幂等创建/更新用户,并自动绑定所属企业下的「司机」角色。
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param params 注册入参
|
|
|
+ * @param driverId 已入库的司机档案主键
|
|
|
+ */
|
|
|
+ private void registerUserEdit(DriverRegisterDto params, Long driverId) {
|
|
|
+ log.info("开始同步司机注册系统用户,driverId={}, phone={}, entId={}",
|
|
|
+ driverId, maskPhone(params.getPhone()), params.getEntId());
|
|
|
+ KwsUserReqDto kwsUserReqDto = new KwsUserReqDto();
|
|
|
+ String salt = PasswordUtils.generateSalt();
|
|
|
+ kwsUserReqDto.setSystemType(SystemTypeEnum.DRIVER.getCode());
|
|
|
+ kwsUserReqDto.setEntId(params.getEntId());
|
|
|
+ kwsUserReqDto.setAccount(params.getPhone());
|
|
|
+ kwsUserReqDto.setPassword(PasswordUtils.entryptPassword(params.getPhone() + PasswordUtils.md5(params.getPhone()), salt));
|
|
|
+ kwsUserReqDto.setName(params.getName());
|
|
|
+ kwsUserReqDto.setPhone(params.getPhone());
|
|
|
+ kwsUserReqDto.setPhoto("");
|
|
|
+ kwsUserReqDto.setEmail("");
|
|
|
+ kwsUserReqDto.setClientId("");
|
|
|
+ kwsUserReqDto.setIsMain(0);
|
|
|
+ kwsUserReqDto.setSalt(salt);
|
|
|
+ kwsUserReqDto.setRemark("司机注册");
|
|
|
+ kwsUserReqDto.setStatus(0);
|
|
|
+ Date date = new Date();
|
|
|
+ kwsUserReqDto.setCreateBy(LoginUserHolder.getUserId());
|
|
|
+ kwsUserReqDto.setCreateTime(date);
|
|
|
+ kwsUserReqDto.setUpdateBy(LoginUserHolder.getUserId());
|
|
|
+ kwsUserReqDto.setUpdateTime(date);
|
|
|
+ kwsUserReqDto.setDelFlag(0);
|
|
|
+ kwsUserReqDto.setDriverId(driverId);
|
|
|
+ remoteUserService.saveUser(kwsUserReqDto);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 手机号脱敏,用于日志输出(保留前3后4)。
|
|
|
+ */
|
|
|
+ private String maskPhone(String phone) {
|
|
|
+ if (StringUtils.isBlank(phone) || phone.length() < 7) {
|
|
|
+ return phone;
|
|
|
+ }
|
|
|
+ return phone.substring(0, 3) + "****" + phone.substring(phone.length() - 4);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 身份证号脱敏,用于日志输出(保留前6后4)。
|
|
|
+ */
|
|
|
+ private String maskIdcard(String idcard) {
|
|
|
+ if (StringUtils.isBlank(idcard) || idcard.length() < 10) {
|
|
|
+ return idcard;
|
|
|
+ }
|
|
|
+ return idcard.substring(0, 6) + "********" + idcard.substring(idcard.length() - 4);
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 全局事务下子步骤若仅用 {@link HttpResult} 表示失败而不抛异常,TM 仍会提交;失败时必须抛异常以驱动回滚。
|
|
|
*/
|