chenxiaofei 6 ore în urmă
părinte
comite
d12ec83f1b

+ 4 - 4
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/service/operateService/KwcContractTradeService.java

@@ -2566,10 +2566,10 @@ public class KwcContractTradeService {
             log.debug("供应商登录,使用登录企业ID[{}]和企业类型[{}]进行查询",
             log.debug("供应商登录,使用登录企业ID[{}]和企业类型[{}]进行查询",
                     contractTradeOrderDto.getEntId(), contractTradeOrderDto.getEntType());
                     contractTradeOrderDto.getEntId(), contractTradeOrderDto.getEntType());
         } else if (Objects.equals(LoginUserHolder.getEntTypes(), CooperateTypeEnum.PURCHASER.getCode())) {
         } else if (Objects.equals(LoginUserHolder.getEntTypes(), CooperateTypeEnum.PURCHASER.getCode())) {
-            // 采购商登录时,企业ID从商品表获取,忽略前端传入的企业ID
-//            if (Objects.isNull(contractTradeOrderDto.getGoodsId())) {
-//                throw new BusinessException("商品id不能为空!");
-//            }
+            // 采购商登录时,企业ID从商品表获取,忽略前端传入的企业ID,兼容前端之前可能不会传商品id的情况,增加校验
+            if (Objects.isNull(contractTradeOrderDto.getGoodsId()) && Objects.equals(contractTradeOrderDto.getEntType(), 1)) {
+                throw new BusinessException("商品id不能为空!");
+            }
             KwpGoods kwpGoods = goodsInfoService.getGoodsById(contractTradeOrderDto.getGoodsId());
             KwpGoods kwpGoods = goodsInfoService.getGoodsById(contractTradeOrderDto.getGoodsId());
             if (Objects.isNull(kwpGoods) || Objects.isNull(kwpGoods.getEntId())) {
             if (Objects.isNull(kwpGoods) || Objects.isNull(kwpGoods.getEntId())) {
                 throw new BusinessException("商品不存在或商品企业信息缺失!");
                 throw new BusinessException("商品不存在或商品企业信息缺失!");

+ 10 - 0
sckw-modules/sckw-fleet/src/main/java/com/sckw/fleet/controller/KwfDriverController.java

@@ -170,6 +170,16 @@ public class KwfDriverController {
         return driverService.add(params);
         return driverService.add(params);
     }
     }
 
 
+    /**
+     * 司机自助注册
+     */
+    @Operation(summary = "司机注册", description = "司机端自助注册,需短信验证码")
+    @PostMapping("/register")
+    public HttpResult register(@Valid @RequestBody DriverRegisterDto params) {
+        return driverService.register(params);
+    }
+
+
     /**
     /**
      * @param params {}
      * @param params {}
      * @desc 更新
      * @desc 更新

+ 52 - 0
sckw-modules/sckw-fleet/src/main/java/com/sckw/fleet/model/dto/DriverRegisterDto.java

@@ -0,0 +1,52 @@
+package com.sckw.fleet.model.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Pattern;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+/**
+ * 司机注册入参
+ */
+@Data
+public class DriverRegisterDto {
+
+    /**
+     * 所属物流企业ID
+     */
+    @NotNull(message = "所属物流公司不能为空")
+    @Schema(description = "所属物流公司ID")
+    private Long entId;
+
+    /**
+     * 司机姓名
+     */
+    @NotBlank(message = "姓名不能为空")
+    @Schema(description = "司机姓名")
+    private String name;
+
+    /**
+     * 身份证号
+     */
+    @NotBlank(message = "身份证号不能为空")
+    @Pattern(regexp = "[0-9A-Za-z]{18}", message = "身份证号码格式不正确")
+    @Schema(description = "身份证号")
+    private String idcard;
+
+    /**
+     * 手机号
+     */
+    @NotBlank(message = "电话号码不能为空")
+    @Pattern(regexp = "^1[3456789]\\d{9}$", message = "电话号码格式不正确")
+    @Schema(description = "手机号")
+    private String phone;
+
+    /**
+     * 短信验证码
+     */
+    @NotBlank(message = "验证码不能为空")
+    @Schema(description = "短信验证码")
+    private String captcha;
+}

+ 20 - 0
sckw-modules/sckw-fleet/src/main/java/com/sckw/fleet/model/vo/DriverRegisterLogisticsEntVo.java

@@ -0,0 +1,20 @@
+package com.sckw.fleet.model.vo;
+
+import lombok.Data;
+
+/**
+ * 司机注册-所属物流企业选项
+ */
+@Data
+public class DriverRegisterLogisticsEntVo {
+
+    /**
+     * 企业ID
+     */
+    private Long entId;
+
+    /**
+     * 企业名称
+     */
+    private String firmName;
+}

+ 173 - 0
sckw-modules/sckw-fleet/src/main/java/com/sckw/fleet/service/KwfDriverService.java

@@ -583,6 +583,179 @@ public class KwfDriverService {
         return HttpResult.ok(result.getMsg(), driver);
         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 仍会提交;失败时必须抛异常以驱动回滚。
      * 全局事务下子步骤若仅用 {@link HttpResult} 表示失败而不抛异常,TM 仍会提交;失败时必须抛异常以驱动回滚。
      */
      */

+ 1 - 1
sckw-modules/sckw-system/src/main/java/com/sckw/system/service/KwsEnterpriseService.java

@@ -1684,7 +1684,7 @@ public class KwsEnterpriseService {
     }
     }
 
 
     public List<EntInfo> queryEnterpriseByPageType(EnterprisePageQueryReqVo req) {
     public List<EntInfo> queryEnterpriseByPageType(EnterprisePageQueryReqVo req) {
-        log.info("查询企业信息请求参数:{}", JSON.toJSONString(req));
+        log.info("根据企业类型查询企业信息请求参数:{}", JSON.toJSONString(req));
 
 
         Long loginEntId = LoginUserHolder.getEntId();
         Long loginEntId = LoginUserHolder.getEntId();
         if (Objects.isNull(loginEntId)) {
         if (Objects.isNull(loginEntId)) {

+ 7 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/param/WaybillOrderStatusResp.java

@@ -207,6 +207,13 @@ public class WaybillOrderStatusResp implements Serializable {
      */
      */
     @Schema(description = "状态描述")
     @Schema(description = "状态描述")
     private String statusDesc;
     private String statusDesc;
+
+    /**
+     * 是否展示打印按钮(待离场状态展示)
+     */
+    @Schema(description = "是否展示打印按钮")
+    private Boolean showPrintButton;
+
     /**
     /**
      * 订单余量
      * 订单余量
      */
      */

+ 2 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/service/app/WaybillOrderService.java

@@ -933,6 +933,8 @@ public class WaybillOrderService {
         } else {
         } else {
             wbOrderResp.setStatusDesc("未知状态");
             wbOrderResp.setStatusDesc("未知状态");
         }
         }
+        //打印按钮
+        wbOrderResp.setShowPrintButton(Objects.equals(wbOrder.getStatus(), CarWaybillV1Enum.WAIT_LEAVE.getCode()));
 
 
         return wbOrderResp;
         return wbOrderResp;