feat: 增加分类权限控制
- 新增角色分类授权模型与超级管理员配置接口 - 接入助手、插件、工作流、知识库、素材的分类可见性过滤 - 增加角色页分类权限树与插件多分类可见性支持
This commit is contained in:
@@ -1,11 +1,20 @@
|
|||||||
package tech.easyflow.admin.controller.ai;
|
package tech.easyflow.admin.controller.ai;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
import tech.easyflow.ai.entity.BotCategory;
|
import tech.easyflow.ai.entity.BotCategory;
|
||||||
import tech.easyflow.ai.service.BotCategoryService;
|
import tech.easyflow.ai.service.BotCategoryService;
|
||||||
import tech.easyflow.common.annotation.UsePermission;
|
import tech.easyflow.common.annotation.UsePermission;
|
||||||
|
import tech.easyflow.common.domain.Result;
|
||||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import tech.easyflow.system.entity.vo.RoleCategoryAccessSnapshot;
|
||||||
|
import tech.easyflow.system.service.CategoryPermissionService;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bot分类 控制层。
|
* bot分类 控制层。
|
||||||
@@ -17,7 +26,24 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
@RequestMapping("/api/v1/botCategory")
|
@RequestMapping("/api/v1/botCategory")
|
||||||
@UsePermission(moduleName = "/api/v1/bot")
|
@UsePermission(moduleName = "/api/v1/bot")
|
||||||
public class BotCategoryController extends BaseCurdController<BotCategoryService, BotCategory> {
|
public class BotCategoryController extends BaseCurdController<BotCategoryService, BotCategory> {
|
||||||
|
@Resource
|
||||||
|
private CategoryPermissionService categoryPermissionService;
|
||||||
|
|
||||||
public BotCategoryController(BotCategoryService service) {
|
public BotCategoryController(BotCategoryService service) {
|
||||||
super(service);
|
super(service);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@GetMapping("visibleList")
|
||||||
|
public Result<List<BotCategory>> visibleList(BotCategory entity, Boolean asTree, String sortKey, String sortType) {
|
||||||
|
QueryWrapper queryWrapper = QueryWrapper.create(entity, buildOperators(entity));
|
||||||
|
RoleCategoryAccessSnapshot access = categoryPermissionService.getCurrentAccess("BOT");
|
||||||
|
if (access.isRestricted()) {
|
||||||
|
if (access.getCategoryIds().isEmpty()) {
|
||||||
|
return Result.ok(Collections.emptyList());
|
||||||
|
}
|
||||||
|
queryWrapper.in(BotCategory::getId, access.getCategoryIds());
|
||||||
|
}
|
||||||
|
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||||
|
return Result.ok(service.list(queryWrapper));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ package tech.easyflow.admin.controller.ai;
|
|||||||
|
|
||||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
import cn.dev33.satoken.annotation.SaIgnore;
|
import cn.dev33.satoken.annotation.SaIgnore;
|
||||||
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
import com.easyagents.core.model.chat.ChatModel;
|
import com.easyagents.core.model.chat.ChatModel;
|
||||||
import com.easyagents.core.model.chat.ChatOptions;
|
import com.easyagents.core.model.chat.ChatOptions;
|
||||||
import com.alicp.jetcache.Cache;
|
import com.alicp.jetcache.Cache;
|
||||||
|
import com.mybatisflex.core.paginate.Page;
|
||||||
import com.mybatisflex.core.keygen.impl.SnowFlakeIDKeyGenerator;
|
import com.mybatisflex.core.keygen.impl.SnowFlakeIDKeyGenerator;
|
||||||
import com.mybatisflex.core.query.QueryWrapper;
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -25,6 +27,8 @@ import tech.easyflow.common.web.exceptions.BusinessException;
|
|||||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||||
import tech.easyflow.core.chat.protocol.sse.ChatSseEmitter;
|
import tech.easyflow.core.chat.protocol.sse.ChatSseEmitter;
|
||||||
import tech.easyflow.core.chat.protocol.sse.ChatSseUtil;
|
import tech.easyflow.core.chat.protocol.sse.ChatSseUtil;
|
||||||
|
import tech.easyflow.system.entity.vo.RoleCategoryAccessSnapshot;
|
||||||
|
import tech.easyflow.system.service.CategoryPermissionService;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
@@ -34,6 +38,8 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static tech.easyflow.ai.entity.table.BotTableDef.BOT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 控制层。
|
* 控制层。
|
||||||
*
|
*
|
||||||
@@ -55,6 +61,8 @@ public class BotController extends BaseCurdController<BotService, Bot> {
|
|||||||
private Cache<String, Object> cache;
|
private Cache<String, Object> cache;
|
||||||
@Resource
|
@Resource
|
||||||
private AudioServiceManager audioServiceManager;
|
private AudioServiceManager audioServiceManager;
|
||||||
|
@Resource
|
||||||
|
private CategoryPermissionService categoryPermissionService;
|
||||||
|
|
||||||
public BotController(BotService service, ModelService modelService, BotWorkflowService botWorkflowService,
|
public BotController(BotService service, ModelService modelService, BotWorkflowService botWorkflowService,
|
||||||
BotDocumentCollectionService botDocumentCollectionService, BotMessageService botMessageService) {
|
BotDocumentCollectionService botDocumentCollectionService, BotMessageService botMessageService) {
|
||||||
@@ -164,7 +172,11 @@ public class BotController extends BaseCurdController<BotService, Bot> {
|
|||||||
@GetMapping("getDetail")
|
@GetMapping("getDetail")
|
||||||
@SaIgnore
|
@SaIgnore
|
||||||
public Result<Bot> getDetail(String id) {
|
public Result<Bot> getDetail(String id) {
|
||||||
return Result.ok(botService.getDetail(id));
|
Bot bot = botService.getDetail(id);
|
||||||
|
if (bot != null && StpUtil.isLogin()) {
|
||||||
|
categoryPermissionService.assertCategoryResourceVisible("BOT", bot.getCreatedBy(), bot.getCategoryId(), "无权限访问聊天助手");
|
||||||
|
}
|
||||||
|
return Result.ok(bot);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -174,6 +186,9 @@ public class BotController extends BaseCurdController<BotService, Bot> {
|
|||||||
if (data == null) {
|
if (data == null) {
|
||||||
return Result.ok(data);
|
return Result.ok(data);
|
||||||
}
|
}
|
||||||
|
if (StpUtil.isLogin()) {
|
||||||
|
categoryPermissionService.assertCategoryResourceVisible("BOT", data.getCreatedBy(), data.getCategoryId(), "无权限访问聊天助手");
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, Object> llmOptions = data.getModelOptions();
|
Map<String, Object> llmOptions = data.getModelOptions();
|
||||||
if (llmOptions == null) {
|
if (llmOptions == null) {
|
||||||
@@ -205,6 +220,32 @@ public class BotController extends BaseCurdController<BotService, Bot> {
|
|||||||
return Result.ok(data);
|
return Result.ok(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<List<Bot>> list(Bot entity, Boolean asTree, String sortKey, String sortType) {
|
||||||
|
QueryWrapper queryWrapper = QueryWrapper.create(entity, buildOperators(entity));
|
||||||
|
applyCategoryPermission(queryWrapper);
|
||||||
|
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||||
|
return Result.ok(service.list(queryWrapper));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Page<Bot> queryPage(Page<Bot> page, QueryWrapper queryWrapper) {
|
||||||
|
applyCategoryPermission(queryWrapper);
|
||||||
|
return super.queryPage(page, queryWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyCategoryPermission(QueryWrapper queryWrapper) {
|
||||||
|
RoleCategoryAccessSnapshot access = categoryPermissionService.getCurrentAccess("BOT");
|
||||||
|
if (!access.isRestricted()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (access.getCategoryIds().isEmpty()) {
|
||||||
|
queryWrapper.eq(Bot::getCreatedBy, access.getAccountId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
queryWrapper.and(BOT.CREATED_BY.eq(access.getAccountId()).or(BOT.CATEGORY_ID.in(access.getCategoryIds())));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Result<?> onSaveOrUpdateBefore(Bot entity, boolean isSave) {
|
protected Result<?> onSaveOrUpdateBefore(Bot entity, boolean isSave) {
|
||||||
|
|
||||||
|
|||||||
@@ -3,19 +3,25 @@ package tech.easyflow.admin.controller.ai;
|
|||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import tech.easyflow.ai.entity.Plugin;
|
import tech.easyflow.ai.entity.Plugin;
|
||||||
import tech.easyflow.ai.entity.BotPlugin;
|
import tech.easyflow.ai.entity.BotPlugin;
|
||||||
|
import tech.easyflow.ai.entity.PluginItem;
|
||||||
import tech.easyflow.common.annotation.UsePermission;
|
import tech.easyflow.common.annotation.UsePermission;
|
||||||
import tech.easyflow.common.domain.Result;
|
import tech.easyflow.common.domain.Result;
|
||||||
import tech.easyflow.common.tree.Tree;
|
import tech.easyflow.common.tree.Tree;
|
||||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||||
import tech.easyflow.ai.service.BotPluginService;
|
import tech.easyflow.ai.service.BotPluginService;
|
||||||
|
import tech.easyflow.ai.service.PluginService;
|
||||||
|
import tech.easyflow.ai.service.PluginItemService;
|
||||||
|
import tech.easyflow.ai.service.PluginVisibilityService;
|
||||||
import com.mybatisflex.core.query.QueryWrapper;
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||||
|
import tech.easyflow.system.service.CategoryPermissionService;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,6 +41,12 @@ public class BotPluginController extends BaseCurdController<BotPluginService, Bo
|
|||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private BotPluginService botPluginService;
|
private BotPluginService botPluginService;
|
||||||
|
@Resource
|
||||||
|
private PluginItemService pluginItemService;
|
||||||
|
@Resource
|
||||||
|
private PluginService pluginService;
|
||||||
|
@Resource
|
||||||
|
private PluginVisibilityService pluginVisibilityService;
|
||||||
|
|
||||||
@GetMapping("list")
|
@GetMapping("list")
|
||||||
public Result<List<BotPlugin>> list(BotPlugin entity, Boolean asTree, String sortKey, String sortType){
|
public Result<List<BotPlugin>> list(BotPlugin entity, Boolean asTree, String sortKey, String sortType){
|
||||||
@@ -43,15 +55,29 @@ public class BotPluginController extends BaseCurdController<BotPluginService, Bo
|
|||||||
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||||
|
|
||||||
List<BotPlugin> botPlugins = service.getMapper().selectListWithRelationsByQuery(queryWrapper);
|
List<BotPlugin> botPlugins = service.getMapper().selectListWithRelationsByQuery(queryWrapper);
|
||||||
|
List<BotPlugin> visibleList = new ArrayList<>();
|
||||||
|
for (BotPlugin relation : botPlugins) {
|
||||||
|
Plugin plugin = relation.getAiPlugin();
|
||||||
|
if (plugin == null || pluginVisibilityService.canAccessPlugin(plugin.getCreatedBy(), plugin.getId())) {
|
||||||
|
visibleList.add(relation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
List<BotPlugin> list = Tree.tryToTree(botPlugins, asTree);
|
List<BotPlugin> list = Tree.tryToTree(visibleList, asTree);
|
||||||
|
|
||||||
return Result.ok(list);
|
return Result.ok(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/getList")
|
@PostMapping("/getList")
|
||||||
public Result<List<Plugin>> getList(@JsonBody(value = "botId", required = true) String botId){
|
public Result<List<Plugin>> getList(@JsonBody(value = "botId", required = true) String botId){
|
||||||
return Result.ok(botPluginService.getList(botId));
|
List<Plugin> plugins = botPluginService.getList(botId);
|
||||||
|
List<Plugin> visibleList = new ArrayList<>();
|
||||||
|
for (Plugin plugin : plugins) {
|
||||||
|
if (plugin == null || pluginVisibilityService.canAccessPlugin(plugin.getCreatedBy(), plugin.getId())) {
|
||||||
|
visibleList.add(plugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Result.ok(visibleList);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/getBotPluginToolIds")
|
@PostMapping("/getBotPluginToolIds")
|
||||||
@@ -67,6 +93,23 @@ public class BotPluginController extends BaseCurdController<BotPluginService, Bo
|
|||||||
|
|
||||||
@PostMapping("updateBotPluginToolIds")
|
@PostMapping("updateBotPluginToolIds")
|
||||||
public Result<?> save(@JsonBody("botId") BigInteger botId, @JsonBody("pluginToolIds") BigInteger [] pluginToolIds) {
|
public Result<?> save(@JsonBody("botId") BigInteger botId, @JsonBody("pluginToolIds") BigInteger [] pluginToolIds) {
|
||||||
|
if (pluginToolIds != null) {
|
||||||
|
for (BigInteger pluginToolId : pluginToolIds) {
|
||||||
|
if (pluginToolId == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
PluginItem pluginItem = pluginItemService.getById(pluginToolId);
|
||||||
|
if (pluginItem == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (pluginItem.getPluginId() != null) {
|
||||||
|
Plugin plugin = pluginService.getById(pluginItem.getPluginId());
|
||||||
|
if (plugin != null) {
|
||||||
|
pluginVisibilityService.assertPluginVisible(plugin.getCreatedBy(), plugin.getId(), "无权限绑定插件");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
service.saveBotAndPluginTool(botId, pluginToolIds);
|
service.saveBotAndPluginTool(botId, pluginToolIds);
|
||||||
return Result.ok();
|
return Result.ok();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,17 +3,17 @@ package tech.easyflow.admin.controller.ai;
|
|||||||
import com.mybatisflex.core.query.QueryWrapper;
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import tech.easyflow.ai.entity.DocumentCollection;
|
import tech.easyflow.ai.entity.DocumentCollection;
|
||||||
import tech.easyflow.ai.entity.DocumentCollectionCategory;
|
import tech.easyflow.ai.entity.DocumentCollectionCategory;
|
||||||
import tech.easyflow.ai.entity.WorkflowCategory;
|
|
||||||
import tech.easyflow.ai.mapper.DocumentCollectionMapper;
|
import tech.easyflow.ai.mapper.DocumentCollectionMapper;
|
||||||
import tech.easyflow.ai.service.DocumentCollectionCategoryService;
|
import tech.easyflow.ai.service.DocumentCollectionCategoryService;
|
||||||
import tech.easyflow.ai.service.DocumentCollectionService;
|
|
||||||
import tech.easyflow.ai.service.WorkflowCategoryService;
|
|
||||||
import tech.easyflow.common.annotation.UsePermission;
|
import tech.easyflow.common.annotation.UsePermission;
|
||||||
import tech.easyflow.common.domain.Result;
|
import tech.easyflow.common.domain.Result;
|
||||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||||
|
import tech.easyflow.system.entity.vo.RoleCategoryAccessSnapshot;
|
||||||
|
import tech.easyflow.system.service.CategoryPermissionService;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
@@ -34,6 +34,8 @@ public class DocumentCollectionCategoryController extends BaseCurdController<Doc
|
|||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private DocumentCollectionMapper documentCollectionMapper;
|
private DocumentCollectionMapper documentCollectionMapper;
|
||||||
|
@Resource
|
||||||
|
private CategoryPermissionService categoryPermissionService;
|
||||||
|
|
||||||
public DocumentCollectionCategoryController(DocumentCollectionCategoryService service) {
|
public DocumentCollectionCategoryController(DocumentCollectionCategoryService service) {
|
||||||
super(service);
|
super(service);
|
||||||
@@ -51,4 +53,18 @@ public class DocumentCollectionCategoryController extends BaseCurdController<Doc
|
|||||||
|
|
||||||
return super.onRemoveBefore(ids);
|
return super.onRemoveBefore(ids);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@GetMapping("visibleList")
|
||||||
|
public Result<List<DocumentCollectionCategory>> visibleList(DocumentCollectionCategory entity, Boolean asTree, String sortKey, String sortType) {
|
||||||
|
QueryWrapper queryWrapper = QueryWrapper.create(entity, buildOperators(entity));
|
||||||
|
RoleCategoryAccessSnapshot access = categoryPermissionService.getCurrentAccess("KNOWLEDGE");
|
||||||
|
if (access.isRestricted()) {
|
||||||
|
if (access.getCategoryIds().isEmpty()) {
|
||||||
|
return Result.ok(Collections.emptyList());
|
||||||
|
}
|
||||||
|
queryWrapper.in(DocumentCollectionCategory::getId, access.getCategoryIds());
|
||||||
|
}
|
||||||
|
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||||
|
return Result.ok(service.list(queryWrapper));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package tech.easyflow.admin.controller.ai;
|
package tech.easyflow.admin.controller.ai;
|
||||||
|
|
||||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
@@ -10,9 +11,13 @@ import tech.easyflow.ai.service.PluginCategoryService;
|
|||||||
import tech.easyflow.common.annotation.UsePermission;
|
import tech.easyflow.common.annotation.UsePermission;
|
||||||
import tech.easyflow.common.domain.Result;
|
import tech.easyflow.common.domain.Result;
|
||||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||||
|
import tech.easyflow.system.entity.vo.RoleCategoryAccessSnapshot;
|
||||||
|
import tech.easyflow.system.service.CategoryPermissionService;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 控制层。
|
* 控制层。
|
||||||
@@ -30,6 +35,8 @@ public class PluginCategoryController extends BaseCurdController<PluginCategoryS
|
|||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PluginCategoryService pluginCategoryService;
|
private PluginCategoryService pluginCategoryService;
|
||||||
|
@Resource
|
||||||
|
private CategoryPermissionService categoryPermissionService;
|
||||||
|
|
||||||
@GetMapping("/doRemoveCategory")
|
@GetMapping("/doRemoveCategory")
|
||||||
@SaCheckPermission("/api/v1/plugin/remove")
|
@SaCheckPermission("/api/v1/plugin/remove")
|
||||||
@@ -37,4 +44,18 @@ public class PluginCategoryController extends BaseCurdController<PluginCategoryS
|
|||||||
|
|
||||||
return Result.ok(pluginCategoryService.doRemoveCategory(id));
|
return Result.ok(pluginCategoryService.doRemoveCategory(id));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@GetMapping("/visibleList")
|
||||||
|
public Result<List<PluginCategory>> visibleList(PluginCategory entity, Boolean asTree, String sortKey, String sortType) {
|
||||||
|
QueryWrapper queryWrapper = QueryWrapper.create(entity, buildOperators(entity));
|
||||||
|
RoleCategoryAccessSnapshot access = categoryPermissionService.getCurrentAccess("PLUGIN");
|
||||||
|
if (access.isRestricted()) {
|
||||||
|
if (access.getCategoryIds().isEmpty()) {
|
||||||
|
return Result.ok(Collections.emptyList());
|
||||||
|
}
|
||||||
|
queryWrapper.in(PluginCategory::getId, access.getCategoryIds());
|
||||||
|
}
|
||||||
|
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||||
|
return Result.ok(service.list(queryWrapper));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,16 +6,25 @@ import com.mybatisflex.core.query.QueryWrapper;
|
|||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import tech.easyflow.ai.entity.Model;
|
||||||
import tech.easyflow.ai.entity.Plugin;
|
import tech.easyflow.ai.entity.Plugin;
|
||||||
|
import tech.easyflow.ai.service.ModelService;
|
||||||
|
import tech.easyflow.ai.service.PluginVisibilityService;
|
||||||
import tech.easyflow.common.domain.Result;
|
import tech.easyflow.common.domain.Result;
|
||||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||||
import tech.easyflow.ai.service.PluginService;
|
import tech.easyflow.ai.service.PluginService;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||||
|
import tech.easyflow.system.entity.vo.RoleCategoryAccessSnapshot;
|
||||||
|
import tech.easyflow.system.service.CategoryPermissionService;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import java.math.BigInteger;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static tech.easyflow.ai.entity.table.PluginTableDef.PLUGIN;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 控制层。
|
* 控制层。
|
||||||
@@ -32,6 +41,12 @@ public class PluginController extends BaseCurdController<PluginService, Plugin>
|
|||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
PluginService pluginService;
|
PluginService pluginService;
|
||||||
|
@Resource
|
||||||
|
private CategoryPermissionService categoryPermissionService;
|
||||||
|
@Resource
|
||||||
|
private PluginVisibilityService pluginVisibilityService;
|
||||||
|
@Resource
|
||||||
|
private ModelService modelService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Result<?> onSaveOrUpdateBefore(Plugin entity, boolean isSave) {
|
protected Result<?> onSaveOrUpdateBefore(Plugin entity, boolean isSave) {
|
||||||
@@ -62,7 +77,9 @@ public class PluginController extends BaseCurdController<PluginService, Plugin>
|
|||||||
@PostMapping("/getList")
|
@PostMapping("/getList")
|
||||||
@SaCheckPermission("/api/v1/plugin/query")
|
@SaCheckPermission("/api/v1/plugin/query")
|
||||||
public Result<List<Plugin>> getList(){
|
public Result<List<Plugin>> getList(){
|
||||||
return Result.ok(pluginService.getList());
|
QueryWrapper queryWrapper = QueryWrapper.create().select();
|
||||||
|
applyCategoryPermission(queryWrapper);
|
||||||
|
return Result.ok(service.getMapper().selectListByQuery(queryWrapper));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/pageByCategory")
|
@GetMapping("/pageByCategory")
|
||||||
@@ -76,6 +93,7 @@ public class PluginController extends BaseCurdController<PluginService, Plugin>
|
|||||||
}
|
}
|
||||||
if (category == 0){
|
if (category == 0){
|
||||||
QueryWrapper queryWrapper = buildQueryWrapper(request);
|
QueryWrapper queryWrapper = buildQueryWrapper(request);
|
||||||
|
applyCategoryPermission(queryWrapper);
|
||||||
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||||
return Result.ok(queryPage(new Page<>(pageNumber, pageSize), queryWrapper));
|
return Result.ok(queryPage(new Page<>(pageNumber, pageSize), queryWrapper));
|
||||||
} else {
|
} else {
|
||||||
@@ -83,8 +101,41 @@ public class PluginController extends BaseCurdController<PluginService, Plugin>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/modelList")
|
||||||
|
@SaCheckPermission("/api/v1/plugin/query")
|
||||||
|
public Result<List<Model>> modelList(Model entity, Boolean asTree, String sortKey, String sortType) {
|
||||||
|
return Result.ok(modelService.listSelectableModels(entity, asTree, sortKey, sortType));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Page<Plugin> queryPage(Page<Plugin> page, QueryWrapper queryWrapper) {
|
protected Page<Plugin> queryPage(Page<Plugin> page, QueryWrapper queryWrapper) {
|
||||||
|
applyCategoryPermission(queryWrapper);
|
||||||
return service.getMapper().paginateWithRelations(page, queryWrapper);
|
return service.getMapper().paginateWithRelations(page, queryWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<Plugin> detail(String id) {
|
||||||
|
Plugin plugin = service.getById(id);
|
||||||
|
if (plugin != null) {
|
||||||
|
pluginVisibilityService.assertPluginVisible(plugin.getCreatedBy(), plugin.getId(), "无权限访问插件");
|
||||||
|
}
|
||||||
|
return Result.ok(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyCategoryPermission(QueryWrapper queryWrapper) {
|
||||||
|
RoleCategoryAccessSnapshot access = categoryPermissionService.getCurrentAccess("PLUGIN");
|
||||||
|
if (!access.isRestricted()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (access.getCategoryIds().isEmpty()) {
|
||||||
|
queryWrapper.eq(Plugin::getCreatedBy, access.getAccountIdAsLong());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Set<BigInteger> pluginIds = pluginVisibilityService.getCurrentVisiblePluginIds();
|
||||||
|
if (pluginIds.isEmpty()) {
|
||||||
|
queryWrapper.eq(Plugin::getCreatedBy, access.getAccountIdAsLong());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
queryWrapper.and(PLUGIN.CREATED_BY.eq(access.getAccountIdAsLong()).or(PLUGIN.ID.in(pluginIds)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,20 @@
|
|||||||
package tech.easyflow.admin.controller.ai;
|
package tech.easyflow.admin.controller.ai;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import tech.easyflow.ai.entity.ResourceCategory;
|
import tech.easyflow.ai.entity.ResourceCategory;
|
||||||
import tech.easyflow.ai.service.ResourceCategoryService;
|
import tech.easyflow.ai.service.ResourceCategoryService;
|
||||||
import tech.easyflow.common.annotation.UsePermission;
|
import tech.easyflow.common.annotation.UsePermission;
|
||||||
|
import tech.easyflow.common.domain.Result;
|
||||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||||
|
import tech.easyflow.system.entity.vo.RoleCategoryAccessSnapshot;
|
||||||
|
import tech.easyflow.system.service.CategoryPermissionService;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 素材分类
|
* 素材分类
|
||||||
@@ -14,9 +23,24 @@ import tech.easyflow.common.web.controller.BaseCurdController;
|
|||||||
@RequestMapping("/api/v1/resourceCategory")
|
@RequestMapping("/api/v1/resourceCategory")
|
||||||
@UsePermission(moduleName = "/api/v1/resource")
|
@UsePermission(moduleName = "/api/v1/resource")
|
||||||
public class ResourceCategoryController extends BaseCurdController<ResourceCategoryService, ResourceCategory> {
|
public class ResourceCategoryController extends BaseCurdController<ResourceCategoryService, ResourceCategory> {
|
||||||
|
@Resource
|
||||||
|
private CategoryPermissionService categoryPermissionService;
|
||||||
|
|
||||||
public ResourceCategoryController(ResourceCategoryService service) {
|
public ResourceCategoryController(ResourceCategoryService service) {
|
||||||
super(service);
|
super(service);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
@GetMapping("visibleList")
|
||||||
|
public Result<List<ResourceCategory>> visibleList(ResourceCategory entity, Boolean asTree, String sortKey, String sortType) {
|
||||||
|
QueryWrapper queryWrapper = QueryWrapper.create(entity, buildOperators(entity));
|
||||||
|
RoleCategoryAccessSnapshot access = categoryPermissionService.getCurrentAccess("RESOURCE");
|
||||||
|
if (access.isRestricted()) {
|
||||||
|
if (access.getCategoryIds().isEmpty()) {
|
||||||
|
return Result.ok(Collections.emptyList());
|
||||||
|
}
|
||||||
|
queryWrapper.in(ResourceCategory::getId, access.getCategoryIds());
|
||||||
|
}
|
||||||
|
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||||
|
return Result.ok(service.list(queryWrapper));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,10 +12,15 @@ import tech.easyflow.common.domain.Result;
|
|||||||
import tech.easyflow.common.entity.LoginAccount;
|
import tech.easyflow.common.entity.LoginAccount;
|
||||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||||
|
import tech.easyflow.system.entity.vo.RoleCategoryAccessSnapshot;
|
||||||
|
import tech.easyflow.system.service.CategoryPermissionService;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static tech.easyflow.ai.entity.table.ResourceTableDef.RESOURCE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 素材库
|
* 素材库
|
||||||
@@ -26,6 +31,9 @@ import java.util.Date;
|
|||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/resource")
|
@RequestMapping("/api/v1/resource")
|
||||||
public class ResourceController extends BaseCurdController<ResourceService, Resource> {
|
public class ResourceController extends BaseCurdController<ResourceService, Resource> {
|
||||||
|
@javax.annotation.Resource
|
||||||
|
private CategoryPermissionService categoryPermissionService;
|
||||||
|
|
||||||
public ResourceController(ResourceService service) {
|
public ResourceController(ResourceService service) {
|
||||||
super(service);
|
super(service);
|
||||||
}
|
}
|
||||||
@@ -50,7 +58,36 @@ public class ResourceController extends BaseCurdController<ResourceService, Reso
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Page<Resource> queryPage(Page<Resource> page, QueryWrapper queryWrapper) {
|
protected Page<Resource> queryPage(Page<Resource> page, QueryWrapper queryWrapper) {
|
||||||
queryWrapper.eq(Resource::getCreatedBy, SaTokenUtil.getLoginAccount().getId().toString());
|
applyCategoryPermission(queryWrapper);
|
||||||
return super.queryPage(page, queryWrapper);
|
return super.queryPage(page, queryWrapper);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
public Result<List<Resource>> list(Resource entity, Boolean asTree, String sortKey, String sortType) {
|
||||||
|
QueryWrapper queryWrapper = QueryWrapper.create(entity, buildOperators(entity));
|
||||||
|
applyCategoryPermission(queryWrapper);
|
||||||
|
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||||
|
return Result.ok(service.list(queryWrapper));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<Resource> detail(String id) {
|
||||||
|
Resource resource = service.getById(id);
|
||||||
|
if (resource != null) {
|
||||||
|
categoryPermissionService.assertCategoryResourceVisible("RESOURCE", resource.getCreatedBy(), resource.getCategoryId(), "无权限访问素材");
|
||||||
|
}
|
||||||
|
return Result.ok(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyCategoryPermission(QueryWrapper queryWrapper) {
|
||||||
|
RoleCategoryAccessSnapshot access = categoryPermissionService.getCurrentAccess("RESOURCE");
|
||||||
|
if (!access.isRestricted()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (access.getCategoryIds().isEmpty()) {
|
||||||
|
queryWrapper.eq(Resource::getCreatedBy, access.getAccountId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
queryWrapper.and(RESOURCE.CREATED_BY.eq(access.getAccountId()).or(RESOURCE.CATEGORY_ID.in(access.getCategoryIds())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,12 +1,21 @@
|
|||||||
package tech.easyflow.admin.controller.ai;
|
package tech.easyflow.admin.controller.ai;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
import tech.easyflow.ai.entity.WorkflowCategory;
|
import tech.easyflow.ai.entity.WorkflowCategory;
|
||||||
import tech.easyflow.ai.service.WorkflowCategoryService;
|
import tech.easyflow.ai.service.WorkflowCategoryService;
|
||||||
import tech.easyflow.common.annotation.UsePermission;
|
import tech.easyflow.common.annotation.UsePermission;
|
||||||
|
import tech.easyflow.common.domain.Result;
|
||||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||||
|
import tech.easyflow.system.entity.vo.RoleCategoryAccessSnapshot;
|
||||||
|
import tech.easyflow.system.service.CategoryPermissionService;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 控制层。
|
* 控制层。
|
||||||
*
|
*
|
||||||
@@ -17,9 +26,24 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
@RequestMapping("/api/v1/workflowCategory")
|
@RequestMapping("/api/v1/workflowCategory")
|
||||||
@UsePermission(moduleName = "/api/v1/workflow")
|
@UsePermission(moduleName = "/api/v1/workflow")
|
||||||
public class WorkflowCategoryController extends BaseCurdController<WorkflowCategoryService, WorkflowCategory> {
|
public class WorkflowCategoryController extends BaseCurdController<WorkflowCategoryService, WorkflowCategory> {
|
||||||
|
@Resource
|
||||||
|
private CategoryPermissionService categoryPermissionService;
|
||||||
|
|
||||||
public WorkflowCategoryController(WorkflowCategoryService service) {
|
public WorkflowCategoryController(WorkflowCategoryService service) {
|
||||||
super(service);
|
super(service);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
@GetMapping("visibleList")
|
||||||
|
public Result<List<WorkflowCategory>> visibleList(WorkflowCategory entity, Boolean asTree, String sortKey, String sortType) {
|
||||||
|
QueryWrapper queryWrapper = QueryWrapper.create(entity, buildOperators(entity));
|
||||||
|
RoleCategoryAccessSnapshot access = categoryPermissionService.getCurrentAccess("WORKFLOW");
|
||||||
|
if (access.isRestricted()) {
|
||||||
|
if (access.getCategoryIds().isEmpty()) {
|
||||||
|
return Result.ok(Collections.emptyList());
|
||||||
|
}
|
||||||
|
queryWrapper.in(WorkflowCategory::getId, access.getCategoryIds());
|
||||||
|
}
|
||||||
|
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||||
|
return Result.ok(service.list(queryWrapper));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package tech.easyflow.admin.controller.system;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import tech.easyflow.common.domain.Result;
|
||||||
|
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||||
|
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||||
|
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||||
|
import tech.easyflow.system.entity.vo.SysRoleCategoryScopeDetailVo;
|
||||||
|
import tech.easyflow.system.service.CategoryPermissionService;
|
||||||
|
import tech.easyflow.system.service.SysRoleCategoryScopeService;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/sysRoleCategoryScope")
|
||||||
|
public class SysRoleCategoryScopeController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SysRoleCategoryScopeService sysRoleCategoryScopeService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CategoryPermissionService categoryPermissionService;
|
||||||
|
|
||||||
|
@GetMapping("/detail")
|
||||||
|
@SaCheckPermission("/api/v1/sysRole/query")
|
||||||
|
public Result<SysRoleCategoryScopeDetailVo> detail(BigInteger roleId) {
|
||||||
|
SysRoleCategoryScopeDetailVo detail = sysRoleCategoryScopeService.getRoleScopeDetail(roleId);
|
||||||
|
detail.setEditable(categoryPermissionService.isCurrentSuperAdmin());
|
||||||
|
return Result.ok(detail);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/save")
|
||||||
|
@SaCheckPermission("/api/v1/sysRole/save")
|
||||||
|
public Result<Void> save(@JsonBody SysRoleCategoryScopeDetailVo request) {
|
||||||
|
assertSuperAdmin();
|
||||||
|
if (request == null || request.getRoleId() == null) {
|
||||||
|
throw new BusinessException("角色ID不能为空");
|
||||||
|
}
|
||||||
|
BigInteger operatorId = SaTokenUtil.getLoginAccount().getId();
|
||||||
|
sysRoleCategoryScopeService.saveRoleScopes(request.getRoleId(), request.getScopes(), operatorId);
|
||||||
|
return Result.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertSuperAdmin() {
|
||||||
|
if (!categoryPermissionService.isCurrentSuperAdmin()) {
|
||||||
|
throw new BusinessException("仅超级管理员可配置分类权限");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -80,13 +80,13 @@ public class SysRoleController extends BaseCurdController<SysRoleService, SysRol
|
|||||||
*/
|
*/
|
||||||
@PostMapping("saveRole")
|
@PostMapping("saveRole")
|
||||||
@SaCheckPermission("/api/v1/sysRole/save")
|
@SaCheckPermission("/api/v1/sysRole/save")
|
||||||
public Result<Void> saveRole(@JsonBody SysRole entity) {
|
public Result<BigInteger> saveRole(@JsonBody SysRole entity) {
|
||||||
LoginAccount loginUser = SaTokenUtil.getLoginAccount();
|
LoginAccount loginUser = SaTokenUtil.getLoginAccount();
|
||||||
if (entity.getId() == null) {
|
if (entity.getId() == null) {
|
||||||
commonFiled(entity, loginUser.getId(), loginUser.getTenantId(), loginUser.getDeptId());
|
commonFiled(entity, loginUser.getId(), loginUser.getTenantId(), loginUser.getDeptId());
|
||||||
}
|
}
|
||||||
service.saveRole(entity);
|
service.saveRole(entity);
|
||||||
return Result.ok();
|
return Result.ok(entity.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -115,4 +115,4 @@ public class SysRoleController extends BaseCurdController<SysRoleService, SysRol
|
|||||||
}
|
}
|
||||||
return super.onRemoveBefore(ids);
|
return super.onRemoveBefore(ids);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,20 @@
|
|||||||
package tech.easyflow.usercenter.controller.ai;
|
package tech.easyflow.usercenter.controller.ai;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import tech.easyflow.ai.entity.BotCategory;
|
import tech.easyflow.ai.entity.BotCategory;
|
||||||
import tech.easyflow.ai.service.BotCategoryService;
|
import tech.easyflow.ai.service.BotCategoryService;
|
||||||
import tech.easyflow.common.annotation.UsePermission;
|
import tech.easyflow.common.annotation.UsePermission;
|
||||||
|
import tech.easyflow.common.domain.Result;
|
||||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||||
|
import tech.easyflow.system.entity.vo.RoleCategoryAccessSnapshot;
|
||||||
|
import tech.easyflow.system.service.CategoryPermissionService;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bot分类 控制层。
|
* bot分类 控制层。
|
||||||
@@ -17,7 +26,24 @@ import tech.easyflow.common.web.controller.BaseCurdController;
|
|||||||
@RequestMapping("/userCenter/botCategory")
|
@RequestMapping("/userCenter/botCategory")
|
||||||
@UsePermission(moduleName = "/api/v1/bot")
|
@UsePermission(moduleName = "/api/v1/bot")
|
||||||
public class UcBotCategoryController extends BaseCurdController<BotCategoryService, BotCategory> {
|
public class UcBotCategoryController extends BaseCurdController<BotCategoryService, BotCategory> {
|
||||||
|
@Resource
|
||||||
|
private CategoryPermissionService categoryPermissionService;
|
||||||
|
|
||||||
public UcBotCategoryController(BotCategoryService service) {
|
public UcBotCategoryController(BotCategoryService service) {
|
||||||
super(service);
|
super(service);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@GetMapping("visibleList")
|
||||||
|
public Result<List<BotCategory>> visibleList(BotCategory entity, Boolean asTree, String sortKey, String sortType) {
|
||||||
|
QueryWrapper queryWrapper = QueryWrapper.create(entity, buildOperators(entity));
|
||||||
|
RoleCategoryAccessSnapshot access = categoryPermissionService.getCurrentAccess("BOT");
|
||||||
|
if (access.isRestricted()) {
|
||||||
|
if (access.getCategoryIds().isEmpty()) {
|
||||||
|
return Result.ok(Collections.emptyList());
|
||||||
|
}
|
||||||
|
queryWrapper.in(BotCategory::getId, access.getCategoryIds());
|
||||||
|
}
|
||||||
|
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||||
|
return Result.ok(service.list(queryWrapper));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ package tech.easyflow.usercenter.controller.ai;
|
|||||||
|
|
||||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
import cn.dev33.satoken.annotation.SaIgnore;
|
import cn.dev33.satoken.annotation.SaIgnore;
|
||||||
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
import com.alicp.jetcache.Cache;
|
import com.alicp.jetcache.Cache;
|
||||||
|
import com.mybatisflex.core.paginate.Page;
|
||||||
import com.mybatisflex.core.keygen.impl.SnowFlakeIDKeyGenerator;
|
import com.mybatisflex.core.keygen.impl.SnowFlakeIDKeyGenerator;
|
||||||
import com.mybatisflex.core.query.QueryWrapper;
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -25,6 +27,8 @@ import tech.easyflow.common.satoken.util.SaTokenUtil;
|
|||||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||||
|
import tech.easyflow.system.entity.vo.RoleCategoryAccessSnapshot;
|
||||||
|
import tech.easyflow.system.service.CategoryPermissionService;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
@@ -34,6 +38,8 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static tech.easyflow.ai.entity.table.BotTableDef.BOT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 控制层。
|
* 控制层。
|
||||||
*
|
*
|
||||||
@@ -70,6 +76,8 @@ public class UcBotController extends BaseCurdController<BotService, Bot> {
|
|||||||
private BotPluginService botPluginService;
|
private BotPluginService botPluginService;
|
||||||
@Resource
|
@Resource
|
||||||
private BotConversationService conversationMessageService;
|
private BotConversationService conversationMessageService;
|
||||||
|
@Resource
|
||||||
|
private CategoryPermissionService categoryPermissionService;
|
||||||
|
|
||||||
@GetMapping("/generateConversationId")
|
@GetMapping("/generateConversationId")
|
||||||
public Result<Long> generateConversationId() {
|
public Result<Long> generateConversationId() {
|
||||||
@@ -188,7 +196,11 @@ public class UcBotController extends BaseCurdController<BotService, Bot> {
|
|||||||
@GetMapping("getDetail")
|
@GetMapping("getDetail")
|
||||||
@SaIgnore
|
@SaIgnore
|
||||||
public Result<Bot> getDetail(String id) {
|
public Result<Bot> getDetail(String id) {
|
||||||
return Result.ok(botService.getDetail(id));
|
Bot bot = botService.getDetail(id);
|
||||||
|
if (bot != null && StpUtil.isLogin()) {
|
||||||
|
categoryPermissionService.assertCategoryResourceVisible("BOT", bot.getCreatedBy(), bot.getCategoryId(), "无权限访问聊天助手");
|
||||||
|
}
|
||||||
|
return Result.ok(bot);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -198,6 +210,9 @@ public class UcBotController extends BaseCurdController<BotService, Bot> {
|
|||||||
if (data == null) {
|
if (data == null) {
|
||||||
return Result.ok(data);
|
return Result.ok(data);
|
||||||
}
|
}
|
||||||
|
if (StpUtil.isLogin()) {
|
||||||
|
categoryPermissionService.assertCategoryResourceVisible("BOT", data.getCreatedBy(), data.getCategoryId(), "无权限访问聊天助手");
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, Object> llmOptions = data.getModelOptions();
|
Map<String, Object> llmOptions = data.getModelOptions();
|
||||||
if (llmOptions == null) {
|
if (llmOptions == null) {
|
||||||
@@ -229,6 +244,32 @@ public class UcBotController extends BaseCurdController<BotService, Bot> {
|
|||||||
return Result.ok(data);
|
return Result.ok(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<List<Bot>> list(Bot entity, Boolean asTree, String sortKey, String sortType) {
|
||||||
|
QueryWrapper queryWrapper = QueryWrapper.create(entity, buildOperators(entity));
|
||||||
|
applyCategoryPermission(queryWrapper);
|
||||||
|
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||||
|
return Result.ok(service.list(queryWrapper));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Page<Bot> queryPage(Page<Bot> page, QueryWrapper queryWrapper) {
|
||||||
|
applyCategoryPermission(queryWrapper);
|
||||||
|
return super.queryPage(page, queryWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyCategoryPermission(QueryWrapper queryWrapper) {
|
||||||
|
RoleCategoryAccessSnapshot access = categoryPermissionService.getCurrentAccess("BOT");
|
||||||
|
if (!access.isRestricted()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (access.getCategoryIds().isEmpty()) {
|
||||||
|
queryWrapper.eq(Bot::getCreatedBy, access.getAccountId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
queryWrapper.and(BOT.CREATED_BY.eq(access.getAccountId()).or(BOT.CATEGORY_ID.in(access.getCategoryIds())));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Result<?> onSaveOrUpdateBefore(Bot entity, boolean isSave) {
|
protected Result<?> onSaveOrUpdateBefore(Bot entity, boolean isSave) {
|
||||||
|
|
||||||
|
|||||||
@@ -13,10 +13,15 @@ import tech.easyflow.common.domain.Result;
|
|||||||
import tech.easyflow.common.entity.LoginAccount;
|
import tech.easyflow.common.entity.LoginAccount;
|
||||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||||
|
import tech.easyflow.system.entity.vo.RoleCategoryAccessSnapshot;
|
||||||
|
import tech.easyflow.system.service.CategoryPermissionService;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static tech.easyflow.ai.entity.table.ResourceTableDef.RESOURCE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 素材库
|
* 素材库
|
||||||
@@ -28,6 +33,9 @@ import java.util.Date;
|
|||||||
@RequestMapping("/userCenter/resource")
|
@RequestMapping("/userCenter/resource")
|
||||||
@UsePermission(moduleName = "/api/v1/resource")
|
@UsePermission(moduleName = "/api/v1/resource")
|
||||||
public class UcResourceController extends BaseCurdController<ResourceService, Resource> {
|
public class UcResourceController extends BaseCurdController<ResourceService, Resource> {
|
||||||
|
@javax.annotation.Resource
|
||||||
|
private CategoryPermissionService categoryPermissionService;
|
||||||
|
|
||||||
public UcResourceController(ResourceService service) {
|
public UcResourceController(ResourceService service) {
|
||||||
super(service);
|
super(service);
|
||||||
}
|
}
|
||||||
@@ -52,7 +60,36 @@ public class UcResourceController extends BaseCurdController<ResourceService, Re
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Page<Resource> queryPage(Page<Resource> page, QueryWrapper queryWrapper) {
|
protected Page<Resource> queryPage(Page<Resource> page, QueryWrapper queryWrapper) {
|
||||||
queryWrapper.eq(Resource::getCreatedBy, SaTokenUtil.getLoginAccount().getId().toString());
|
applyCategoryPermission(queryWrapper);
|
||||||
return super.queryPage(page, queryWrapper);
|
return super.queryPage(page, queryWrapper);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
public Result<List<Resource>> list(Resource entity, Boolean asTree, String sortKey, String sortType) {
|
||||||
|
QueryWrapper queryWrapper = QueryWrapper.create(entity, buildOperators(entity));
|
||||||
|
applyCategoryPermission(queryWrapper);
|
||||||
|
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||||
|
return Result.ok(service.list(queryWrapper));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<Resource> detail(String id) {
|
||||||
|
Resource resource = service.getById(id);
|
||||||
|
if (resource != null) {
|
||||||
|
categoryPermissionService.assertCategoryResourceVisible("RESOURCE", resource.getCreatedBy(), resource.getCategoryId(), "无权限访问素材");
|
||||||
|
}
|
||||||
|
return Result.ok(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyCategoryPermission(QueryWrapper queryWrapper) {
|
||||||
|
RoleCategoryAccessSnapshot access = categoryPermissionService.getCurrentAccess("RESOURCE");
|
||||||
|
if (!access.isRestricted()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (access.getCategoryIds().isEmpty()) {
|
||||||
|
queryWrapper.eq(Resource::getCreatedBy, access.getAccountId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
queryWrapper.and(RESOURCE.CREATED_BY.eq(access.getAccountId()).or(RESOURCE.CATEGORY_ID.in(access.getCategoryIds())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,15 +1,22 @@
|
|||||||
package tech.easyflow.usercenter.controller.ai;
|
package tech.easyflow.usercenter.controller.ai;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import tech.easyflow.ai.entity.WorkflowCategory;
|
import tech.easyflow.ai.entity.WorkflowCategory;
|
||||||
import tech.easyflow.ai.service.WorkflowCategoryService;
|
import tech.easyflow.ai.service.WorkflowCategoryService;
|
||||||
import tech.easyflow.common.annotation.UsePermission;
|
import tech.easyflow.common.annotation.UsePermission;
|
||||||
import tech.easyflow.common.domain.Result;
|
import tech.easyflow.common.domain.Result;
|
||||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||||
|
import tech.easyflow.system.entity.vo.RoleCategoryAccessSnapshot;
|
||||||
|
import tech.easyflow.system.service.CategoryPermissionService;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 工作流分类
|
* 工作流分类
|
||||||
@@ -21,6 +28,8 @@ import java.util.Collection;
|
|||||||
@RequestMapping("/userCenter/workflowCategory")
|
@RequestMapping("/userCenter/workflowCategory")
|
||||||
@UsePermission(moduleName = "/api/v1/workflow")
|
@UsePermission(moduleName = "/api/v1/workflow")
|
||||||
public class UcWorkflowCategoryController extends BaseCurdController<WorkflowCategoryService, WorkflowCategory> {
|
public class UcWorkflowCategoryController extends BaseCurdController<WorkflowCategoryService, WorkflowCategory> {
|
||||||
|
@Resource
|
||||||
|
private CategoryPermissionService categoryPermissionService;
|
||||||
|
|
||||||
public UcWorkflowCategoryController(WorkflowCategoryService service) {
|
public UcWorkflowCategoryController(WorkflowCategoryService service) {
|
||||||
super(service);
|
super(service);
|
||||||
@@ -35,4 +44,18 @@ public class UcWorkflowCategoryController extends BaseCurdController<WorkflowCat
|
|||||||
protected Result<?> onRemoveBefore(Collection<Serializable> ids) {
|
protected Result<?> onRemoveBefore(Collection<Serializable> ids) {
|
||||||
return Result.fail("-");
|
return Result.fail("-");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@GetMapping("visibleList")
|
||||||
|
public Result<List<WorkflowCategory>> visibleList(WorkflowCategory entity, Boolean asTree, String sortKey, String sortType) {
|
||||||
|
QueryWrapper queryWrapper = QueryWrapper.create(entity, buildOperators(entity));
|
||||||
|
RoleCategoryAccessSnapshot access = categoryPermissionService.getCurrentAccess("WORKFLOW");
|
||||||
|
if (access.isRestricted()) {
|
||||||
|
if (access.getCategoryIds().isEmpty()) {
|
||||||
|
return Result.ok(Collections.emptyList());
|
||||||
|
}
|
||||||
|
queryWrapper.in(WorkflowCategory::getId, access.getCategoryIds());
|
||||||
|
}
|
||||||
|
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||||
|
return Result.ok(service.list(queryWrapper));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,11 +2,14 @@ package tech.easyflow.usercenter.controller.ai;
|
|||||||
|
|
||||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import com.mybatisflex.core.paginate.Page;
|
||||||
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
import com.easyagents.flow.core.chain.ChainDefinition;
|
import com.easyagents.flow.core.chain.ChainDefinition;
|
||||||
import com.easyagents.flow.core.chain.Parameter;
|
import com.easyagents.flow.core.chain.Parameter;
|
||||||
import com.easyagents.flow.core.chain.runtime.ChainExecutor;
|
import com.easyagents.flow.core.chain.runtime.ChainExecutor;
|
||||||
import com.easyagents.flow.core.parser.ChainParser;
|
import com.easyagents.flow.core.parser.ChainParser;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import tech.easyflow.ai.permission.WorkflowVisibilityQueryHelper;
|
||||||
import tech.easyflow.ai.easyagentsflow.entity.ChainInfo;
|
import tech.easyflow.ai.easyagentsflow.entity.ChainInfo;
|
||||||
import tech.easyflow.ai.easyagentsflow.entity.NodeInfo;
|
import tech.easyflow.ai.easyagentsflow.entity.NodeInfo;
|
||||||
import tech.easyflow.ai.easyagentsflow.entity.WorkflowCheckStage;
|
import tech.easyflow.ai.easyagentsflow.entity.WorkflowCheckStage;
|
||||||
@@ -20,6 +23,10 @@ import tech.easyflow.common.domain.Result;
|
|||||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||||
|
import tech.easyflow.system.enums.CategoryResourceType;
|
||||||
|
import tech.easyflow.system.enums.ResourceAction;
|
||||||
|
import tech.easyflow.system.enums.ResourceLookup;
|
||||||
|
import tech.easyflow.system.permission.resource.RequireResourceAccess;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
@@ -45,6 +52,8 @@ public class UcWorkflowController extends BaseCurdController<WorkflowService, Wo
|
|||||||
private TinyFlowService tinyFlowService;
|
private TinyFlowService tinyFlowService;
|
||||||
@Resource
|
@Resource
|
||||||
private WorkflowCheckService workflowCheckService;
|
private WorkflowCheckService workflowCheckService;
|
||||||
|
@Resource
|
||||||
|
private WorkflowVisibilityQueryHelper workflowVisibilityQueryHelper;
|
||||||
|
|
||||||
public UcWorkflowController(WorkflowService service) {
|
public UcWorkflowController(WorkflowService service) {
|
||||||
super(service);
|
super(service);
|
||||||
@@ -55,6 +64,13 @@ public class UcWorkflowController extends BaseCurdController<WorkflowService, Wo
|
|||||||
*/
|
*/
|
||||||
@PostMapping("/singleRun")
|
@PostMapping("/singleRun")
|
||||||
@SaCheckPermission("/api/v1/workflow/save")
|
@SaCheckPermission("/api/v1/workflow/save")
|
||||||
|
@RequireResourceAccess(
|
||||||
|
resource = CategoryResourceType.WORKFLOW,
|
||||||
|
action = ResourceAction.USE,
|
||||||
|
lookup = ResourceLookup.WORKFLOW_ID,
|
||||||
|
idExpr = "#workflowId",
|
||||||
|
denyMessage = "无权限运行工作流"
|
||||||
|
)
|
||||||
public Result<?> singleRun(
|
public Result<?> singleRun(
|
||||||
@JsonBody(value = "workflowId", required = true) BigInteger workflowId,
|
@JsonBody(value = "workflowId", required = true) BigInteger workflowId,
|
||||||
@JsonBody(value = "nodeId", required = true) String nodeId,
|
@JsonBody(value = "nodeId", required = true) String nodeId,
|
||||||
@@ -73,6 +89,13 @@ public class UcWorkflowController extends BaseCurdController<WorkflowService, Wo
|
|||||||
*/
|
*/
|
||||||
@PostMapping("/runAsync")
|
@PostMapping("/runAsync")
|
||||||
@SaCheckPermission("/api/v1/workflow/save")
|
@SaCheckPermission("/api/v1/workflow/save")
|
||||||
|
@RequireResourceAccess(
|
||||||
|
resource = CategoryResourceType.WORKFLOW,
|
||||||
|
action = ResourceAction.USE,
|
||||||
|
lookup = ResourceLookup.WORKFLOW_ID,
|
||||||
|
idExpr = "#id",
|
||||||
|
denyMessage = "无权限运行工作流"
|
||||||
|
)
|
||||||
public Result<String> runAsync(@JsonBody(value = "id", required = true) BigInteger id,
|
public Result<String> runAsync(@JsonBody(value = "id", required = true) BigInteger id,
|
||||||
@JsonBody("variables") Map<String, Object> variables) {
|
@JsonBody("variables") Map<String, Object> variables) {
|
||||||
if (variables == null) {
|
if (variables == null) {
|
||||||
@@ -94,6 +117,13 @@ public class UcWorkflowController extends BaseCurdController<WorkflowService, Wo
|
|||||||
* 获取工作流运行状态 - v2
|
* 获取工作流运行状态 - v2
|
||||||
*/
|
*/
|
||||||
@PostMapping("/getChainStatus")
|
@PostMapping("/getChainStatus")
|
||||||
|
@RequireResourceAccess(
|
||||||
|
resource = CategoryResourceType.WORKFLOW,
|
||||||
|
action = ResourceAction.USE,
|
||||||
|
lookup = ResourceLookup.EXEC_KEY,
|
||||||
|
idExpr = "#executeId",
|
||||||
|
denyMessage = "无权限访问该执行记录"
|
||||||
|
)
|
||||||
public Result<ChainInfo> getChainStatus(@JsonBody(value = "executeId") String executeId,
|
public Result<ChainInfo> getChainStatus(@JsonBody(value = "executeId") String executeId,
|
||||||
@JsonBody("nodes") List<NodeInfo> nodes) {
|
@JsonBody("nodes") List<NodeInfo> nodes) {
|
||||||
ChainInfo res = tinyFlowService.getChainStatus(executeId, nodes);
|
ChainInfo res = tinyFlowService.getChainStatus(executeId, nodes);
|
||||||
@@ -105,6 +135,13 @@ public class UcWorkflowController extends BaseCurdController<WorkflowService, Wo
|
|||||||
*/
|
*/
|
||||||
@PostMapping("/resume")
|
@PostMapping("/resume")
|
||||||
@SaCheckPermission("/api/v1/workflow/save")
|
@SaCheckPermission("/api/v1/workflow/save")
|
||||||
|
@RequireResourceAccess(
|
||||||
|
resource = CategoryResourceType.WORKFLOW,
|
||||||
|
action = ResourceAction.USE,
|
||||||
|
lookup = ResourceLookup.EXEC_KEY,
|
||||||
|
idExpr = "#executeId",
|
||||||
|
denyMessage = "无权限恢复工作流执行"
|
||||||
|
)
|
||||||
public Result<Void> resume(@JsonBody(value = "executeId", required = true) String executeId,
|
public Result<Void> resume(@JsonBody(value = "executeId", required = true) String executeId,
|
||||||
@JsonBody("confirmParams") Map<String, Object> confirmParams) {
|
@JsonBody("confirmParams") Map<String, Object> confirmParams) {
|
||||||
chainExecutor.resumeAsync(executeId, confirmParams);
|
chainExecutor.resumeAsync(executeId, confirmParams);
|
||||||
@@ -116,6 +153,13 @@ public class UcWorkflowController extends BaseCurdController<WorkflowService, Wo
|
|||||||
*/
|
*/
|
||||||
@GetMapping("getRunningParameters")
|
@GetMapping("getRunningParameters")
|
||||||
@SaCheckPermission("/api/v1/workflow/query")
|
@SaCheckPermission("/api/v1/workflow/query")
|
||||||
|
@RequireResourceAccess(
|
||||||
|
resource = CategoryResourceType.WORKFLOW,
|
||||||
|
action = ResourceAction.READ,
|
||||||
|
lookup = ResourceLookup.WORKFLOW_ID,
|
||||||
|
idExpr = "#id",
|
||||||
|
denyMessage = "无权限访问工作流"
|
||||||
|
)
|
||||||
public Result<?> getRunningParameters(@RequestParam BigInteger id) {
|
public Result<?> getRunningParameters(@RequestParam BigInteger id) {
|
||||||
Workflow workflow = service.getById(id);
|
Workflow workflow = service.getById(id);
|
||||||
|
|
||||||
@@ -146,4 +190,32 @@ public class UcWorkflowController extends BaseCurdController<WorkflowService, Wo
|
|||||||
protected Result<?> onRemoveBefore(Collection<Serializable> ids) {
|
protected Result<?> onRemoveBefore(Collection<Serializable> ids) {
|
||||||
return Result.fail("-");
|
return Result.fail("-");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<List<Workflow>> list(Workflow entity, Boolean asTree, String sortKey, String sortType) {
|
||||||
|
QueryWrapper queryWrapper = QueryWrapper.create(entity, buildOperators(entity));
|
||||||
|
workflowVisibilityQueryHelper.applyReadableAccess(queryWrapper);
|
||||||
|
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||||
|
return Result.ok(service.list(queryWrapper));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Page<Workflow> queryPage(Page<Workflow> page, QueryWrapper queryWrapper) {
|
||||||
|
workflowVisibilityQueryHelper.applyReadableAccess(queryWrapper);
|
||||||
|
return super.queryPage(page, queryWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@GetMapping("detail")
|
||||||
|
@RequireResourceAccess(
|
||||||
|
resource = CategoryResourceType.WORKFLOW,
|
||||||
|
action = ResourceAction.READ,
|
||||||
|
lookup = ResourceLookup.WORKFLOW_ID,
|
||||||
|
idExpr = "#id",
|
||||||
|
denyMessage = "无权限访问工作流"
|
||||||
|
)
|
||||||
|
public Result<Workflow> detail(String id) {
|
||||||
|
Workflow workflow = service.getDetail(id);
|
||||||
|
return Result.ok(workflow);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package tech.easyflow.ai.service;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public interface PluginVisibilityService {
|
||||||
|
|
||||||
|
Set<BigInteger> getCurrentVisiblePluginIds();
|
||||||
|
|
||||||
|
boolean canAccessPlugin(Long createdBy, BigInteger pluginId);
|
||||||
|
|
||||||
|
void assertPluginVisible(Long createdBy, BigInteger pluginId, String message);
|
||||||
|
}
|
||||||
@@ -41,6 +41,7 @@ import tech.easyflow.common.util.UrlEncoderUtil;
|
|||||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||||
import tech.easyflow.core.chat.protocol.sse.ChatSseEmitter;
|
import tech.easyflow.core.chat.protocol.sse.ChatSseEmitter;
|
||||||
import tech.easyflow.core.chat.protocol.sse.ChatSseUtil;
|
import tech.easyflow.core.chat.protocol.sse.ChatSseUtil;
|
||||||
|
import tech.easyflow.system.service.CategoryPermissionService;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
@@ -107,6 +108,8 @@ public class BotServiceImpl extends ServiceImpl<BotMapper, Bot> implements BotSe
|
|||||||
private McpService mcpService;
|
private McpService mcpService;
|
||||||
@Resource(name = "default")
|
@Resource(name = "default")
|
||||||
FileStorageService storageService;
|
FileStorageService storageService;
|
||||||
|
@Resource
|
||||||
|
private CategoryPermissionService categoryPermissionService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Bot getDetail(String id) {
|
public Bot getDetail(String id) {
|
||||||
@@ -144,6 +147,13 @@ public class BotServiceImpl extends ServiceImpl<BotMapper, Bot> implements BotSe
|
|||||||
if (aiBot == null) {
|
if (aiBot == null) {
|
||||||
return ChatSseUtil.sendSystemError(conversationId, "聊天助手不存在");
|
return ChatSseUtil.sendSystemError(conversationId, "聊天助手不存在");
|
||||||
}
|
}
|
||||||
|
if (StpUtil.isLogin()) {
|
||||||
|
try {
|
||||||
|
categoryPermissionService.assertCategoryResourceVisible("BOT", aiBot.getCreatedBy(), aiBot.getCategoryId(), "无权限访问聊天助手");
|
||||||
|
} catch (BusinessException e) {
|
||||||
|
return ChatSseUtil.sendSystemError(conversationId, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
if (aiBot.getModelId() == null) {
|
if (aiBot.getModelId() == null) {
|
||||||
return ChatSseUtil.sendSystemError(conversationId, "请配置大模型!");
|
return ChatSseUtil.sendSystemError(conversationId, "请配置大模型!");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +1,39 @@
|
|||||||
package tech.easyflow.ai.service.impl;
|
package tech.easyflow.ai.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
import com.mybatisflex.core.paginate.Page;
|
import com.mybatisflex.core.paginate.Page;
|
||||||
import com.mybatisflex.core.query.QueryWrapper;
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
import com.mybatisflex.spring.service.impl.ServiceImpl;
|
import com.mybatisflex.spring.service.impl.ServiceImpl;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import tech.easyflow.ai.entity.*;
|
import tech.easyflow.ai.entity.*;
|
||||||
import tech.easyflow.ai.mapper.PluginCategoryMappingMapper;
|
import tech.easyflow.ai.mapper.PluginCategoryMappingMapper;
|
||||||
import tech.easyflow.ai.mapper.PluginMapper;
|
import tech.easyflow.ai.mapper.PluginMapper;
|
||||||
import tech.easyflow.ai.service.BotPluginService;
|
import tech.easyflow.ai.service.BotPluginService;
|
||||||
import tech.easyflow.ai.service.PluginService;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import tech.easyflow.ai.service.PluginItemService;
|
import tech.easyflow.ai.service.PluginItemService;
|
||||||
|
import tech.easyflow.ai.service.PluginService;
|
||||||
|
import tech.easyflow.ai.service.PluginVisibilityService;
|
||||||
import tech.easyflow.common.domain.Result;
|
import tech.easyflow.common.domain.Result;
|
||||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||||
|
import tech.easyflow.system.entity.vo.RoleCategoryAccessSnapshot;
|
||||||
|
import tech.easyflow.system.service.CategoryPermissionService;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static tech.easyflow.ai.entity.table.PluginTableDef.PLUGIN;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 服务层实现。
|
* 服务层实现。
|
||||||
*
|
*
|
||||||
@@ -46,6 +56,10 @@ public class PluginServiceImpl extends ServiceImpl<PluginMapper, Plugin> impleme
|
|||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PluginItemService pluginItemService;
|
private PluginItemService pluginItemService;
|
||||||
|
@Resource
|
||||||
|
private CategoryPermissionService categoryPermissionService;
|
||||||
|
@Resource
|
||||||
|
private PluginVisibilityService pluginVisibilityService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Plugin savePlugin(Plugin plugin) {
|
public Plugin savePlugin(Plugin plugin) {
|
||||||
@@ -104,22 +118,39 @@ public class PluginServiceImpl extends ServiceImpl<PluginMapper, Plugin> impleme
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result<Page<Plugin>> pageByCategory(Long pageNumber, Long pageSize, int category) {
|
public Result<Page<Plugin>> pageByCategory(Long pageNumber, Long pageSize, int category) {
|
||||||
// 通过分类查询插件
|
RoleCategoryAccessSnapshot access = categoryPermissionService.getCurrentAccess("PLUGIN");
|
||||||
QueryWrapper queryWrapper = QueryWrapper.create().select(PluginCategoryMapping::getPluginId)
|
QueryWrapper queryWrapper = QueryWrapper.create().select(PluginCategoryMapping::getPluginId)
|
||||||
.eq(PluginCategoryMapping::getCategoryId, category);
|
.eq(PluginCategoryMapping::getCategoryId, category);
|
||||||
// 分页查询该分类中的插件
|
List<BigInteger> allCategoryPluginIds = pluginCategoryMappingMapper.selectListByQueryAs(queryWrapper, BigInteger.class)
|
||||||
Page<BigInteger> pagePluginIds = pluginCategoryMappingMapper.paginateAs(new Page<>(pageNumber, pageSize), queryWrapper, BigInteger.class);
|
.stream()
|
||||||
Page<PluginCategoryMapping> paginateCategories = pluginCategoryMappingMapper.paginate(pageNumber, pageSize, queryWrapper);
|
.filter(item -> item != null)
|
||||||
List<Plugin> plugins = Collections.emptyList();
|
.collect(Collectors.toCollection(ArrayList::new));
|
||||||
if (paginateCategories.getRecords().isEmpty()) {
|
if (CollectionUtil.isEmpty(allCategoryPluginIds)) {
|
||||||
return Result.ok(new Page<>(plugins, pageNumber, pageSize, paginateCategories.getTotalRow()));
|
return Result.ok(new Page<>(Collections.emptyList(), pageNumber, pageSize, 0L));
|
||||||
}
|
}
|
||||||
List<BigInteger> pluginIds = pagePluginIds.getRecords();
|
|
||||||
// 查询对应的插件信息
|
List<BigInteger> orderedCategoryPluginIds = new ArrayList<>(new LinkedHashSet<>(allCategoryPluginIds));
|
||||||
QueryWrapper queryPluginWrapper = QueryWrapper.create().select()
|
List<BigInteger> visiblePluginIds = orderedCategoryPluginIds;
|
||||||
.in(Plugin::getId, pluginIds);
|
if (access.isRestricted()) {
|
||||||
plugins = pluginMapper.selectListByQuery(queryPluginWrapper);
|
Set<BigInteger> visiblePluginIdSet = new LinkedHashSet<>(pluginVisibilityService.getCurrentVisiblePluginIds());
|
||||||
Page<Plugin> aiPluginPage = new Page<>(plugins, pageNumber, pageSize, paginateCategories.getTotalRow());
|
List<BigInteger> creatorPluginIds = queryCreatorPluginIds(orderedCategoryPluginIds, access.getAccountIdAsLong());
|
||||||
|
LinkedHashSet<BigInteger> mergedVisibleIds = orderedCategoryPluginIds.stream()
|
||||||
|
.filter(pluginId -> visiblePluginIdSet.contains(pluginId) || creatorPluginIds.contains(pluginId))
|
||||||
|
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||||
|
visiblePluginIds = new ArrayList<>(mergedVisibleIds);
|
||||||
|
}
|
||||||
|
if (visiblePluginIds.isEmpty()) {
|
||||||
|
return Result.ok(new Page<>(Collections.emptyList(), pageNumber, pageSize, 0L));
|
||||||
|
}
|
||||||
|
|
||||||
|
int fromIndex = Math.max(0, Math.toIntExact((pageNumber - 1) * pageSize));
|
||||||
|
if (fromIndex >= visiblePluginIds.size()) {
|
||||||
|
return Result.ok(new Page<>(Collections.emptyList(), pageNumber, pageSize, visiblePluginIds.size()));
|
||||||
|
}
|
||||||
|
int toIndex = Math.min(visiblePluginIds.size(), Math.toIntExact(fromIndex + pageSize));
|
||||||
|
List<BigInteger> currentPagePluginIds = new ArrayList<>(visiblePluginIds.subList(fromIndex, toIndex));
|
||||||
|
List<Plugin> plugins = queryPluginsByIds(currentPagePluginIds);
|
||||||
|
Page<Plugin> aiPluginPage = new Page<>(plugins, pageNumber, pageSize, visiblePluginIds.size());
|
||||||
return Result.ok(aiPluginPage);
|
return Result.ok(aiPluginPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,5 +160,37 @@ public class PluginServiceImpl extends ServiceImpl<PluginMapper, Plugin> impleme
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<BigInteger> queryCreatorPluginIds(List<BigInteger> pluginIds, Long creatorId) {
|
||||||
|
if (CollectionUtil.isEmpty(pluginIds) || creatorId == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
QueryWrapper creatorPluginWrapper = QueryWrapper.create().select(Plugin::getId)
|
||||||
|
.in(Plugin::getId, pluginIds)
|
||||||
|
.eq(Plugin::getCreatedBy, creatorId);
|
||||||
|
return pluginMapper.selectListByQueryAs(creatorPluginWrapper, BigInteger.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Plugin> queryPluginsByIds(List<BigInteger> pluginIds) {
|
||||||
|
if (CollectionUtil.isEmpty(pluginIds)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
QueryWrapper queryPluginWrapper = QueryWrapper.create().select().in(Plugin::getId, pluginIds);
|
||||||
|
List<Plugin> plugins = pluginMapper.selectListByQuery(queryPluginWrapper);
|
||||||
|
Map<BigInteger, Plugin> pluginMap = plugins.stream().collect(Collectors.toMap(
|
||||||
|
Plugin::getId,
|
||||||
|
item -> item,
|
||||||
|
(left, right) -> left,
|
||||||
|
LinkedHashMap::new
|
||||||
|
));
|
||||||
|
List<Plugin> orderedPlugins = new ArrayList<>();
|
||||||
|
for (BigInteger pluginId : pluginIds) {
|
||||||
|
Plugin plugin = pluginMap.get(pluginId);
|
||||||
|
if (plugin != null) {
|
||||||
|
orderedPlugins.add(plugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return orderedPlugins;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package tech.easyflow.ai.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import tech.easyflow.ai.entity.PluginCategoryMapping;
|
||||||
|
import tech.easyflow.ai.mapper.PluginCategoryMappingMapper;
|
||||||
|
import tech.easyflow.ai.service.PluginVisibilityService;
|
||||||
|
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||||
|
import tech.easyflow.system.entity.vo.RoleCategoryAccessSnapshot;
|
||||||
|
import tech.easyflow.system.service.CategoryPermissionService;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class PluginVisibilityServiceImpl implements PluginVisibilityService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CategoryPermissionService categoryPermissionService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private PluginCategoryMappingMapper pluginCategoryMappingMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<BigInteger> getCurrentVisiblePluginIds() {
|
||||||
|
RoleCategoryAccessSnapshot snapshot = categoryPermissionService.getCurrentAccess("PLUGIN");
|
||||||
|
if (!snapshot.isRestricted() || CollectionUtil.isEmpty(snapshot.getCategoryIds())) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
QueryWrapper mappingWrapper = QueryWrapper.create()
|
||||||
|
.select(PluginCategoryMapping::getPluginId)
|
||||||
|
.in(PluginCategoryMapping::getCategoryId, snapshot.getCategoryIds());
|
||||||
|
List<BigInteger> pluginIds = pluginCategoryMappingMapper.selectListByQueryAs(mappingWrapper, BigInteger.class);
|
||||||
|
return new LinkedHashSet<>(pluginIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canAccessPlugin(Long createdBy, BigInteger pluginId) {
|
||||||
|
RoleCategoryAccessSnapshot snapshot = categoryPermissionService.getCurrentAccess("PLUGIN");
|
||||||
|
if (!snapshot.isRestricted()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (createdBy != null && snapshot.getAccountId() != null
|
||||||
|
&& snapshot.getAccountId().equals(BigInteger.valueOf(createdBy))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (CollectionUtil.isEmpty(snapshot.getCategoryIds())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
QueryWrapper mappingWrapper = QueryWrapper.create()
|
||||||
|
.select(PluginCategoryMapping::getPluginId)
|
||||||
|
.eq(PluginCategoryMapping::getPluginId, pluginId)
|
||||||
|
.in(PluginCategoryMapping::getCategoryId, snapshot.getCategoryIds());
|
||||||
|
List<BigInteger> pluginIds = pluginCategoryMappingMapper.selectListByQueryAs(mappingWrapper, BigInteger.class);
|
||||||
|
return CollectionUtil.isNotEmpty(pluginIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void assertPluginVisible(Long createdBy, BigInteger pluginId, String message) {
|
||||||
|
if (!canAccessPlugin(createdBy, pluginId)) {
|
||||||
|
throw new BusinessException(message == null ? "无权限访问该资源" : message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package tech.easyflow.system.entity;
|
||||||
|
|
||||||
|
import com.mybatisflex.annotation.Column;
|
||||||
|
import com.mybatisflex.annotation.Table;
|
||||||
|
import tech.easyflow.system.entity.base.SysRoleCategoryScopeBase;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Table(value = "tb_sys_role_category_scope", comment = "角色分类权限范围")
|
||||||
|
public class SysRoleCategoryScope extends SysRoleCategoryScopeBase {
|
||||||
|
|
||||||
|
@Column(ignore = true)
|
||||||
|
private List<BigInteger> categoryIds;
|
||||||
|
|
||||||
|
public List<BigInteger> getCategoryIds() {
|
||||||
|
return categoryIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCategoryIds(List<BigInteger> categoryIds) {
|
||||||
|
this.categoryIds = categoryIds;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package tech.easyflow.system.entity;
|
||||||
|
|
||||||
|
import com.mybatisflex.annotation.Table;
|
||||||
|
import tech.easyflow.system.entity.base.SysRoleCategoryScopeItemBase;
|
||||||
|
|
||||||
|
@Table(value = "tb_sys_role_category_scope_item", comment = "角色分类权限明细")
|
||||||
|
public class SysRoleCategoryScopeItem extends SysRoleCategoryScopeItemBase {
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
package tech.easyflow.system.entity.base;
|
||||||
|
|
||||||
|
import com.mybatisflex.annotation.Column;
|
||||||
|
import com.mybatisflex.annotation.Id;
|
||||||
|
import com.mybatisflex.annotation.KeyType;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class SysRoleCategoryScopeBase implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Id(keyType = KeyType.Generator, value = "snowFlakeId", comment = "主键")
|
||||||
|
private BigInteger id;
|
||||||
|
|
||||||
|
@Column(comment = "角色ID")
|
||||||
|
private BigInteger roleId;
|
||||||
|
|
||||||
|
@Column(comment = "资源类型")
|
||||||
|
private String resourceType;
|
||||||
|
|
||||||
|
@Column(comment = "范围模式")
|
||||||
|
private String scopeMode;
|
||||||
|
|
||||||
|
@Column(comment = "创建时间")
|
||||||
|
private Date created;
|
||||||
|
|
||||||
|
@Column(comment = "创建者")
|
||||||
|
private BigInteger createdBy;
|
||||||
|
|
||||||
|
@Column(comment = "修改时间")
|
||||||
|
private Date modified;
|
||||||
|
|
||||||
|
@Column(comment = "修改者")
|
||||||
|
private BigInteger modifiedBy;
|
||||||
|
|
||||||
|
public BigInteger getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(BigInteger id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigInteger getRoleId() {
|
||||||
|
return roleId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoleId(BigInteger roleId) {
|
||||||
|
this.roleId = roleId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResourceType() {
|
||||||
|
return resourceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResourceType(String resourceType) {
|
||||||
|
this.resourceType = resourceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getScopeMode() {
|
||||||
|
return scopeMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScopeMode(String scopeMode) {
|
||||||
|
this.scopeMode = scopeMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreated() {
|
||||||
|
return created;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreated(Date created) {
|
||||||
|
this.created = created;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigInteger getCreatedBy() {
|
||||||
|
return createdBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatedBy(BigInteger createdBy) {
|
||||||
|
this.createdBy = createdBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getModified() {
|
||||||
|
return modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModified(Date modified) {
|
||||||
|
this.modified = modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigInteger getModifiedBy() {
|
||||||
|
return modifiedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModifiedBy(BigInteger modifiedBy) {
|
||||||
|
this.modifiedBy = modifiedBy;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package tech.easyflow.system.entity.base;
|
||||||
|
|
||||||
|
import com.mybatisflex.annotation.Column;
|
||||||
|
import com.mybatisflex.annotation.Id;
|
||||||
|
import com.mybatisflex.annotation.KeyType;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
public class SysRoleCategoryScopeItemBase implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Id(keyType = KeyType.Generator, value = "snowFlakeId", comment = "主键")
|
||||||
|
private BigInteger id;
|
||||||
|
|
||||||
|
@Column(comment = "范围ID")
|
||||||
|
private BigInteger scopeId;
|
||||||
|
|
||||||
|
@Column(comment = "分类ID")
|
||||||
|
private BigInteger categoryId;
|
||||||
|
|
||||||
|
public BigInteger getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(BigInteger id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigInteger getScopeId() {
|
||||||
|
return scopeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScopeId(BigInteger scopeId) {
|
||||||
|
this.scopeId = scopeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigInteger getCategoryId() {
|
||||||
|
return categoryId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCategoryId(BigInteger categoryId) {
|
||||||
|
this.categoryId = categoryId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package tech.easyflow.system.entity.vo;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class RoleCategoryAccessSnapshot {
|
||||||
|
|
||||||
|
private final String resourceType;
|
||||||
|
private final BigInteger accountId;
|
||||||
|
private final boolean superAdmin;
|
||||||
|
private final boolean allAccess;
|
||||||
|
private final Set<BigInteger> categoryIds;
|
||||||
|
|
||||||
|
public RoleCategoryAccessSnapshot(String resourceType,
|
||||||
|
BigInteger accountId,
|
||||||
|
boolean superAdmin,
|
||||||
|
boolean allAccess,
|
||||||
|
Set<BigInteger> categoryIds) {
|
||||||
|
this.resourceType = resourceType;
|
||||||
|
this.accountId = accountId;
|
||||||
|
this.superAdmin = superAdmin;
|
||||||
|
this.allAccess = allAccess;
|
||||||
|
this.categoryIds = categoryIds == null
|
||||||
|
? Collections.emptySet()
|
||||||
|
: Collections.unmodifiableSet(new LinkedHashSet<>(categoryIds));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResourceType() {
|
||||||
|
return resourceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigInteger getAccountId() {
|
||||||
|
return accountId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getAccountIdAsLong() {
|
||||||
|
return accountId == null ? null : accountId.longValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSuperAdmin() {
|
||||||
|
return superAdmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAllAccess() {
|
||||||
|
return allAccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<BigInteger> getCategoryIds() {
|
||||||
|
return categoryIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRestricted() {
|
||||||
|
return !superAdmin && !allAccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canAccess(BigInteger createdBy, BigInteger categoryId) {
|
||||||
|
if (!isRestricted()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (accountId != null && accountId.equals(createdBy)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return categoryId != null && categoryIds.contains(categoryId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package tech.easyflow.system.entity.vo;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SysRoleCategoryScopeDetailVo {
|
||||||
|
|
||||||
|
private BigInteger roleId;
|
||||||
|
|
||||||
|
private boolean editable;
|
||||||
|
|
||||||
|
private List<SysRoleCategoryScopeItemVo> scopes = new ArrayList<>();
|
||||||
|
|
||||||
|
public BigInteger getRoleId() {
|
||||||
|
return roleId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoleId(BigInteger roleId) {
|
||||||
|
this.roleId = roleId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEditable() {
|
||||||
|
return editable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEditable(boolean editable) {
|
||||||
|
this.editable = editable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<SysRoleCategoryScopeItemVo> getScopes() {
|
||||||
|
return scopes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScopes(List<SysRoleCategoryScopeItemVo> scopes) {
|
||||||
|
this.scopes = scopes;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package tech.easyflow.system.entity.vo;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SysRoleCategoryScopeItemVo {
|
||||||
|
|
||||||
|
private String resourceType;
|
||||||
|
|
||||||
|
private String scopeMode;
|
||||||
|
|
||||||
|
private List<BigInteger> categoryIds = new ArrayList<>();
|
||||||
|
|
||||||
|
public String getResourceType() {
|
||||||
|
return resourceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResourceType(String resourceType) {
|
||||||
|
this.resourceType = resourceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getScopeMode() {
|
||||||
|
return scopeMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScopeMode(String scopeMode) {
|
||||||
|
this.scopeMode = scopeMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<BigInteger> getCategoryIds() {
|
||||||
|
return categoryIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCategoryIds(List<BigInteger> categoryIds) {
|
||||||
|
this.categoryIds = categoryIds;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package tech.easyflow.system.enums;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public enum CategoryResourceType {
|
||||||
|
|
||||||
|
BOT("BOT"),
|
||||||
|
PLUGIN("PLUGIN"),
|
||||||
|
WORKFLOW("WORKFLOW"),
|
||||||
|
KNOWLEDGE("KNOWLEDGE"),
|
||||||
|
RESOURCE("RESOURCE");
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
|
||||||
|
CategoryResourceType(String code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CategoryResourceType from(String code) {
|
||||||
|
if (code == null) {
|
||||||
|
throw new IllegalArgumentException("resourceType不能为空");
|
||||||
|
}
|
||||||
|
String normalized = code.trim().toUpperCase(Locale.ROOT);
|
||||||
|
return Arrays.stream(values())
|
||||||
|
.filter(item -> item.code.equals(normalized))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new IllegalArgumentException("不支持的resourceType: " + code));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> allCodes() {
|
||||||
|
return Arrays.stream(values()).map(CategoryResourceType::getCode).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package tech.easyflow.system.enums;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public enum CategoryScopeMode {
|
||||||
|
|
||||||
|
ALL("ALL"),
|
||||||
|
CUSTOM("CUSTOM");
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
|
||||||
|
CategoryScopeMode(String code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CategoryScopeMode from(String code) {
|
||||||
|
if (code == null) {
|
||||||
|
return CUSTOM;
|
||||||
|
}
|
||||||
|
String normalized = code.trim().toUpperCase(Locale.ROOT);
|
||||||
|
return Arrays.stream(values())
|
||||||
|
.filter(item -> item.code.equals(normalized))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new IllegalArgumentException("不支持的scopeMode: " + code));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package tech.easyflow.system.mapper;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.BaseMapper;
|
||||||
|
import tech.easyflow.system.entity.SysRoleCategoryScopeItem;
|
||||||
|
|
||||||
|
public interface SysRoleCategoryScopeItemMapper extends BaseMapper<SysRoleCategoryScopeItem> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package tech.easyflow.system.mapper;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.BaseMapper;
|
||||||
|
import tech.easyflow.system.entity.SysRoleCategoryScope;
|
||||||
|
|
||||||
|
public interface SysRoleCategoryScopeMapper extends BaseMapper<SysRoleCategoryScope> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package tech.easyflow.system.service;
|
||||||
|
|
||||||
|
import tech.easyflow.system.entity.vo.RoleCategoryAccessSnapshot;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public interface CategoryPermissionService {
|
||||||
|
|
||||||
|
boolean isCurrentSuperAdmin();
|
||||||
|
|
||||||
|
RoleCategoryAccessSnapshot getCurrentAccess(String resourceType);
|
||||||
|
|
||||||
|
Set<BigInteger> getCurrentVisibleCategoryIds(String resourceType);
|
||||||
|
|
||||||
|
boolean canAccessCategory(String resourceType, BigInteger createdBy, BigInteger categoryId);
|
||||||
|
|
||||||
|
void assertCategoryResourceVisible(String resourceType, BigInteger createdBy, BigInteger categoryId, String message);
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package tech.easyflow.system.service;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.service.IService;
|
||||||
|
import tech.easyflow.system.entity.SysRoleCategoryScope;
|
||||||
|
import tech.easyflow.system.entity.vo.SysRoleCategoryScopeDetailVo;
|
||||||
|
import tech.easyflow.system.entity.vo.SysRoleCategoryScopeItemVo;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface SysRoleCategoryScopeService extends IService<SysRoleCategoryScope> {
|
||||||
|
|
||||||
|
SysRoleCategoryScopeDetailVo getRoleScopeDetail(BigInteger roleId);
|
||||||
|
|
||||||
|
void saveRoleScopes(BigInteger roleId, List<SysRoleCategoryScopeItemVo> scopes, BigInteger operatorId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
package tech.easyflow.system.service.impl;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import tech.easyflow.common.constant.Constants;
|
||||||
|
import tech.easyflow.common.entity.LoginAccount;
|
||||||
|
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||||
|
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||||
|
import tech.easyflow.system.entity.SysRole;
|
||||||
|
import tech.easyflow.system.entity.SysRoleCategoryScope;
|
||||||
|
import tech.easyflow.system.entity.SysRoleCategoryScopeItem;
|
||||||
|
import tech.easyflow.system.entity.vo.RoleCategoryAccessSnapshot;
|
||||||
|
import tech.easyflow.system.enums.CategoryScopeMode;
|
||||||
|
import tech.easyflow.system.mapper.SysRoleCategoryScopeItemMapper;
|
||||||
|
import tech.easyflow.system.mapper.SysRoleCategoryScopeMapper;
|
||||||
|
import tech.easyflow.system.service.CategoryPermissionService;
|
||||||
|
import tech.easyflow.system.service.SysRoleService;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class CategoryPermissionServiceImpl implements CategoryPermissionService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SysRoleService sysRoleService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SysRoleCategoryScopeMapper sysRoleCategoryScopeMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SysRoleCategoryScopeItemMapper sysRoleCategoryScopeItemMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCurrentSuperAdmin() {
|
||||||
|
if (!StpUtil.isLogin()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LoginAccount loginAccount = SaTokenUtil.getLoginAccount();
|
||||||
|
return loginAccount != null && isSuperAdmin(loginAccount.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RoleCategoryAccessSnapshot getCurrentAccess(String resourceType) {
|
||||||
|
if (!StpUtil.isLogin()) {
|
||||||
|
return new RoleCategoryAccessSnapshot(resourceType, null, false, true, Collections.emptySet());
|
||||||
|
}
|
||||||
|
LoginAccount loginAccount = SaTokenUtil.getLoginAccount();
|
||||||
|
if (loginAccount == null) {
|
||||||
|
return new RoleCategoryAccessSnapshot(resourceType, null, false, true, Collections.emptySet());
|
||||||
|
}
|
||||||
|
BigInteger accountId = loginAccount.getId();
|
||||||
|
if (isSuperAdmin(accountId)) {
|
||||||
|
return new RoleCategoryAccessSnapshot(resourceType, accountId, true, true, Collections.emptySet());
|
||||||
|
}
|
||||||
|
List<SysRole> roles = sysRoleService.getRolesByAccountId(accountId);
|
||||||
|
if (CollectionUtil.isEmpty(roles)) {
|
||||||
|
return new RoleCategoryAccessSnapshot(resourceType, accountId, false, false, Collections.emptySet());
|
||||||
|
}
|
||||||
|
List<BigInteger> roleIds = roles.stream().map(SysRole::getId).collect(Collectors.toList());
|
||||||
|
QueryWrapper scopeWrapper = QueryWrapper.create()
|
||||||
|
.in(SysRoleCategoryScope::getRoleId, roleIds)
|
||||||
|
.eq(SysRoleCategoryScope::getResourceType, resourceType);
|
||||||
|
List<SysRoleCategoryScope> scopes = sysRoleCategoryScopeMapper.selectListByQuery(scopeWrapper);
|
||||||
|
if (CollectionUtil.isEmpty(scopes)) {
|
||||||
|
return new RoleCategoryAccessSnapshot(resourceType, accountId, false, false, Collections.emptySet());
|
||||||
|
}
|
||||||
|
boolean allAccess = scopes.stream()
|
||||||
|
.anyMatch(item -> CategoryScopeMode.ALL.getCode().equalsIgnoreCase(item.getScopeMode()));
|
||||||
|
if (allAccess) {
|
||||||
|
return new RoleCategoryAccessSnapshot(resourceType, accountId, false, true, Collections.emptySet());
|
||||||
|
}
|
||||||
|
List<BigInteger> scopeIds = scopes.stream().map(SysRoleCategoryScope::getId).collect(Collectors.toList());
|
||||||
|
if (CollectionUtil.isEmpty(scopeIds)) {
|
||||||
|
return new RoleCategoryAccessSnapshot(resourceType, accountId, false, false, Collections.emptySet());
|
||||||
|
}
|
||||||
|
QueryWrapper itemWrapper = QueryWrapper.create().in(SysRoleCategoryScopeItem::getScopeId, scopeIds);
|
||||||
|
List<SysRoleCategoryScopeItem> items = sysRoleCategoryScopeItemMapper.selectListByQuery(itemWrapper);
|
||||||
|
Set<BigInteger> categoryIds = items.stream()
|
||||||
|
.map(SysRoleCategoryScopeItem::getCategoryId)
|
||||||
|
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||||
|
return new RoleCategoryAccessSnapshot(resourceType, accountId, false, false, categoryIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<BigInteger> getCurrentVisibleCategoryIds(String resourceType) {
|
||||||
|
return getCurrentAccess(resourceType).getCategoryIds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canAccessCategory(String resourceType, BigInteger createdBy, BigInteger categoryId) {
|
||||||
|
RoleCategoryAccessSnapshot snapshot = getCurrentAccess(resourceType);
|
||||||
|
return snapshot.canAccess(createdBy, categoryId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void assertCategoryResourceVisible(String resourceType, BigInteger createdBy, BigInteger categoryId, String message) {
|
||||||
|
if (!canAccessCategory(resourceType, createdBy, categoryId)) {
|
||||||
|
throw new BusinessException(message == null ? "无权限访问该资源" : message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSuperAdmin(BigInteger accountId) {
|
||||||
|
List<SysRole> roles = sysRoleService.getRolesByAccountId(accountId);
|
||||||
|
return CollectionUtil.isNotEmpty(roles)
|
||||||
|
&& roles.stream().anyMatch(item -> Constants.SUPER_ADMIN_ROLE_CODE.equals(item.getRoleKey()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
package tech.easyflow.system.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
|
import com.mybatisflex.spring.service.impl.ServiceImpl;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import tech.easyflow.system.entity.SysRoleCategoryScope;
|
||||||
|
import tech.easyflow.system.entity.SysRoleCategoryScopeItem;
|
||||||
|
import tech.easyflow.system.entity.vo.SysRoleCategoryScopeDetailVo;
|
||||||
|
import tech.easyflow.system.entity.vo.SysRoleCategoryScopeItemVo;
|
||||||
|
import tech.easyflow.system.enums.CategoryResourceType;
|
||||||
|
import tech.easyflow.system.enums.CategoryScopeMode;
|
||||||
|
import tech.easyflow.system.mapper.SysRoleCategoryScopeItemMapper;
|
||||||
|
import tech.easyflow.system.mapper.SysRoleCategoryScopeMapper;
|
||||||
|
import tech.easyflow.system.service.SysRoleCategoryScopeService;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class SysRoleCategoryScopeServiceImpl extends ServiceImpl<SysRoleCategoryScopeMapper, SysRoleCategoryScope>
|
||||||
|
implements SysRoleCategoryScopeService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SysRoleCategoryScopeMapper sysRoleCategoryScopeMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SysRoleCategoryScopeItemMapper sysRoleCategoryScopeItemMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SysRoleCategoryScopeDetailVo getRoleScopeDetail(BigInteger roleId) {
|
||||||
|
SysRoleCategoryScopeDetailVo detailVo = new SysRoleCategoryScopeDetailVo();
|
||||||
|
detailVo.setRoleId(roleId);
|
||||||
|
if (roleId == null) {
|
||||||
|
detailVo.setScopes(defaultScopes());
|
||||||
|
return detailVo;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryWrapper scopeWrapper = QueryWrapper.create().eq(SysRoleCategoryScope::getRoleId, roleId);
|
||||||
|
List<SysRoleCategoryScope> scopes = list(scopeWrapper);
|
||||||
|
if (CollectionUtil.isEmpty(scopes)) {
|
||||||
|
detailVo.setScopes(defaultScopes());
|
||||||
|
return detailVo;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<BigInteger> scopeIds = scopes.stream().map(SysRoleCategoryScope::getId).collect(Collectors.toList());
|
||||||
|
Map<BigInteger, List<BigInteger>> scopeItemMap = new LinkedHashMap<>();
|
||||||
|
if (CollectionUtil.isNotEmpty(scopeIds)) {
|
||||||
|
QueryWrapper itemWrapper = QueryWrapper.create().in(SysRoleCategoryScopeItem::getScopeId, scopeIds);
|
||||||
|
List<SysRoleCategoryScopeItem> items = sysRoleCategoryScopeItemMapper.selectListByQuery(itemWrapper);
|
||||||
|
scopeItemMap = items.stream().collect(Collectors.groupingBy(
|
||||||
|
SysRoleCategoryScopeItem::getScopeId,
|
||||||
|
LinkedHashMap::new,
|
||||||
|
Collectors.mapping(SysRoleCategoryScopeItem::getCategoryId, Collectors.toList())
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, SysRoleCategoryScope> scopeMap = scopes.stream().collect(Collectors.toMap(
|
||||||
|
SysRoleCategoryScope::getResourceType,
|
||||||
|
item -> item,
|
||||||
|
(left, right) -> left,
|
||||||
|
LinkedHashMap::new
|
||||||
|
));
|
||||||
|
|
||||||
|
List<SysRoleCategoryScopeItemVo> result = new ArrayList<>();
|
||||||
|
for (String resourceType : CategoryResourceType.allCodes()) {
|
||||||
|
SysRoleCategoryScope existing = scopeMap.get(resourceType);
|
||||||
|
SysRoleCategoryScopeItemVo itemVo = new SysRoleCategoryScopeItemVo();
|
||||||
|
itemVo.setResourceType(resourceType);
|
||||||
|
if (existing == null) {
|
||||||
|
itemVo.setScopeMode(CategoryScopeMode.CUSTOM.getCode());
|
||||||
|
itemVo.setCategoryIds(new ArrayList<>());
|
||||||
|
} else {
|
||||||
|
itemVo.setScopeMode(CategoryScopeMode.from(existing.getScopeMode()).getCode());
|
||||||
|
itemVo.setCategoryIds(new ArrayList<>(scopeItemMap.getOrDefault(existing.getId(), new ArrayList<>())));
|
||||||
|
}
|
||||||
|
result.add(itemVo);
|
||||||
|
}
|
||||||
|
detailVo.setScopes(result);
|
||||||
|
return detailVo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void saveRoleScopes(BigInteger roleId, List<SysRoleCategoryScopeItemVo> scopes, BigInteger operatorId) {
|
||||||
|
QueryWrapper scopeWrapper = QueryWrapper.create().eq(SysRoleCategoryScope::getRoleId, roleId);
|
||||||
|
List<SysRoleCategoryScope> existingScopes = sysRoleCategoryScopeMapper.selectListByQuery(scopeWrapper);
|
||||||
|
if (CollectionUtil.isNotEmpty(existingScopes)) {
|
||||||
|
List<BigInteger> existingScopeIds = existingScopes.stream()
|
||||||
|
.map(SysRoleCategoryScope::getId)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (CollectionUtil.isNotEmpty(existingScopeIds)) {
|
||||||
|
QueryWrapper itemDeleteWrapper = QueryWrapper.create().in(SysRoleCategoryScopeItem::getScopeId, existingScopeIds);
|
||||||
|
sysRoleCategoryScopeItemMapper.deleteByQuery(itemDeleteWrapper);
|
||||||
|
}
|
||||||
|
sysRoleCategoryScopeMapper.deleteByQuery(scopeWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
Date now = new Date();
|
||||||
|
for (SysRoleCategoryScopeItemVo itemVo : normalizeScopes(scopes)) {
|
||||||
|
SysRoleCategoryScope scope = new SysRoleCategoryScope();
|
||||||
|
scope.setRoleId(roleId);
|
||||||
|
scope.setResourceType(itemVo.getResourceType());
|
||||||
|
scope.setScopeMode(itemVo.getScopeMode());
|
||||||
|
scope.setCreated(now);
|
||||||
|
scope.setCreatedBy(operatorId);
|
||||||
|
scope.setModified(now);
|
||||||
|
scope.setModifiedBy(operatorId);
|
||||||
|
sysRoleCategoryScopeMapper.insert(scope);
|
||||||
|
|
||||||
|
if (!CategoryScopeMode.CUSTOM.getCode().equals(itemVo.getScopeMode())
|
||||||
|
|| CollectionUtil.isEmpty(itemVo.getCategoryIds())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (BigInteger categoryId : itemVo.getCategoryIds()) {
|
||||||
|
SysRoleCategoryScopeItem scopeItem = new SysRoleCategoryScopeItem();
|
||||||
|
scopeItem.setScopeId(scope.getId());
|
||||||
|
scopeItem.setCategoryId(categoryId);
|
||||||
|
sysRoleCategoryScopeItemMapper.insert(scopeItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<SysRoleCategoryScopeItemVo> defaultScopes() {
|
||||||
|
return normalizeScopes(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<SysRoleCategoryScopeItemVo> normalizeScopes(List<SysRoleCategoryScopeItemVo> scopes) {
|
||||||
|
Map<String, SysRoleCategoryScopeItemVo> scopeMap = new LinkedHashMap<>();
|
||||||
|
if (CollectionUtil.isNotEmpty(scopes)) {
|
||||||
|
for (SysRoleCategoryScopeItemVo itemVo : scopes) {
|
||||||
|
if (itemVo == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String resourceType = CategoryResourceType.from(itemVo.getResourceType()).getCode();
|
||||||
|
CategoryScopeMode scopeMode = CategoryScopeMode.from(itemVo.getScopeMode());
|
||||||
|
SysRoleCategoryScopeItemVo normalized = new SysRoleCategoryScopeItemVo();
|
||||||
|
normalized.setResourceType(resourceType);
|
||||||
|
normalized.setScopeMode(scopeMode.getCode());
|
||||||
|
Set<BigInteger> categoryIds = itemVo.getCategoryIds() == null
|
||||||
|
? new LinkedHashSet<>()
|
||||||
|
: itemVo.getCategoryIds().stream()
|
||||||
|
.filter(item -> item != null)
|
||||||
|
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||||
|
normalized.setCategoryIds(new ArrayList<>(categoryIds));
|
||||||
|
scopeMap.put(resourceType, normalized);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<SysRoleCategoryScopeItemVo> result = new ArrayList<>();
|
||||||
|
for (String resourceType : CategoryResourceType.allCodes()) {
|
||||||
|
SysRoleCategoryScopeItemVo itemVo = scopeMap.get(resourceType);
|
||||||
|
if (itemVo == null) {
|
||||||
|
itemVo = new SysRoleCategoryScopeItemVo();
|
||||||
|
itemVo.setResourceType(resourceType);
|
||||||
|
itemVo.setScopeMode(CategoryScopeMode.CUSTOM.getCode());
|
||||||
|
itemVo.setCategoryIds(new ArrayList<>());
|
||||||
|
}
|
||||||
|
result.add(itemVo);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
CREATE TABLE `tb_sys_role_category_scope`
|
||||||
|
(
|
||||||
|
`id` bigint UNSIGNED NOT NULL COMMENT '主键',
|
||||||
|
`role_id` bigint UNSIGNED NOT NULL COMMENT '角色ID',
|
||||||
|
`resource_type` varchar(32) NOT NULL COMMENT '资源类型',
|
||||||
|
`scope_mode` varchar(16) NOT NULL COMMENT '范围模式',
|
||||||
|
`created` datetime NULL DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`created_by` bigint UNSIGNED NULL DEFAULT NULL COMMENT '创建者',
|
||||||
|
`modified` datetime NULL DEFAULT NULL COMMENT '修改时间',
|
||||||
|
`modified_by` bigint UNSIGNED NULL DEFAULT NULL COMMENT '修改者',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
UNIQUE INDEX `uni_role_resource_type`(`role_id`, `resource_type`) USING BTREE
|
||||||
|
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '角色分类权限范围';
|
||||||
|
|
||||||
|
CREATE TABLE `tb_sys_role_category_scope_item`
|
||||||
|
(
|
||||||
|
`id` bigint UNSIGNED NOT NULL COMMENT '主键',
|
||||||
|
`scope_id` bigint UNSIGNED NOT NULL COMMENT '范围ID',
|
||||||
|
`category_id` bigint UNSIGNED NOT NULL COMMENT '分类ID',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
UNIQUE INDEX `uni_scope_category`(`scope_id`, `category_id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '角色分类权限明细';
|
||||||
|
|
||||||
|
INSERT INTO `tb_sys_role_category_scope` (`id`, `role_id`, `resource_type`, `scope_mode`, `created`, `created_by`, `modified`, `modified_by`)
|
||||||
|
SELECT UUID_SHORT(), `id`, 'BOT', 'ALL', NOW(), `created_by`, NOW(), `modified_by`
|
||||||
|
FROM `tb_sys_role`
|
||||||
|
WHERE `role_key` = 'super_admin'
|
||||||
|
UNION ALL
|
||||||
|
SELECT UUID_SHORT(), `id`, 'PLUGIN', 'ALL', NOW(), `created_by`, NOW(), `modified_by`
|
||||||
|
FROM `tb_sys_role`
|
||||||
|
WHERE `role_key` = 'super_admin'
|
||||||
|
UNION ALL
|
||||||
|
SELECT UUID_SHORT(), `id`, 'WORKFLOW', 'ALL', NOW(), `created_by`, NOW(), `modified_by`
|
||||||
|
FROM `tb_sys_role`
|
||||||
|
WHERE `role_key` = 'super_admin'
|
||||||
|
UNION ALL
|
||||||
|
SELECT UUID_SHORT(), `id`, 'KNOWLEDGE', 'ALL', NOW(), `created_by`, NOW(), `modified_by`
|
||||||
|
FROM `tb_sys_role`
|
||||||
|
WHERE `role_key` = 'super_admin'
|
||||||
|
UNION ALL
|
||||||
|
SELECT UUID_SHORT(), `id`, 'RESOURCE', 'ALL', NOW(), `created_by`, NOW(), `modified_by`
|
||||||
|
FROM `tb_sys_role`
|
||||||
|
WHERE `role_key` = 'super_admin';
|
||||||
@@ -9,10 +9,15 @@ import { api } from '#/api/request';
|
|||||||
import { $t } from '#/locales';
|
import { $t } from '#/locales';
|
||||||
// 定义组件属性
|
// 定义组件属性
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
// 直接传入树数据
|
||||||
|
data: {
|
||||||
|
type: Array<any>,
|
||||||
|
default: undefined,
|
||||||
|
},
|
||||||
// 获取树数据的URL
|
// 获取树数据的URL
|
||||||
dataUrl: {
|
dataUrl: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
default: '',
|
||||||
},
|
},
|
||||||
// 已选择的节点数组(支持双向绑定)
|
// 已选择的节点数组(支持双向绑定)
|
||||||
modelValue: {
|
modelValue: {
|
||||||
@@ -47,6 +52,10 @@ const props = defineProps({
|
|||||||
type: Number,
|
type: Number,
|
||||||
default: 200,
|
default: 200,
|
||||||
},
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
// 是否显示子节点数量
|
// 是否显示子节点数量
|
||||||
showCount: {
|
showCount: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
@@ -117,27 +126,38 @@ const buildNodeMap = (nodes: any) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function applyTreeData(data: any[]) {
|
||||||
|
treeData.value = Array.isArray(data) ? data : [];
|
||||||
|
nodeMap.value.clear();
|
||||||
|
buildNodeMap(treeData.value);
|
||||||
|
|
||||||
|
if (props.modelValue && props.modelValue.length > 0) {
|
||||||
|
nextTick(() => {
|
||||||
|
if (treeRef.value) {
|
||||||
|
treeRef.value.setCheckedKeys(props.modelValue);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.data,
|
||||||
|
(newData) => {
|
||||||
|
if (newData !== undefined) {
|
||||||
|
applyTreeData(newData || []);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true, deep: true },
|
||||||
|
);
|
||||||
|
|
||||||
// 获取树数据
|
// 获取树数据
|
||||||
const fetchTreeData = async () => {
|
const fetchTreeData = async () => {
|
||||||
if (!props.dataUrl) return;
|
if (props.data !== undefined || !props.dataUrl) return;
|
||||||
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
const res = await api.get(props.dataUrl);
|
const res = await api.get(props.dataUrl);
|
||||||
|
applyTreeData(res.data);
|
||||||
treeData.value = res.data;
|
|
||||||
// 构建节点映射
|
|
||||||
nodeMap.value.clear();
|
|
||||||
buildNodeMap(res.data);
|
|
||||||
|
|
||||||
// 数据加载完成后,如果有选中值则设置
|
|
||||||
if (props.modelValue && props.modelValue.length > 0) {
|
|
||||||
nextTick(() => {
|
|
||||||
if (treeRef.value) {
|
|
||||||
treeRef.value.setCheckedKeys(props.modelValue);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('get data error:', error);
|
console.error('get data error:', error);
|
||||||
ElMessage.error($t('message.getDataError'));
|
ElMessage.error($t('message.getDataError'));
|
||||||
@@ -189,13 +209,14 @@ defineExpose({
|
|||||||
|
|
||||||
// 组件挂载时获取数据
|
// 组件挂载时获取数据
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchTreeData();
|
if (props.data === undefined) {
|
||||||
|
fetchTreeData();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="tree-select">
|
<div class="tree-select" :class="{ 'tree-select--disabled': disabled }">
|
||||||
<div class="tree-header"></div>
|
|
||||||
<div class="tree-wrapper">
|
<div class="tree-wrapper">
|
||||||
<ElTreeV2
|
<ElTreeV2
|
||||||
ref="treeRef"
|
ref="treeRef"
|
||||||
@@ -231,32 +252,129 @@ onMounted(() => {
|
|||||||
<style scoped>
|
<style scoped>
|
||||||
.tree-select {
|
.tree-select {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: #fff;
|
overflow: hidden;
|
||||||
border: 1px solid #e4e7ed;
|
background:
|
||||||
border-radius: 6px;
|
linear-gradient(
|
||||||
}
|
180deg,
|
||||||
|
color-mix(in srgb, var(--el-color-primary-light-9) 32%, var(--el-bg-color)) 0%,
|
||||||
.tree-header {
|
var(--el-bg-color) 72%
|
||||||
display: flex;
|
);
|
||||||
align-items: center;
|
border: 1px solid var(--el-border-color-lighter);
|
||||||
justify-content: space-between;
|
border-radius: 14px;
|
||||||
padding: 12px 16px;
|
box-shadow: var(--el-box-shadow-lighter);
|
||||||
background-color: #f8f9fa;
|
|
||||||
border-bottom: 1px solid #e4e7ed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tree-wrapper {
|
.tree-wrapper {
|
||||||
padding: 8px;
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-select--disabled {
|
||||||
|
background:
|
||||||
|
linear-gradient(
|
||||||
|
180deg,
|
||||||
|
var(--el-fill-color-extra-light) 0%,
|
||||||
|
var(--el-fill-color-blank) 72%
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tree-node {
|
.tree-node {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.node-label {
|
||||||
|
overflow: hidden;
|
||||||
|
color: var(--el-text-color-primary);
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.node-count {
|
.node-count {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-width: 22px;
|
||||||
|
height: 20px;
|
||||||
|
padding: 0 6px;
|
||||||
|
color: var(--el-text-color-secondary);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #909399;
|
line-height: 1;
|
||||||
|
background: var(--el-fill-color);
|
||||||
|
border-radius: 999px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-tree) {
|
||||||
|
background: transparent;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-tree-node__content) {
|
||||||
|
height: 38px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
padding: 0 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
transition:
|
||||||
|
background-color 0.18s ease,
|
||||||
|
color 0.18s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-tree-node__content:hover) {
|
||||||
|
background: var(--el-fill-color-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-tree-node:focus > .el-tree-node__content) {
|
||||||
|
background: var(--el-color-primary-light-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-tree-node.is-current > .el-tree-node__content) {
|
||||||
|
background: color-mix(
|
||||||
|
in srgb,
|
||||||
|
var(--el-color-primary-light-8) 70%,
|
||||||
|
var(--el-bg-color)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-tree-node__expand-icon) {
|
||||||
|
color: var(--el-text-color-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-checkbox) {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-tree-node__children) {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-tree-node__children .el-tree-node__content) {
|
||||||
|
padding-left: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-scrollbar__bar.is-vertical) {
|
||||||
|
width: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-scrollbar__thumb) {
|
||||||
|
background: color-mix(
|
||||||
|
in srgb,
|
||||||
|
var(--el-text-color-secondary) 22%,
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
border-radius: 999px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-select--disabled :deep(.el-tree-node__content) {
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.72;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-select--disabled :deep(.el-checkbox),
|
||||||
|
.tree-select--disabled :deep(.el-tree-node__expand-icon),
|
||||||
|
.tree-select--disabled :deep(.el-tree-node__content) {
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -12,6 +12,11 @@
|
|||||||
"isDeleted": "IsDeleted",
|
"isDeleted": "IsDeleted",
|
||||||
"menuPermission": "MenuPermission",
|
"menuPermission": "MenuPermission",
|
||||||
"dataPermission": "DataPermission",
|
"dataPermission": "DataPermission",
|
||||||
|
"categoryPermission": "CategoryPermission",
|
||||||
|
"categoryPermissionHint": "Deny by default. Applies to resource visibility and selectors/binders only.",
|
||||||
|
"categoryScopeAll": "AllCategories",
|
||||||
|
"categoryScopeCustom": "CustomCategories",
|
||||||
|
"categoryScopePlaceholder": "Select categories",
|
||||||
"checkStrictlyTrue": "Linked",
|
"checkStrictlyTrue": "Linked",
|
||||||
"checkStrictlyFalse": "NotLinked"
|
"checkStrictlyFalse": "NotLinked"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,11 @@
|
|||||||
"isDeleted": "删除标识",
|
"isDeleted": "删除标识",
|
||||||
"menuPermission": "菜单权限",
|
"menuPermission": "菜单权限",
|
||||||
"dataPermission": "数据权限",
|
"dataPermission": "数据权限",
|
||||||
|
"categoryPermission": "分类权限",
|
||||||
|
"categoryPermissionHint": "未配置即拒绝,仅控制资源可见性与选择器/绑定器。",
|
||||||
|
"categoryScopeAll": "全部分类",
|
||||||
|
"categoryScopeCustom": "自定义分类",
|
||||||
|
"categoryScopePlaceholder": "请选择分类",
|
||||||
"checkStrictlyTrue": "联动",
|
"checkStrictlyTrue": "联动",
|
||||||
"checkStrictlyFalse": "不联动"
|
"checkStrictlyFalse": "不联动"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -257,7 +257,7 @@ function handleSubmit() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
const getSideList = async () => {
|
const getSideList = async () => {
|
||||||
const [, res] = await tryit(api.get)('/api/v1/botCategory/list', {
|
const [, res] = await tryit(api.get)('/api/v1/botCategory/visibleList', {
|
||||||
params: { sortKey: 'sortNo', sortType: 'asc' },
|
params: { sortKey: 'sortNo', sortType: 'asc' },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -41,10 +41,10 @@ const authTypeList = ref<headersType[]>([
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
api.get('/api/v1/model/list?supportEmbed=true').then((res) => {
|
api.get('/api/v1/plugin/modelList?supportEmbed=true').then((res) => {
|
||||||
embeddingLlmList.value = res.data;
|
embeddingLlmList.value = res.data;
|
||||||
});
|
});
|
||||||
api.get('/api/v1/model/list?supportRerankerLlmList=true').then((res) => {
|
api.get('/api/v1/plugin/modelList?supportRerankerLlmList=true').then((res) => {
|
||||||
rerankerLlmList.value = res.data;
|
rerankerLlmList.value = res.data;
|
||||||
});
|
});
|
||||||
api.get('/api/v1/pluginCategory/list').then((res) => {
|
api.get('/api/v1/pluginCategory/list').then((res) => {
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ const footerButton = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
const getPluginCategoryList = async () => {
|
const getPluginCategoryList = async () => {
|
||||||
return api.get('/api/v1/pluginCategory/list').then((res) => {
|
return api.get('/api/v1/pluginCategory/visibleList').then((res) => {
|
||||||
if (res.errorCode === 0) {
|
if (res.errorCode === 0) {
|
||||||
const serverCategories = Array.isArray(res.data)
|
const serverCategories = Array.isArray(res.data)
|
||||||
? (res.data as PluginCategory[])
|
? (res.data as PluginCategory[])
|
||||||
|
|||||||
@@ -230,7 +230,7 @@ function handleSideSubmit() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
const getSideList = async () => {
|
const getSideList = async () => {
|
||||||
const [, res] = await tryit(api.get)('/api/v1/resourceCategory/list', {
|
const [, res] = await tryit(api.get)('/api/v1/resourceCategory/visibleList', {
|
||||||
params: { sortKey: 'sortNo', sortType: 'asc' },
|
params: { sortKey: 'sortNo', sortType: 'asc' },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { FormInstance } from 'element-plus';
|
import type { FormInstance } from 'element-plus';
|
||||||
|
|
||||||
import { onMounted, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
|
|
||||||
import { EasyFlowFormModal } from '@easyflow/common-ui';
|
import { EasyFlowFormModal } from '@easyflow/common-ui';
|
||||||
|
|
||||||
import { ElForm, ElFormItem, ElInput, ElMessage, ElSwitch } from 'element-plus';
|
import {
|
||||||
|
ElForm,
|
||||||
|
ElFormItem,
|
||||||
|
ElInput,
|
||||||
|
ElMessage,
|
||||||
|
} from 'element-plus';
|
||||||
|
|
||||||
import { api } from '#/api/request';
|
import { api } from '#/api/request';
|
||||||
import DictSelect from '#/components/dict/DictSelect.vue';
|
import DictSelect from '#/components/dict/DictSelect.vue';
|
||||||
@@ -13,20 +18,57 @@ import Tree from '#/components/tree/Tree.vue';
|
|||||||
import { $t } from '#/locales';
|
import { $t } from '#/locales';
|
||||||
|
|
||||||
const emit = defineEmits(['reload']);
|
const emit = defineEmits(['reload']);
|
||||||
// vue
|
|
||||||
onMounted(() => {});
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
openDialog,
|
openDialog,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
type ResourceType = 'BOT' | 'KNOWLEDGE' | 'PLUGIN' | 'RESOURCE' | 'WORKFLOW';
|
||||||
|
|
||||||
|
interface CategoryScopeItem {
|
||||||
|
categoryIds: Array<number | string>;
|
||||||
|
resourceType: ResourceType;
|
||||||
|
scopeMode: 'ALL' | 'CUSTOM';
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CategoryOption {
|
||||||
|
id: number | string;
|
||||||
|
label: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CategoryPermissionTreeNode {
|
||||||
|
children?: CategoryPermissionTreeNode[];
|
||||||
|
id: string;
|
||||||
|
label: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RESOURCE_SCOPE_GROUPS: Array<{ label: string; resourceType: ResourceType }> =
|
||||||
|
[
|
||||||
|
{ resourceType: 'BOT', label: $t('bot.chatAssistant') },
|
||||||
|
{ resourceType: 'PLUGIN', label: $t('menus.ai.plugin') },
|
||||||
|
{ resourceType: 'WORKFLOW', label: $t('menus.ai.workflow') },
|
||||||
|
{ resourceType: 'KNOWLEDGE', label: $t('menus.ai.documentCollection') },
|
||||||
|
{ resourceType: 'RESOURCE', label: $t('menus.ai.resources') },
|
||||||
|
];
|
||||||
|
|
||||||
const saveForm = ref<FormInstance>();
|
const saveForm = ref<FormInstance>();
|
||||||
// variables
|
|
||||||
const dialogVisible = ref(false);
|
const dialogVisible = ref(false);
|
||||||
const isAdd = ref(true);
|
const isAdd = ref(true);
|
||||||
const entity = ref<any>({
|
const entity = ref<any>(buildDefaultEntity());
|
||||||
roleName: '',
|
const categoryScopeLoaded = ref(false);
|
||||||
roleKey: '',
|
const categoryScopeEditable = ref(false);
|
||||||
status: '',
|
const categoryOptions = ref<Record<ResourceType, CategoryOption[]>>({
|
||||||
remark: '',
|
BOT: [],
|
||||||
|
KNOWLEDGE: [],
|
||||||
|
PLUGIN: [],
|
||||||
|
RESOURCE: [],
|
||||||
|
WORKFLOW: [],
|
||||||
|
});
|
||||||
|
const categoryTreeCheckedKeys = ref<string[]>([]);
|
||||||
|
const categoryScopeDetail = ref<{
|
||||||
|
roleId?: number | string;
|
||||||
|
scopes: CategoryScopeItem[];
|
||||||
|
}>({
|
||||||
|
scopes: buildDefaultScopes(),
|
||||||
});
|
});
|
||||||
const btnLoading = ref(false);
|
const btnLoading = ref(false);
|
||||||
const rules = ref({
|
const rules = ref({
|
||||||
@@ -40,50 +82,229 @@ const rules = ref({
|
|||||||
{ required: true, message: $t('message.required'), trigger: 'blur' },
|
{ required: true, message: $t('message.required'), trigger: 'blur' },
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
// functions
|
const categoryPermissionTreeData = computed<CategoryPermissionTreeNode[]>(() =>
|
||||||
function openDialog(row: any) {
|
RESOURCE_SCOPE_GROUPS.map(({ label, resourceType }) => ({
|
||||||
|
id: buildGroupNodeKey(resourceType),
|
||||||
|
label,
|
||||||
|
children: categoryOptions.value[resourceType].map((option) => ({
|
||||||
|
id: buildCategoryNodeKey(resourceType, option.id),
|
||||||
|
label: option.label,
|
||||||
|
})),
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
|
||||||
|
function buildDefaultEntity() {
|
||||||
|
return {
|
||||||
|
menuCheckStrictly: true,
|
||||||
|
menuIds: [],
|
||||||
|
remark: '',
|
||||||
|
roleKey: '',
|
||||||
|
roleName: '',
|
||||||
|
status: '',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildDefaultScopes(): CategoryScopeItem[] {
|
||||||
|
return RESOURCE_SCOPE_GROUPS.map(({ resourceType }) => ({
|
||||||
|
categoryIds: [],
|
||||||
|
resourceType,
|
||||||
|
scopeMode: 'CUSTOM',
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function openDialog(row: any = {}) {
|
||||||
|
entity.value = {
|
||||||
|
...buildDefaultEntity(),
|
||||||
|
...row,
|
||||||
|
menuCheckStrictly: true,
|
||||||
|
};
|
||||||
|
categoryScopeDetail.value = {
|
||||||
|
roleId: row.id,
|
||||||
|
scopes: buildDefaultScopes(),
|
||||||
|
};
|
||||||
|
categoryScopeEditable.value = false;
|
||||||
|
syncCategoryTreeCheckedKeys(buildDefaultScopes());
|
||||||
|
|
||||||
if (row.id) {
|
if (row.id) {
|
||||||
isAdd.value = false;
|
isAdd.value = false;
|
||||||
getMenuIds(row.id);
|
getMenuIds(row.id);
|
||||||
getDeptIds(row.id);
|
|
||||||
}
|
}
|
||||||
entity.value = row;
|
getCategoryScopeDetail(row.id);
|
||||||
|
void ensureCategoryOptions();
|
||||||
dialogVisible.value = true;
|
dialogVisible.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function save() {
|
function save() {
|
||||||
saveForm.value?.validate((valid) => {
|
saveForm.value?.validate(async (valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
btnLoading.value = true;
|
btnLoading.value = true;
|
||||||
api
|
try {
|
||||||
.post('/api/v1/sysRole/saveRole', entity.value)
|
const res = await api.post('/api/v1/sysRole/saveRole', {
|
||||||
.then((res) => {
|
...entity.value,
|
||||||
btnLoading.value = false;
|
menuCheckStrictly: true,
|
||||||
if (res.errorCode === 0) {
|
|
||||||
ElMessage.success(res.message);
|
|
||||||
emit('reload');
|
|
||||||
closeDialog();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
btnLoading.value = false;
|
|
||||||
});
|
});
|
||||||
|
if (res.errorCode !== 0) {
|
||||||
|
btnLoading.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const roleId = res.data || entity.value.id;
|
||||||
|
if (roleId && categoryScopeEditable.value) {
|
||||||
|
const scopeRes = await saveCategoryScope(roleId);
|
||||||
|
if (scopeRes.errorCode !== 0) {
|
||||||
|
btnLoading.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
btnLoading.value = false;
|
||||||
|
ElMessage.success(res.message);
|
||||||
|
emit('reload');
|
||||||
|
closeDialog();
|
||||||
|
} catch {
|
||||||
|
btnLoading.value = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeDialog() {
|
function closeDialog() {
|
||||||
saveForm.value?.resetFields();
|
saveForm.value?.resetFields();
|
||||||
isAdd.value = true;
|
isAdd.value = true;
|
||||||
entity.value = {};
|
entity.value = buildDefaultEntity();
|
||||||
|
categoryScopeDetail.value = {
|
||||||
|
scopes: buildDefaultScopes(),
|
||||||
|
};
|
||||||
|
categoryScopeEditable.value = false;
|
||||||
|
syncCategoryTreeCheckedKeys(buildDefaultScopes());
|
||||||
dialogVisible.value = false;
|
dialogVisible.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMenuIds(roleId: any) {
|
function getMenuIds(roleId: any) {
|
||||||
api.get(`/api/v1/sysRole/getRoleMenuIds?roleId=${roleId}`).then((res) => {
|
api.get(`/api/v1/sysRole/getRoleMenuIds?roleId=${roleId}`).then((res) => {
|
||||||
entity.value.menuIds = res.data;
|
entity.value.menuIds = res.data;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function getDeptIds(roleId: any) {
|
|
||||||
api.get(`/api/v1/sysRole/getRoleDeptIds?roleId=${roleId}`).then((res) => {
|
async function ensureCategoryOptions() {
|
||||||
entity.value.deptIds = res.data;
|
if (categoryScopeLoaded.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const requests = [
|
||||||
|
api.get('/api/v1/botCategory/list', {
|
||||||
|
params: { sortKey: 'sortNo', sortType: 'asc' },
|
||||||
|
}),
|
||||||
|
api.get('/api/v1/pluginCategory/list'),
|
||||||
|
api.get('/api/v1/workflowCategory/list', {
|
||||||
|
params: { sortKey: 'sortNo', sortType: 'asc' },
|
||||||
|
}),
|
||||||
|
api.get('/api/v1/documentCollectionCategory/list', {
|
||||||
|
params: { sortKey: 'sortNo', sortType: 'asc' },
|
||||||
|
}),
|
||||||
|
api.get('/api/v1/resourceCategory/list', {
|
||||||
|
params: { sortKey: 'sortNo', sortType: 'asc' },
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
const [botRes, pluginRes, workflowRes, knowledgeRes, resourceRes] =
|
||||||
|
await Promise.all(requests);
|
||||||
|
categoryOptions.value = {
|
||||||
|
BOT: normalizeCategoryOptions(botRes.data, 'categoryName'),
|
||||||
|
KNOWLEDGE: normalizeCategoryOptions(knowledgeRes.data, 'categoryName'),
|
||||||
|
PLUGIN: normalizeCategoryOptions(pluginRes.data, 'name'),
|
||||||
|
RESOURCE: normalizeCategoryOptions(resourceRes.data, 'categoryName'),
|
||||||
|
WORKFLOW: normalizeCategoryOptions(workflowRes.data, 'categoryName'),
|
||||||
|
};
|
||||||
|
categoryScopeLoaded.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeCategoryOptions(data: any[] = [], labelKey: string) {
|
||||||
|
return (Array.isArray(data) ? data : []).map((item) => ({
|
||||||
|
id: item.id,
|
||||||
|
label: item[labelKey],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildGroupNodeKey(resourceType: ResourceType) {
|
||||||
|
return `group:${resourceType}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildCategoryNodeKey(
|
||||||
|
resourceType: ResourceType,
|
||||||
|
categoryId: number | string,
|
||||||
|
) {
|
||||||
|
return `category:${resourceType}:${String(categoryId)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncCategoryTreeCheckedKeys(scopes: CategoryScopeItem[]) {
|
||||||
|
categoryTreeCheckedKeys.value = scopes.flatMap((scope) => {
|
||||||
|
if (scope.scopeMode === 'ALL') {
|
||||||
|
return [buildGroupNodeKey(scope.resourceType)];
|
||||||
|
}
|
||||||
|
return scope.categoryIds.map((categoryId) =>
|
||||||
|
buildCategoryNodeKey(scope.resourceType, categoryId),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildScopeItemsFromTree(): CategoryScopeItem[] {
|
||||||
|
const checkedKeySet = new Set(categoryTreeCheckedKeys.value);
|
||||||
|
return RESOURCE_SCOPE_GROUPS.map(({ resourceType }) => {
|
||||||
|
const groupNodeKey = buildGroupNodeKey(resourceType);
|
||||||
|
const grantedCategoryIds = categoryOptions.value[resourceType]
|
||||||
|
.filter((option) =>
|
||||||
|
checkedKeySet.has(buildCategoryNodeKey(resourceType, option.id)),
|
||||||
|
)
|
||||||
|
.map((option) => option.id);
|
||||||
|
const allCategoriesSelected =
|
||||||
|
categoryOptions.value[resourceType].length > 0 &&
|
||||||
|
grantedCategoryIds.length === categoryOptions.value[resourceType].length;
|
||||||
|
const scopeMode: CategoryScopeItem['scopeMode'] =
|
||||||
|
checkedKeySet.has(groupNodeKey) || allCategoriesSelected
|
||||||
|
? 'ALL'
|
||||||
|
: 'CUSTOM';
|
||||||
|
return {
|
||||||
|
categoryIds: scopeMode === 'ALL' ? [] : grantedCategoryIds,
|
||||||
|
resourceType,
|
||||||
|
scopeMode,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCategoryScopeDetail(roleId: number | string) {
|
||||||
|
api.get('/api/v1/sysRoleCategoryScope/detail', {
|
||||||
|
params: { roleId },
|
||||||
|
}).then((res) => {
|
||||||
|
if (res.errorCode !== 0) {
|
||||||
|
categoryScopeEditable.value = false;
|
||||||
|
categoryScopeDetail.value = {
|
||||||
|
roleId,
|
||||||
|
scopes: buildDefaultScopes(),
|
||||||
|
};
|
||||||
|
syncCategoryTreeCheckedKeys(categoryScopeDetail.value.scopes);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
categoryScopeEditable.value = !!res.data?.editable;
|
||||||
|
categoryScopeDetail.value = {
|
||||||
|
roleId,
|
||||||
|
scopes: (res.data?.scopes || buildDefaultScopes()).map((item: any) => ({
|
||||||
|
categoryIds: item.categoryIds || [],
|
||||||
|
resourceType: item.resourceType,
|
||||||
|
scopeMode: item.scopeMode || 'CUSTOM',
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
syncCategoryTreeCheckedKeys(categoryScopeDetail.value.scopes);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveCategoryScope(roleId: number | string) {
|
||||||
|
await ensureCategoryOptions();
|
||||||
|
const scopes = buildScopeItemsFromTree();
|
||||||
|
categoryScopeDetail.value = {
|
||||||
|
roleId,
|
||||||
|
scopes,
|
||||||
|
};
|
||||||
|
return api.post('/api/v1/sysRoleCategoryScope/save', {
|
||||||
|
roleId,
|
||||||
|
scopes,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -120,11 +341,6 @@ function getDeptIds(roleId: any) {
|
|||||||
<ElInput v-model.trim="entity.remark" />
|
<ElInput v-model.trim="entity.remark" />
|
||||||
</ElFormItem>
|
</ElFormItem>
|
||||||
<ElFormItem :label="$t('sysRole.menuPermission')">
|
<ElFormItem :label="$t('sysRole.menuPermission')">
|
||||||
<ElSwitch
|
|
||||||
v-model="entity.menuCheckStrictly"
|
|
||||||
:active-text="$t('sysRole.checkStrictlyTrue')"
|
|
||||||
:inactive-text="$t('sysRole.checkStrictlyFalse')"
|
|
||||||
/>
|
|
||||||
<Tree
|
<Tree
|
||||||
data-url="/api/v1/sysMenu/list?asTree=true"
|
data-url="/api/v1/sysMenu/list?asTree=true"
|
||||||
v-model="entity.menuIds"
|
v-model="entity.menuIds"
|
||||||
@@ -132,25 +348,23 @@ function getDeptIds(roleId: any) {
|
|||||||
label: 'menuTitle',
|
label: 'menuTitle',
|
||||||
children: 'children',
|
children: 'children',
|
||||||
}"
|
}"
|
||||||
:check-strictly="!entity.menuCheckStrictly"
|
:check-strictly="false"
|
||||||
/>
|
/>
|
||||||
</ElFormItem>
|
</ElFormItem>
|
||||||
<ElFormItem :label="$t('sysRole.dataPermission')">
|
<ElFormItem :label="$t('sysRole.categoryPermission')">
|
||||||
<DictSelect v-model="entity.dataScope" dict-code="dataScope" />
|
<div class="role-category-scope-panel">
|
||||||
<div v-if="entity.dataScope === 5" style="width: 100%">
|
|
||||||
<ElSwitch
|
|
||||||
v-model="entity.deptCheckStrictly"
|
|
||||||
:active-text="$t('sysRole.checkStrictlyTrue')"
|
|
||||||
:inactive-text="$t('sysRole.checkStrictlyFalse')"
|
|
||||||
/>
|
|
||||||
<Tree
|
<Tree
|
||||||
data-url="/api/v1/sysDept/list?asTree=true"
|
:data="categoryPermissionTreeData"
|
||||||
v-model="entity.deptIds"
|
v-model="categoryTreeCheckedKeys"
|
||||||
:default-props="{
|
:default-props="{
|
||||||
label: 'deptName',
|
label: 'label',
|
||||||
children: 'children',
|
children: 'children',
|
||||||
}"
|
}"
|
||||||
:check-strictly="!entity.deptCheckStrictly"
|
node-key="id"
|
||||||
|
:default-expand-all="true"
|
||||||
|
:check-strictly="false"
|
||||||
|
:height="280"
|
||||||
|
:disabled="!categoryScopeEditable"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</ElFormItem>
|
</ElFormItem>
|
||||||
@@ -158,4 +372,34 @@ function getDeptIds(roleId: any) {
|
|||||||
</EasyFlowFormModal>
|
</EasyFlowFormModal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped>
|
||||||
|
.role-category-scope-panel {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.role-category-scope-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 12px;
|
||||||
|
border: 1px solid var(--el-border-color-lighter);
|
||||||
|
border-radius: 10px;
|
||||||
|
background: var(--el-fill-color-extra-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.role-category-scope-head {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.role-category-scope-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--el-text-color-primary);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ onMounted(async () => {
|
|||||||
getUserUsed();
|
getUserUsed();
|
||||||
});
|
});
|
||||||
function getCategoryList() {
|
function getCategoryList() {
|
||||||
api.get('/userCenter/botCategory/list').then((res) => {
|
api.get('/userCenter/botCategory/visibleList').then((res) => {
|
||||||
categories.value = [
|
categories.value = [
|
||||||
{
|
{
|
||||||
id: '',
|
id: '',
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ onMounted(async () => {
|
|||||||
getCategoryList();
|
getCategoryList();
|
||||||
});
|
});
|
||||||
function getCategoryList() {
|
function getCategoryList() {
|
||||||
api.get('/userCenter/workflowCategory/list').then((res) => {
|
api.get('/userCenter/workflowCategory/visibleList').then((res) => {
|
||||||
categories.value = [
|
categories.value = [
|
||||||
{
|
{
|
||||||
id: '',
|
id: '',
|
||||||
|
|||||||
Reference in New Issue
Block a user