Bläddra i källkod

完善门店的选择;商户端角色权限字符、头像上传完成

Huanyi 1 månad sedan
förälder
incheckning
093e46c5ff

+ 66 - 0
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java

@@ -8,6 +8,7 @@ import org.springframework.util.AntPathMatcher;
 
 import java.nio.charset.Charset;
 import java.util.*;
+import java.util.concurrent.ThreadLocalRandom;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
@@ -22,6 +23,14 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
 
     public static final String SLASH = "/";
 
+    private static final List<String> DEFAULT_CHARS = new ArrayList<>();
+    static {
+        for (char c = '0'; c <= '9'; c++) DEFAULT_CHARS.add(String.valueOf(c));
+        for (char c = 'a'; c <= 'z'; c++) DEFAULT_CHARS.add(String.valueOf(c));
+        for (char c = 'A'; c <= 'Z'; c++) DEFAULT_CHARS.add(String.valueOf(c));
+    }
+    private static final int MAX_RETRY = 1000;
+
     @Deprecated
     private StringUtils() {
     }
@@ -382,4 +391,61 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
         return StringUtils.join(array, SEPARATOR);
     }
 
+    /**
+     * 生成随机字符串
+     * @param excludes 不可重复生成已存在的
+     * @param chars 指定使用的字符集列表,为空则使用默认字符集
+     * @param length 生成字符串的长度
+     * @Author Huanyi
+     */
+    public static String generateStr(List<String> excludes, List<String> chars, int length) {
+
+        if (length <= 0) {
+            return "";
+        }
+
+        List<String> pool;
+        if (chars == null || chars.isEmpty()) {
+            pool = DEFAULT_CHARS;
+        } else {
+            pool = chars;
+        }
+        if (pool.isEmpty()) {
+            throw new IllegalArgumentException("字符集不能为空");
+        }
+
+        Set<String> excludeSet = (excludes == null) ? new HashSet<>() : new HashSet<>(excludes);
+
+        // 避免串行化的排队阻塞
+        ThreadLocalRandom random = ThreadLocalRandom.current();
+        StringBuilder sb = new StringBuilder();
+        int retryCount = 0;
+        String result;
+
+        while (retryCount < MAX_RETRY) {
+
+            // 清空
+            sb.setLength(0);
+
+            for (int i = 0; i < length; i++) {
+                int index = random.nextInt(pool.size());
+                sb.append(pool.get(index));
+            }
+            result = sb.toString();
+
+            if (!excludeSet.contains(result)) {
+                return result;
+            }
+
+            // 重试
+            retryCount++;
+        }
+
+        throw new RuntimeException(String.format(
+            "无法生成不重复的字符串:在 %d 次重试后仍命中黑名单。可能原因:长度(%d)太短、字符集太小(%d),或 excludes 列表过大导致可用组合耗尽。",
+            MAX_RETRY, length, pool.size()
+        ));
+
+    }
+
 }

+ 7 - 0
ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/constants/LockContants.java

@@ -0,0 +1,7 @@
+package org.dromara.common.redis.constants;
+
+public interface LockContants {
+
+    String ROLE = "lock_role:";
+
+}

+ 7 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/constants/StoreConstants.java

@@ -0,0 +1,7 @@
+package org.dromara.system.constants;
+
+public interface StoreConstants {
+
+    Long ALL_STORE = 0L;
+
+}

+ 2 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java

@@ -56,6 +56,7 @@ public class SysUserController extends BaseController {
     private final ISysPostService postService;
     private final ISysDeptService deptService;
     private final ISysTenantService tenantService;
+    private final ISysStoreService storeService;
 
     /**
      * 获取用户列表
@@ -154,6 +155,7 @@ public class SysUserController extends BaseController {
         roleBo.setStatus(SystemConstants.NORMAL);
         List<SysRoleVo> roles = roleService.selectRoleList(roleBo);
         userInfoVo.setRoles(LoginHelper.isSuperAdmin(userId) ? roles : StreamUtils.filter(roles, r -> !r.isSuperAdmin()));
+        userInfoVo.setStoreIds(storeService.selectStoreIds(userId));
         return R.ok(userInfoVo);
     }
 

+ 1 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRoleBo.java

@@ -38,7 +38,7 @@ public class SysRoleBo extends BaseEntity {
     /**
      * 角色权限字符串
      */
-    @NotBlank(message = "角色权限字符串不能为空")
+//    @NotBlank(message = "角色权限字符串不能为空")
     @Size(min = 0, max = 100, message = "权限字符长度不能超过{max}个字符")
     private String roleKey;
 

+ 7 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java

@@ -115,9 +115,16 @@ public class SysUserBo extends BaseEntity {
 
     /**
      * 门店组
+     * @Author Huanyi
      */
     private Long[] storeIds;
 
+    /**
+     * 用户头像
+     * @Author Huanyi
+     */
+    private Long avatar;
+
     public SysUserBo(Long userId) {
         this.userId = userId;
     }

+ 5 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserInfoVo.java

@@ -42,4 +42,9 @@ public class SysUserInfoVo implements Serializable {
      */
     private List<SysPostVo> posts;
 
+    /**
+     * 门店ID列表
+     */
+    private List<Long> storeIds;
+
 }

+ 2 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java

@@ -78,7 +78,8 @@ public class SysUserVo implements Serializable {
     /**
      * 头像地址
      */
-    @Translation(type = TransConstant.OSS_ID_TO_URL)
+    @Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "avatar")
+    private String avatarUrl;
     private Long avatar;
 
     /**

+ 2 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysStoreService.java

@@ -76,4 +76,6 @@ public interface ISysStoreService {
     List<SysStoreListOnMerchantStoreInfoVo> listOnMerchantStoreInfo();
 
     List<SysStoreListOnMerchantAccountInfoVo> listAll();
+
+    List<Long> selectStoreIds(Long userId);
 }

+ 16 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java

@@ -5,6 +5,8 @@ import cn.dev33.satoken.stp.StpUtil;
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.lock.LockInfo;
+import com.baomidou.lock.LockTemplate;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@@ -21,7 +23,9 @@ import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.platform.PlatformUtils;
+import org.dromara.common.redis.constants.LockContants;
 import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.tenant.helper.TenantHelper;
 import org.dromara.system.api.model.LoginUser;
 import org.dromara.system.domain.SysRole;
 import org.dromara.system.domain.SysRoleDept;
@@ -55,6 +59,8 @@ public class SysRoleServiceImpl implements ISysRoleService {
     private final SysUserRoleMapper userRoleMapper;
     private final SysRoleDeptMapper roleDeptMapper;
 
+    private final LockTemplate locker;
+
     /**
      * 分页查询角色列表
      *
@@ -297,10 +303,20 @@ public class SysRoleServiceImpl implements ISysRoleService {
     @Transactional(rollbackFor = Exception.class)
     public int insertRole(SysRoleBo bo) {
         SysRole role = MapstructUtils.convert(bo, SysRole.class);
+
+        // 角色在商户端使用随机字符串的形式进行,需要保证同以租户下的唯一
+        LockInfo lock = locker.lock(LockContants.ROLE + TenantHelper.getTenantId(), 5000L, 5000L);
+        List<String> keys = baseMapper.selectList(Wrappers.lambdaQuery(SysRole.class).select(SysRole::getRoleKey)).stream().map(SysRole::getRoleKey).toList();
+        String key = StringUtils.generateStr(keys, null, 100);
+        role.setRoleKey(key);
+
         // 绑定平台 @author: Huanyi
         role.setPlatformId(PlatformUtils.getId());
         // 新增角色信息
         baseMapper.insert(role);
+
+        locker.releaseLock(lock);
+
         bo.setRoleId(role.getRoleId());
         return insertRoleMenu(bo);
     }

+ 27 - 7
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysStoreServiceImpl.java

@@ -15,7 +15,9 @@ import org.dromara.common.mybatis.utils.WrapperUtils;
 import org.dromara.common.satoken.utils.LoginHelper;
 import org.dromara.service.api.RemoteStoreServiceService;
 import org.dromara.service.api.domain.bo.RemoteStoreServiceBo;
+import org.dromara.system.constants.StoreConstants;
 import org.dromara.system.domain.SysAreaStation;
+import org.dromara.system.domain.SysUserStore;
 import org.dromara.system.domain.bo.SysStorePageBo;
 import org.dromara.system.domain.vo.SysStoreListOnMerchantAccountInfoVo;
 import org.dromara.system.domain.vo.SysStoreListOnMerchantStoreInfoVo;
@@ -23,6 +25,7 @@ import org.dromara.system.domain.vo.SysStoreStatusVo;
 import org.dromara.system.enums.AreaStationStatusEnum;
 import org.dromara.system.enums.SysStoreStatusEnum;
 import org.dromara.system.mapper.SysAreaStationMapper;
+import org.dromara.system.mapper.SysUserStoreMapper;
 import org.springframework.stereotype.Service;
 import org.dromara.system.domain.bo.SysStoreBo;
 import org.dromara.system.domain.vo.SysStoreVo;
@@ -45,6 +48,7 @@ public class SysStoreServiceImpl implements ISysStoreService {
 
     private final SysStoreMapper baseMapper;
     private final SysAreaStationMapper areaStationMapper;
+    private final SysUserStoreMapper userStoreMapper;
 
     @DubboReference
     private final RemoteStoreServiceService storeServiceService;
@@ -220,15 +224,23 @@ public class SysStoreServiceImpl implements ISysStoreService {
 
         List<SysStoreListOnMerchantStoreInfoVo> list = new ArrayList<>();
 
-        if (LoginHelper.isTenantAdmin()) {
-            baseMapper.selectList().forEach(e -> {
-                SysStoreListOnMerchantStoreInfoVo vo = new SysStoreListOnMerchantStoreInfoVo();
-                vo.setId(e.getId());
-                vo.setName(e.getName());
-                list.add(vo);
-            });
+        List<Long> ids = userStoreMapper.selectList(
+            Wrappers.lambdaQuery(SysUserStore.class).select(SysUserStore::getStoreId).eq(SysUserStore::getUserId, LoginHelper.getUserId())
+        ).stream().map(SysUserStore::getStoreId).toList();
+
+        LambdaQueryWrapper<SysStore> wrapper = Wrappers.lambdaQuery(SysStore.class).select(SysStore::getId, SysStore::getName);
+
+        if (!Objects.equals(ids.get(0), StoreConstants.ALL_STORE)) {
+            wrapper.in(SysStore::getId, WrapperUtils.convertIds(ids));
         }
 
+        baseMapper.selectList(wrapper).forEach(e -> {
+            SysStoreListOnMerchantStoreInfoVo vo = new SysStoreListOnMerchantStoreInfoVo();
+            vo.setId(e.getId());
+            vo.setName(e.getName());
+            list.add(vo);
+        });
+
         return list;
     }
 
@@ -242,4 +254,12 @@ public class SysStoreServiceImpl implements ISysStoreService {
                 return vo;
             }).toList();
     }
+
+    @Override
+    public List<Long> selectStoreIds(Long userId) {
+        return userStoreMapper.selectList(
+            Wrappers.lambdaQuery(SysUserStore.class).select(SysUserStore::getStoreId)
+                .eq(userId != null, SysUserStore::getUserId, userId)
+        ).stream().map(SysUserStore::getStoreId).toList();
+    }
 }

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

@@ -27,6 +27,7 @@ import org.dromara.common.platform.Platform;
 import org.dromara.common.redis.utils.CacheUtils;
 import org.dromara.common.tenant.core.TenantEntity;
 import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.system.constants.StoreConstants;
 import org.dromara.system.domain.*;
 import org.dromara.system.domain.bo.SysTenantBo;
 import org.dromara.system.domain.vo.SysTenantOnStoreVo;
@@ -62,6 +63,7 @@ public class SysTenantServiceImpl implements ISysTenantService {
     private final SysDictDataMapper dictDataMapper;
     private final SysConfigMapper configMapper;
     private final SysMenuMapper menuMapper;
+    private final SysUserStoreMapper userStoreMapper;
 
     @DubboReference(mock = "true")
     private RemoteWorkflowService remoteWorkflowService;
@@ -176,7 +178,14 @@ public class SysTenantServiceImpl implements ISysTenantService {
         user.setDeptId(deptId);
         user.setPlatformId(Platform.MERCHANT.getId());
         userMapper.insert(user);
-        //新增系统用户后,默认当前用户为部门的负责人
+
+        // 创建用户与门店关联 @author: Huanyi
+        SysUserStore userStore = new SysUserStore();
+        userStore.setUserId(userId);
+        userStore.setStoreId(StoreConstants.ALL_STORE);
+        userStoreMapper.insert(userStore);
+
+        // 新增系统用户后,默认当前用户为部门的负责人
         SysDept sd = new SysDept();
         sd.setLeader(user.getUserId());
         sd.setDeptId(deptId);

+ 2 - 1
ruoyi-visual/ruoyi-nacos/src/main/resources/application.properties

@@ -28,7 +28,8 @@ server.port=8848
 # nacos.inetutils.prefer-hostname-over-ip=false
 
 ### Specify local server's IP:
-nacos.inetutils.ip-address=192.168.1.140
+nacos.inetutils.ip-address=192.168.1.118
+# nacos.inetutils.ip-address=192.168.1.140
 
 spring.application.name=ruoyi-nacos
 #*************** Config Module Related Configurations ***************#