Huanyi 1 день назад
Родитель
Сommit
a51ae03ed6

+ 1 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysAppletIndexCategoriesServiceImpl.java

@@ -37,7 +37,7 @@ public class SysAppletIndexCategoriesServiceImpl implements ISysAppletIndexCateg
         return baseMapper.selectVoById(id);
     }
 
-    @CacheEvict(cacheNames = CacheNames.SYS_APPLET_CATEGORIES, allEntries = true)
+    @CacheEvict(cacheNames = CacheNames.SYS_APPLET_CATEGORIES, allEntries = true, beforeInvocation = true)
     @Override
     public Boolean updateByBo(SysAppletIndexCategoriesBo bo) {
         SysAppletIndexCategories entity = MapstructUtils.convert(bo, SysAppletIndexCategories.class);

+ 11 - 5
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysAppletIndexSlideshowServiceImpl.java

@@ -1,6 +1,8 @@
 package org.dromara.system.service.impl;
 
 import lombok.RequiredArgsConstructor;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import org.dromara.common.core.constant.CacheNames;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.system.domain.SysAppletIndexSlideshow;
@@ -37,21 +39,25 @@ public class SysAppletIndexSlideshowServiceImpl implements ISysAppletIndexSlides
         return baseMapper.selectVoById(id);
     }
 
-    @CacheEvict(cacheNames = CacheNames.SYS_APPLET_SLIDESHOW, allEntries = true)
+    @CacheEvict(cacheNames = CacheNames.SYS_APPLET_SLIDESHOW, allEntries = true, beforeInvocation = true)
     @Override
     public Boolean insertByBo(SysAppletIndexSlideshowBo bo) {
         SysAppletIndexSlideshow entity = MapstructUtils.convert(bo, SysAppletIndexSlideshow.class);
         return baseMapper.insert(entity) > 0;
     }
 
-    @CacheEvict(cacheNames = CacheNames.SYS_APPLET_SLIDESHOW, allEntries = true)
+    @CacheEvict(cacheNames = CacheNames.SYS_APPLET_SLIDESHOW, allEntries = true, beforeInvocation = true)
     @Override
     public Boolean updateByBo(SysAppletIndexSlideshowBo bo) {
-        SysAppletIndexSlideshow entity = MapstructUtils.convert(bo, SysAppletIndexSlideshow.class);
-        return baseMapper.updateById(entity) > 0;
+        LambdaUpdateWrapper<SysAppletIndexSlideshow> wrapper = new LambdaUpdateWrapper<>();
+        wrapper.eq(SysAppletIndexSlideshow::getId, bo.getId());
+        if (ObjectUtil.isNotNull(bo.getOssId())) {
+            wrapper.set(SysAppletIndexSlideshow::getOssId, bo.getOssId());
+        }
+        return baseMapper.update(null, wrapper) > 0;
     }
 
-    @CacheEvict(cacheNames = CacheNames.SYS_APPLET_SLIDESHOW, allEntries = true)
+    @CacheEvict(cacheNames = CacheNames.SYS_APPLET_SLIDESHOW, allEntries = true, beforeInvocation = true)
     @Override
     public Boolean deleteByIds(List<Long> ids) {
         return baseMapper.deleteBatchIds(ids) > 0;

+ 13 - 2
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysComplaintServiceImpl.java

@@ -1,6 +1,7 @@
 package org.dromara.system.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import lombok.RequiredArgsConstructor;
@@ -107,8 +108,18 @@ public class SysComplaintServiceImpl implements ISysComplaintService {
 
     @Override
     public Boolean updateByBo(SysComplaintBo bo) {
-        SysComplaint update = MapstructUtils.convert(bo, SysComplaint.class);
-        return baseMapper.updateById(update) > 0;
+        LambdaUpdateWrapper<SysComplaint> wrapper = Wrappers.lambdaUpdate();
+        wrapper.eq(SysComplaint::getId, bo.getId());
+
+        if (StringUtils.isNotBlank(bo.getFeedbackType())) wrapper.set(SysComplaint::getFeedbackType, bo.getFeedbackType());
+        if (StringUtils.isNotBlank(bo.getContent())) wrapper.set(SysComplaint::getContent, bo.getContent());
+        if (StringUtils.isNotBlank(bo.getImages())) wrapper.set(SysComplaint::getImages, bo.getImages());
+        if (bo.getEmployeeId() != null) wrapper.set(SysComplaint::getEmployeeId, bo.getEmployeeId());
+        if (StringUtils.isNotBlank(bo.getStatus())) wrapper.set(SysComplaint::getStatus, bo.getStatus());
+        if (StringUtils.isNotBlank(bo.getDealResult())) wrapper.set(SysComplaint::getDealResult, bo.getDealResult());
+        if (StringUtils.isNotBlank(bo.getDealImages())) wrapper.set(SysComplaint::getDealImages, bo.getDealImages());
+
+        return baseMapper.update(null, wrapper) > 0;
     }
 
     @Override

+ 68 - 21
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysEmployeeServiceImpl.java

@@ -23,6 +23,7 @@ import org.dromara.yingpaipay.api.erp.CommonErpClientService;
 import org.dromara.yingpaipay.api.erp.domain.vo.CommonErpClientVo;
 import org.springframework.cache.annotation.Cacheable;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -203,38 +204,84 @@ public class SysEmployeeServiceImpl implements ISysEmployeeService, EmployeeServ
 
     /**
      * 修改员工(仅更新非 null 字段,支持部分更新)
+     * 使用数据库行锁(FOR UPDATE)解决 TOCTOU 竞态条件
      */
+    @Transactional
     @Override
     public Boolean updateByBo(SysEmployeeBo bo) {
-        SysEmployee update = MapstructUtils.convert(bo, SysEmployee.class);
-        LambdaUpdateWrapper<SysEmployee> wrapper = new LambdaUpdateWrapper<>();
-        wrapper.eq(SysEmployee::getId, update.getId());
-        if (ObjectUtil.isNotNull(update.getName())) {
-            wrapper.set(SysEmployee::getName, update.getName());
+        baseMapper.selectOne(
+            Wrappers.lambdaQuery(SysEmployee.class)
+                .eq(SysEmployee::getId, bo.getId())
+                .last("FOR UPDATE")
+        );
+
+        if (StringUtils.isNotBlank(bo.getAuthClientFRowIDs())) {
+            Set<String> newRowIds = Arrays.stream(bo.getAuthClientFRowIDs().split(","))
+                .map(String::trim)
+                .filter(StringUtils::isNotBlank)
+                .collect(Collectors.toSet());
+            if (!newRowIds.isEmpty()) {
+                List<SysEmployee> otherEmployees = baseMapper.selectList(
+                    Wrappers.lambdaQuery(SysEmployee.class)
+                        .select(SysEmployee::getId, SysEmployee::getAuthClientFRowIDs)
+                        .ne(SysEmployee::getId, bo.getId())
+                        .isNotNull(SysEmployee::getAuthClientFRowIDs)
+                        .ne(SysEmployee::getAuthClientFRowIDs, "")
+                        .last("FOR UPDATE")
+                );
+                Set<String> conflictRowIds = new HashSet<>();
+                for (SysEmployee other : otherEmployees) {
+                    if (StringUtils.isBlank(other.getAuthClientFRowIDs())) {
+                        continue;
+                    }
+                    for (String id : other.getAuthClientFRowIDs().split(",")) {
+                        String trimmed = id.trim();
+                        if (newRowIds.contains(trimmed)) {
+                            conflictRowIds.add(trimmed);
+                        }
+                    }
+                }
+                if (!conflictRowIds.isEmpty()) {
+                    Map<String, CommonErpClientVo> infoMap = commonErpClientService.selectInfoByFRowIDs(new ArrayList<>(conflictRowIds));
+                    String conflictNames = conflictRowIds.stream()
+                        .map(id -> {
+                            CommonErpClientVo vo = infoMap.get(id);
+                            return vo != null ? vo.getName() : id;
+                        })
+                        .collect(Collectors.joining("、"));
+                    throw new ServiceException("以下客户已被其他员工授权,请先取消后再操作:" + conflictNames);
+                }
+            }
         }
-        if (ObjectUtil.isNotNull(update.getPhone())) {
-            wrapper.set(SysEmployee::getPhone, update.getPhone());
+
+        if (bo.getId() != null) {
+            CacheUtils.evict(CacheNames.SYS_EMPLOYEE_NAME, bo.getId());
         }
-        if (ObjectUtil.isNotNull(update.getAvatar())) {
-            wrapper.set(SysEmployee::getAvatar, update.getAvatar());
+
+        LambdaUpdateWrapper<SysEmployee> wrapper = new LambdaUpdateWrapper<>();
+        wrapper.eq(SysEmployee::getId, bo.getId());
+        if (ObjectUtil.isNotNull(bo.getName())) {
+            wrapper.set(SysEmployee::getName, bo.getName());
         }
-        if (ObjectUtil.isNotNull(update.getStatus())) {
-            wrapper.set(SysEmployee::getStatus, update.getStatus());
+        if (ObjectUtil.isNotNull(bo.getPhone())) {
+            wrapper.set(SysEmployee::getPhone, bo.getPhone());
         }
-        if (ObjectUtil.isNotNull(update.getAuthClientFRowIDs())) {
-            wrapper.set(SysEmployee::getAuthClientFRowIDs, update.getAuthClientFRowIDs());
+        if (ObjectUtil.isNotNull(bo.getAvatar())) {
+            wrapper.set(SysEmployee::getAvatar, bo.getAvatar());
         }
-        if (ObjectUtil.isNotNull(update.getWechatOpenid())) {
-            wrapper.set(SysEmployee::getWechatOpenid, update.getWechatOpenid());
+        if (ObjectUtil.isNotNull(bo.getStatus())) {
+            wrapper.set(SysEmployee::getStatus, bo.getStatus());
         }
-        if (ObjectUtil.isNotNull(update.getWechatUnionid())) {
-            wrapper.set(SysEmployee::getWechatUnionid, update.getWechatUnionid());
+        if (ObjectUtil.isNotNull(bo.getAuthClientFRowIDs())) {
+            wrapper.set(SysEmployee::getAuthClientFRowIDs, bo.getAuthClientFRowIDs());
         }
-        boolean result = baseMapper.update(null, wrapper) > 0;
-        if (result && bo.getId() != null) {
-            CacheUtils.evict(CacheNames.SYS_EMPLOYEE_NAME, bo.getId());
+        if (ObjectUtil.isNotNull(bo.getWechatOpenid())) {
+            wrapper.set(SysEmployee::getWechatOpenid, bo.getWechatOpenid());
+        }
+        if (ObjectUtil.isNotNull(bo.getWechatUnionid())) {
+            wrapper.set(SysEmployee::getWechatUnionid, bo.getWechatUnionid());
         }
-        return result;
+        return baseMapper.update(null, wrapper) > 0;
     }
 
     /**

+ 23 - 5
ruoyi-modules/yingpaipay-erp/src/main/java/org/dromara/erp/service/impl/ErpOrderDetailServiceImpl.java

@@ -79,17 +79,35 @@ public class ErpOrderDetailServiceImpl implements IErpOrderDetailService {
 
     @Override
     public Boolean update(org.dromara.erp.domain.bo.ErpOrderDetailBo bo) {
-        ErpOrderDetail entity = MapstructUtils.convert(bo, ErpOrderDetail.class);
+        LambdaUpdateWrapper<ErpOrderDetail> wrapper = Wrappers.lambdaUpdate();
+        wrapper.eq(ErpOrderDetail::getRowId, bo.getRowId());
+
+        if (ObjectUtil.isNotEmpty(bo.getOrderId())) wrapper.set(ErpOrderDetail::getOrderId, bo.getOrderId());
+        if (bo.getPlacer() != null) wrapper.set(ErpOrderDetail::getPlacer, bo.getPlacer());
+        if (ObjectUtil.isNotEmpty(bo.getClientId())) wrapper.set(ErpOrderDetail::getClientId, bo.getClientId());
+        if (ObjectUtil.isNotEmpty(bo.getModelId())) wrapper.set(ErpOrderDetail::getModelId, bo.getModelId());
+        if (ObjectUtil.isNotEmpty(bo.getModelNum())) wrapper.set(ErpOrderDetail::getModelNum, bo.getModelNum());
+        if (ObjectUtil.isNotEmpty(bo.getModelName())) wrapper.set(ErpOrderDetail::getModelName, bo.getModelName());
+        if (ObjectUtil.isNotEmpty(bo.getMaterial())) wrapper.set(ErpOrderDetail::getMaterial, bo.getMaterial());
+        if (ObjectUtil.isNotEmpty(bo.getSurfaceId())) wrapper.set(ErpOrderDetail::getSurfaceId, bo.getSurfaceId());
+        if (ObjectUtil.isNotEmpty(bo.getSurfaceName())) wrapper.set(ErpOrderDetail::getSurfaceName, bo.getSurfaceName());
+        if (ObjectUtil.isNotEmpty(bo.getPackId())) wrapper.set(ErpOrderDetail::getPackId, bo.getPackId());
+        if (ObjectUtil.isNotEmpty(bo.getPackName())) wrapper.set(ErpOrderDetail::getPackName, bo.getPackName());
+        if (bo.getLength() != null) wrapper.set(ErpOrderDetail::getLength, bo.getLength());
+        if (bo.getWallThickness() != null) wrapper.set(ErpOrderDetail::getWallThickness, bo.getWallThickness());
+        if (bo.getMeterWeight() != null) wrapper.set(ErpOrderDetail::getMeterWeight, bo.getMeterWeight());
+        if (bo.getCount() != null) wrapper.set(ErpOrderDetail::getCount, bo.getCount());
+        if (ObjectUtil.isNotEmpty(bo.getDocCode())) wrapper.set(ErpOrderDetail::getDocCode, bo.getDocCode());
+        if (ObjectUtil.isNotEmpty(bo.getItemNo())) wrapper.set(ErpOrderDetail::getItemNo, bo.getItemNo());
 
-        // 审计字段回填
         Long userId = null;
         try {
             userId = org.dromara.common.satoken.utils.LoginHelper.getUserId();
         } catch (Exception e) {}
-        entity.setUpdateBy(userId);
-        entity.setUpdateTime(new Date());
+        wrapper.set(ErpOrderDetail::getUpdateBy, userId);
+        wrapper.set(ErpOrderDetail::getUpdateTime, new Date());
 
-        return baseMapper.updateById(entity) > 0;
+        return baseMapper.update(null, wrapper) > 0;
     }
 
     @Override

+ 16 - 9
ruoyi-modules/yingpaipay-erp/src/main/java/org/dromara/erp/service/impl/ErpOrderServiceImpl.java

@@ -7,6 +7,7 @@ import com.baomidou.lock.LockInfo;
 import com.baomidou.lock.LockTemplate;
 import com.baomidou.lock.executor.RedissonLockExecutor;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -217,18 +218,22 @@ public class ErpOrderServiceImpl implements IErpOrderService {
         if (Integer.valueOf(1).equals(order.getIsConfirmed())) {
             throw new org.dromara.common.core.exception.ServiceException("已确认的订单不可以撤销");
         }
-        order.setIsConfirmed(0);
-        return baseMapper.updateById(order) > 0;
+        LambdaUpdateWrapper<ErpOrder> wrapper = Wrappers.lambdaUpdate();
+        wrapper.eq(ErpOrder::getRowId, rowId)
+               .set(ErpOrder::getIsConfirmed, 0);
+        return baseMapper.update(null, wrapper) > 0;
     }
 
     @Override
     public Boolean markUrgent(String rowId) {
-        ErpOrder order = baseMapper.selectById(rowId);
-        if (order == null) {
-            throw new org.dromara.common.core.exception.ServiceException("订单不存在");
+        LambdaUpdateWrapper<ErpOrder> wrapper = Wrappers.lambdaUpdate();
+        wrapper.eq(ErpOrder::getRowId, rowId)
+               .set(ErpOrder::getUrgentFlag, 1);
+        int rows = baseMapper.update(null, wrapper);
+        if (rows == 0) {
+            throw new org.dromara.common.core.exception.RuntimeException("订单修改失败");
         }
-        order.setUrgentFlag(1);
-        return baseMapper.updateById(order) > 0;
+        return true;
     }
 
     @Override
@@ -267,8 +272,10 @@ public class ErpOrderServiceImpl implements IErpOrderService {
                 }
 
                 if (shouldConfirm) {
-                    order.setIsConfirmed(1);
-                    baseMapper.updateById(order);
+                    LambdaUpdateWrapper<ErpOrder> confirmWrapper = Wrappers.lambdaUpdate();
+                    confirmWrapper.eq(ErpOrder::getRowId, order.getRowId())
+                                  .set(ErpOrder::getIsConfirmed, 1);
+                    baseMapper.update(null, confirmWrapper);
                     updatedCount++;
                     log.info("[ERP状态同步] 订单 {} (ERP:{}) 状态更新为已确认",
                         order.getCode(), order.getDocCode());