puzhibing
2026-09-28 d5a8e1c054431418fa895928ae2e3429295a9865
ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/service/impl/TVinManagementServiceImpl.java
@@ -15,16 +15,12 @@
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.security.service.TokenService;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.order.api.feignClient.ChargingOrderClient;
import com.ruoyi.order.api.vo.VinChargingStatusVO;
import com.ruoyi.other.api.domain.TFleet;
import com.ruoyi.other.api.domain.TGroupCompany;
import com.ruoyi.other.api.feignClient.GroupCompanyClient;
import com.ruoyi.system.api.domain.SysUser;
import com.ruoyi.system.api.feignClient.SysUserClient;
import com.ruoyi.system.api.model.LoginUser;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
@@ -70,12 +66,6 @@
    @Resource
    private GroupCompanyClient groupCompanyClient;
    @Resource
    private TokenService tokenService;
    @Resource
    private SysUserClient sysUserClient;
    @Resource
    private RedissonClient redissonClient;
@@ -166,6 +156,44 @@
        }
    }
    @Override public boolean deleteVins(List<Long> ids) { if (ids == null || ids.isEmpty()) throw new ServiceException("请选择需要删除的VIN码"); List<Long> distinct = new ArrayList<>(new HashSet<>(ids)); if (listByIds(distinct).size() != distinct.size()) throw new ServiceException("部分VIN码不存在或已删除"); return removeByIds(distinct); }
    /**
     * 批量解绑车队:仅清空车队归属(fleet_id 置空),公司、初始分配额度、状态等不受影响;
     * 未绑定车队的选中记录忽略不计
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int unbindFleet(List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            throw new ServiceException("请选择需要解绑车队的VIN码");
        }
        List<Long> distinct = ids.stream().filter(Objects::nonNull).distinct().collect(Collectors.toList());
        if (distinct.isEmpty()) {
            throw new ServiceException("请选择需要解绑车队的VIN码");
        }
        List<TVinManagement> records = listByIds(distinct);
        if (records.size() != distinct.size()) {
            throw new ServiceException("部分VIN码不存在或已删除");
        }
        List<Long> boundIds = records.stream()
                .filter(record -> record.getFleetId() != null)
                .map(TVinManagement::getId)
                .collect(Collectors.toList());
        if (boundIds.isEmpty()) {
            return 0;
        }
        // 显式 set null 清空车队归属(MyBatis-Plus 字段策略会忽略实体 null,需走 UpdateWrapper)
        boolean updated = lambdaUpdate()
                .in(TVinManagement::getId, boundIds)
                .set(TVinManagement::getFleetId, null)
                .set(TVinManagement::getUpdateTime, LocalDateTime.now())
                .set(TVinManagement::getUpdateBy, SecurityUtils.getUserId())
                .update();
        if (!updated) {
            throw new ServiceException("VIN码车队解绑失败,请重试");
        }
        return boundIds.size();
    }
    @Override public boolean updateStatus(Long id, Integer status) { if (id == null || !validStatus(status)) throw new ServiceException("VIN码状态参数错误"); if (getById(id) == null) throw new ServiceException("VIN码不存在或已删除"); TVinManagement item = new TVinManagement(); item.setId(id); item.setStatus(status); item.setUpdateTime(LocalDateTime.now()); item.setUpdateBy(SecurityUtils.getUserId()); return updateById(item); }
    @Override public List<VinManagementExcelDTO> selectExportList(VinManagementQueryDTO query) { return baseMapper.selectExportList(query == null ? new VinManagementQueryDTO() : query); }
    @Override public List<TVinManagement> selectAppletVehicleList(Long appUserId) {
@@ -235,7 +263,6 @@
    @Transactional(rollbackFor = Exception.class)
    public VinManagementAllocateVO allocateQuota(VinManagementAllocateDTO dto) {
        Map<Long, BigDecimal> amounts = validateAllocateRequest(dto);
        verifyOperationPassword(dto.getOperationPassword());
        Integer companyId = dto.getCompanyId();
        // 公司必须存在、启用且为分配模式(共享模式不支持额度分配)
        TGroupCompany company = loadAllocationCompany(companyId);
@@ -474,9 +501,6 @@
        if (dto.getItems().size() > MAX_ALLOCATE_VIN_COUNT) {
            throw new ServiceException("单次最多分配" + MAX_ALLOCATE_VIN_COUNT + "条VIN码");
        }
        if (StringUtils.isEmpty(dto.getOperationPassword())) {
            throw new ServiceException("请输入操作密码");
        }
        Map<Long, BigDecimal> amounts = new LinkedHashMap<>();
        for (VinManagementAllocateItemDTO item : dto.getItems()) {
            if (item == null || item.getVinId() == null) {
@@ -517,22 +541,6 @@
            return "公司可分配余额不足,无法完成本次分配";
        }
        return "公司可用余额扣减失败:" + msg;
    }
    /** 校验操作密码(与卡片管理一致,使用账号操作密码二次确认) */
    private void verifyOperationPassword(String operationPassword) {
        LoginUser loginUser = tokenService.getLoginUser();
        if (loginUser == null || loginUser.getUserid() == null) {
            throw new ServiceException("登录状态已失效,请重新登录");
        }
        R<SysUser> response = sysUserClient.getSysUser(loginUser.getUserid());
        SysUser user = response == null ? null : response.getData();
        if (user == null || StringUtils.isEmpty(user.getOperationPassword())) {
            throw new ServiceException("当前账号未设置操作密码");
        }
        if (!SecurityUtils.matchesPassword(operationPassword, user.getOperationPassword())) {
            throw new ServiceException("操作密码错误");
        }
    }
    /** 抢占并发锁,抢占失败抛出业务异常 */