ludc
2024-03-18 7cf54012c46c54bd701310cc29caaa94676ea570
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
package com.vci.ubcs.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.service.impl.ServiceImpl;
import com.vci.ubcs.code.feign.ICodeClassifyClient;
import com.vci.ubcs.starter.web.util.VciBaseUtil;
import com.vci.ubcs.system.dto.ClassifyAuthDTO;
import com.vci.ubcs.system.entity.ClassifyAuth;
import com.vci.ubcs.system.entity.Menu;
import com.vci.ubcs.system.mapper.ClassifyAuthMapper;
import com.vci.ubcs.system.service.IClassifyAuthService;
import com.vci.ubcs.system.service.IMenuService;
import com.vci.ubcs.system.service.IRoleService;
import com.vci.ubcs.system.vo.ClassifyAuthVO;
import com.vci.ubcs.system.wrapper.ClassifyAuthWrapper;
import lombok.AllArgsConstructor;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
import java.util.*;
import java.util.stream.Collectors;
 
/**
 * 分类授权,数据授权
 * @author ludc
 * @date 2023/12/25 15:35
 */
@Service
@AllArgsConstructor
public class ClassifyAuthServiceImpl extends ServiceImpl<ClassifyAuthMapper,ClassifyAuth> implements IClassifyAuthService {
 
    private final ClassifyAuthMapper classifyAuthMapper;
 
    private final IMenuService menuService;
 
    private final ICodeClassifyClient codeClassifyClient;
 
    private final IRoleService roleService;
 
    /**
     * 三员管理角色编号配置:分别为系统管理员,安全管理员,审计管理员顺序
     */
    @Value("#{'${ssa.ssa-names}'.split(',')}")
    private List<String> SSANAMES;
 
    /**
     * 分类授权保存接口
     * @param classifyAuthListDTO
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R submit(ClassifyAuthDTO classifyAuthListDTO) throws ServiceException{
        // 是清空授权列表
        if(classifyAuthListDTO.getIsCLear()){
            if(Func.isEmpty(classifyAuthListDTO.getClassifyId())){
                return R.fail("清空授权列表时,未获取到分类id");
            }
            this.classifyAuthMapper.delete(
                Wrappers.<ClassifyAuth>update()
                .lambda().eq(ClassifyAuth::getClassifyId, classifyAuthListDTO.getClassifyId())
                .eq(ClassifyAuth::getAuthType,classifyAuthListDTO.getAuthType())
            );
            return R.success("授权列表清空成功");
        }
 
        if(!classifyAuthListDTO.getIsCLear() && classifyAuthListDTO.getClassifyAuthList().isEmpty()){
            R.fail("授权列表不能为空!");
        }
        // 判重,查看是否存在同一个classid下配置了相同的角色
        Map<String, Long> roleidCounts = classifyAuthListDTO.getClassifyAuthList().stream()
            .collect(Collectors.groupingBy(ClassifyAuth::getRoleId, Collectors.counting()));
 
        // 检查是否有roleid出现次数大于1的情况
        boolean hasDuplicateRoleid = roleidCounts.values().stream()
            .anyMatch(count -> count > 1);
        if(hasDuplicateRoleid){
            R.fail("角色和分类已经存在,请重新配置!");
        }
 
        // 如果传过来的集合中该分类id下删除了部分角色的授权,就需要将该库中classifyId下不存在的数据删掉
        List<String> roleIds = classifyAuthListDTO.getClassifyAuthList().stream().map(ClassifyAuth::getRoleId).collect(Collectors.toList());
        // 删除
        LambdaUpdateWrapper<ClassifyAuth> updateWrapper = Wrappers.<ClassifyAuth>update()
            .lambda().eq(ClassifyAuth::getClassifyId, classifyAuthListDTO.getClassifyAuthList().get(0).getClassifyId())
            .eq(ClassifyAuth::getAuthType,classifyAuthListDTO.getAuthType())
            .notIn(ClassifyAuth::getRoleId, roleIds);
        try {
            this.classifyAuthMapper.delete(updateWrapper);
        }catch (Exception e){
            throw new ServiceException("分类授权过程中出现错误,错误原因:"+e.getMessage());
        }
        return R.status(saveOrUpdateBatch(classifyAuthListDTO.getClassifyAuthList()));
    }
 
    /**
     * 获取分类授权集合
     * @param classifyAuthVO
     * @return
     */
    @Override
    public List<ClassifyAuthVO> getClassifyAuthList(ClassifyAuthVO classifyAuthVO) {
        if(Func.isBlank(classifyAuthVO.getClassifyId())){
            throw new ServiceException("缺少必传参数分类id");
        }
        LambdaQueryWrapper<ClassifyAuth> wrapper = Wrappers.<ClassifyAuth>query()
            .lambda().eq(ClassifyAuth::getClassifyId,classifyAuthVO.getClassifyId())
            .eq(ClassifyAuth::getAuthType,classifyAuthVO.getAuthType());
        List<ClassifyAuth> classifyAuths = this.classifyAuthMapper.selectList(wrapper);
        if(classifyAuths.isEmpty()){
            return new ArrayList<ClassifyAuthVO>();
        }
        return ClassifyAuthWrapper.build().listVO(classifyAuths);
    }
 
    /**
     * 查询该分类下,当前登录的角色有哪些按钮权限
     * @param classifyId
     * @param menuCode
     * @param authType
     * @return
     */
    public Map<String,Boolean> getAuthButtonList(String classifyId,String menuCode,String authType){
        List<Menu> menuList = this.getButtonList(classifyId, menuCode, authType);
        if(menuList.isEmpty()){
            return new HashMap<>();
        }
        Map<String, Boolean> buttonMaps = menuList.stream()
            .collect(Collectors.toMap(Menu::getCode, menu -> true));
        return buttonMaps;
    }
 
    /**
     * 查询该主数据下,当前登录的角色有哪些按钮菜单权限
     * @param classifyId
     * @param menuCode
     * @param authType
     * @return
     */
    public List<Menu> getAuthMenuButtonList(String classifyId,String menuCode,String authType){
        List<Menu> buttonList = getButtonList(classifyId, menuCode, authType);
        return buttonList;
    }
 
    private List<Menu> getButtonList(String classifyId,String menuCode,String authType){
        if(Func.isBlank(classifyId)){
            throw new ServiceException("必传参数分类oid不能为空!");
        }
        //查询分类节点的所有父级节点
        R<List<String>> listR = codeClassifyClient.selectAllParentOid(classifyId);
        if (!listR.isSuccess() && !listR.getData().isEmpty()) {
            throw new ServiceException("获取分类信息失败!");
        }
        // 返回的分类oid是当前节点为第一个,后面依次是他的上层节点
        List<String> classifyOidList = listR.getData();
        final List<String> roleIds = Func.toStrList(",",AuthUtil.getUser().getRoleId());
        // 先查询按钮id列表
        LambdaQueryWrapper<ClassifyAuth> wrapper = Wrappers.<ClassifyAuth>query()
            .lambda().eq(ClassifyAuth::getClassifyId, classifyId)
            .eq(ClassifyAuth::getAuthType,authType)
            .in(ClassifyAuth::getRoleId, roleIds);
        List<ClassifyAuth> classifyAuths = this.classifyAuthMapper.selectList(wrapper);
        //如果当前分类没有找到授权配置,就依次从当前节点往上层节点找授权配置,找到了就停止,没找到就一直找到最后
        if(classifyAuths.isEmpty()){
            // 下标从1开始因为当前节点0已经查询过
            for (int i = 1; i < classifyOidList.size(); i++) {
                classifyAuths = this.classifyAuthMapper.selectList(
                    Wrappers.<ClassifyAuth>query()
                        .lambda().eq(ClassifyAuth::getClassifyId, classifyOidList.get(i))
                        .eq(ClassifyAuth::getAuthType,authType)
                        .in(ClassifyAuth::getRoleId, roleIds)
                );
                //只要当前节点的上层节点中找到了分类授权信息就不再继续往上找了
                if(!classifyAuths.isEmpty()){
                    break;
                }
            }
        }
        //出现了多条数据
        if(classifyAuths.size()>1){
            // 校验是否存在错误数据,同一个角色和同一个分类id存在多条授权记录
            List<ClassifyAuth> finalClassifyAuths = classifyAuths;
            boolean hasDuplicate = classifyAuths.stream()
                .anyMatch(auth1 -> finalClassifyAuths.stream()
                    .filter(auth2 -> auth1 != auth2)
                    .anyMatch(auth2 -> auth1.getRoleId().equals(auth2.getRoleId()) && auth1.getClassifyId().equals(auth2.getClassifyId())));
            if (hasDuplicate) {
                throw new ServiceException("角色和分类配置存在多条记录,请联系管理人员清理错误配置!");
            }
        }
        // 是否为超管
        Boolean isAdmin = VciBaseUtil.checkAdminTenant();
        // 未配置按钮权限
        if(!isAdmin && (classifyAuths.isEmpty() || Func.isBlank(classifyAuths.get(0).getButtonIds()))){
            return new ArrayList<>();
        }
        List<String> ids = new ArrayList<>();
        // 如果不是超管用户
        if(!isAdmin){
            String concatenatedButtonIds = classifyAuths.stream()
                .map(ClassifyAuth::getButtonIds) // 获取每个classifyAuths对象的buttonIds
                .collect(Collectors.joining(",")); // 用逗号分隔拼接成一个字符串
            ids.addAll(Arrays.asList(concatenatedButtonIds.split(",")));
        }
        return menuService.getMenuListByCode(ids,menuCode,roleIds);
    }
 
    /**
     * 根据角色id查看有哪些分类具备查看权限
     * @param roleIds
     * @return
     */
    @Override
    public List<String> getViewClassByRoleIds(List<String> roleIds,String authType,String buttonCode,String menuCode) {
        if(roleIds.isEmpty()){
            return new ArrayList<>();
        }
        return this.classifyAuthMapper.getViewClassByRoleIds(roleIds, authType,buttonCode,menuCode);
    }
 
    /**
     * 根据角色名称分类id授予默认的分类权限和主数据访问权限
     * @param classifyAuthDTO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public R saveAddClassifyDefaultAuth(ClassifyAuthDTO classifyAuthDTO) throws ServiceException{
        if (Func.isEmpty(classifyAuthDTO.getClassifyId())) {
            return R.fail("未获取到分类id");
        }
        // 配置的系统管理员名称
        String sysAdmin = SSANAMES.get(0);
        List<ClassifyAuth> classifyAuths = new ArrayList<>();
        //先默认生成系统管理员的授权数据
        ClassifyAuth classifyAuth = new ClassifyAuth();
        classifyAuth.setClassifyId(classifyAuthDTO.getClassifyId());
        classifyAuth.setAuthType("classify_auth");
        String roleIds = roleService.getRoleIds(AuthUtil.getTenantId(), sysAdmin);
        if(Func.isBlank(roleIds)){
            return R.fail(AuthUtil.getTenantId()+"租户下未找到,名为"+sysAdmin+"系统管理员角色!");
        }
        classifyAuth.setRoleId(roleIds);
        List<Menu> classifyTreeMenus = menuService.getButtonsByRoleId(roleIds, "classifyTree");
        if(!classifyTreeMenus.isEmpty()){
            String menuIds = classifyTreeMenus.stream()
                .map(menu -> String.valueOf(menu.getId()))
                .collect(Collectors.joining(","));
            classifyAuth.setButtonIds(menuIds);
            classifyAuths.add(classifyAuth);
        }
        /*ClassifyAuth dataAuth = new ClassifyAuth();
        dataAuth.setAuthType("data_auth");
        dataAuth.setClassifyId(classifyAuthDTO.getClassifyId());
        dataAuth.setRoleId(roleIds);
        List<Menu> masterDatas = menuService.getButtonsByRoleId(roleIds, classifyAuthDTO.getClassId());
        if(!masterDatas.isEmpty()){
            String menuIds = masterDatas.stream()
                .map(menu -> String.valueOf(menu.getId()))
                .collect(Collectors.joining(","));
            dataAuth.setButtonIds(menuIds);
            classifyAuths.add(dataAuth);
        }*/
        return R.status(this.saveBatch(classifyAuths));
    }
 
}