Browse Source
- 新增 FormButtonPermissionChecker 接口定义按钮权限检查器 - 实现 FormButtonPermissionCheckerImpl 提供按钮权限校验逻辑 - 创建 RoleFormButton 实体映射角色表单按钮权限配置表 - 定义 IRoleFormButtonService 接口及 RoleFormButtonServiceImpl 实现类 - 添加 RoleFormButtonController 控制器提供按钮权限配置接口 - 创建 RoleFormButtonDto 数据传输对象用于按钮权限配置 - 实现 RoleFormButtonMapper 数据访问层及对应的 XML 映射文件 - 开发 WidgetJsonButtonParser 工具类解析表单中的按钮配置 - 提供 VO 对象 RoleFormButtonVo 用于数据展示 - 实现批量保存和查询按钮权限配置的功能 - 添加按角色 ID 查询和删除相关权限配置的方法feature/form-permission-control
11 changed files with 718 additions and 0 deletions
@ -0,0 +1,105 @@ |
|||||||
|
package apelet.tenantadmin.tenant.controller; |
||||||
|
|
||||||
|
import apelet.common.core.annotation.MyRequestBody; |
||||||
|
import apelet.common.core.constant.ErrorCodeEnum; |
||||||
|
import apelet.common.core.object.*; |
||||||
|
import apelet.common.core.util.MyCommonUtil; |
||||||
|
import apelet.common.core.util.MyPageUtil; |
||||||
|
import apelet.common.log.annotation.OperationLog; |
||||||
|
import apelet.common.log.model.constant.SysOperationLogType; |
||||||
|
import apelet.tenantadmin.tenant.dto.RoleFormButtonDto; |
||||||
|
import apelet.tenantadmin.tenant.model.RoleFormButton; |
||||||
|
import apelet.tenantadmin.tenant.service.IRoleFormButtonService; |
||||||
|
import com.github.pagehelper.page.PageMethod; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.web.bind.annotation.*; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
/** |
||||||
|
* 角色-表单按钮权限控制器。 |
||||||
|
* |
||||||
|
* @author chenchuchuan |
||||||
|
* @date 2026-07-17 |
||||||
|
*/ |
||||||
|
@RestController |
||||||
|
@RequestMapping("/tenantadmin/tenant/roleFormButton") |
||||||
|
public class RoleFormButtonController { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private IRoleFormButtonService service; |
||||||
|
|
||||||
|
/** |
||||||
|
* 查询指定角色+表单的按钮权限配置。 |
||||||
|
* 返回表单中所有开启的按钮 + 每个按钮是否已勾选。 |
||||||
|
* |
||||||
|
* @param roleId 角色ID(必填)。 |
||||||
|
* @param formId 在线表单ID(必填)。 |
||||||
|
* @return 包含 formId, roleId, id, buttonList[{name, checked}]。 |
||||||
|
*/ |
||||||
|
@GetMapping("/getButtonConfig") |
||||||
|
public ResponseResult<Map<String, Object>> getButtonConfig( |
||||||
|
@RequestParam Long roleId, |
||||||
|
@RequestParam Long formId) { |
||||||
|
if (MyCommonUtil.existBlankArgument(roleId, formId)) { |
||||||
|
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); |
||||||
|
} |
||||||
|
Map<String, Object> result = service.getButtonConfigVo(roleId, formId); |
||||||
|
return ResponseResult.success(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 批量保存角色+表单的按钮权限配置(新增或更新)。 |
||||||
|
* |
||||||
|
* @param dtoList 列表,每个元素包含 roleId(必填), formId(必填), id(编辑时传), buttonList。 |
||||||
|
* @return 应答结果。 |
||||||
|
*/ |
||||||
|
@OperationLog(type = SysOperationLogType.ADD) |
||||||
|
@PostMapping("/saveButtonConfig") |
||||||
|
public ResponseResult<Void> saveButtonConfig( |
||||||
|
@MyRequestBody List<RoleFormButtonDto> dtoList) { |
||||||
|
if (dtoList == null || dtoList.isEmpty()) { |
||||||
|
return ResponseResult.error( |
||||||
|
ErrorCodeEnum.ARGUMENT_NULL_EXIST, "数据验证失败,按钮配置列表不能为空!"); |
||||||
|
} |
||||||
|
CallResult result = service.batchSaveButtonConfig(dtoList); |
||||||
|
if (!result.isSuccess()) { |
||||||
|
return ResponseResult.error( |
||||||
|
ErrorCodeEnum.DATA_VALIDATED_FAILED, result.getErrorMessage()); |
||||||
|
} |
||||||
|
return ResponseResult.success(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 根据角色ID查询该角色下所有绑定的按钮权限配置列表。 |
||||||
|
* |
||||||
|
* @param roleId 角色ID。 |
||||||
|
* @return 按钮权限配置列表。 |
||||||
|
*/ |
||||||
|
@GetMapping("/listByRoleId") |
||||||
|
public ResponseResult<List<RoleFormButton>> listByRoleId( |
||||||
|
@RequestParam Long roleId) { |
||||||
|
if (MyCommonUtil.existBlankArgument(roleId)) { |
||||||
|
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); |
||||||
|
} |
||||||
|
return ResponseResult.success(service.listByRoleId(roleId)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 分页查询按钮权限配置列表。 |
||||||
|
*/ |
||||||
|
@PostMapping("/list") |
||||||
|
public ResponseResult<MyPageData<?>> list( |
||||||
|
@MyRequestBody RoleFormButton filter, |
||||||
|
@MyRequestBody MyOrderParam orderParam, |
||||||
|
@MyRequestBody MyPageParam pageParam) { |
||||||
|
if (pageParam != null) { |
||||||
|
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); |
||||||
|
} |
||||||
|
List<RoleFormButton> list = service.getListByFilter( |
||||||
|
filter, MyOrderParam.buildOrderBy(orderParam, RoleFormButton.class)); |
||||||
|
return ResponseResult.success( |
||||||
|
MyPageUtil.makeResponseData(list, RoleFormButton.INSTANCE)); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,23 @@ |
|||||||
|
package apelet.tenantadmin.tenant.dao; |
||||||
|
|
||||||
|
import apelet.common.core.base.dao.BaseDaoMapper; |
||||||
|
import apelet.tenantadmin.tenant.model.RoleFormButton; |
||||||
|
import org.apache.ibatis.annotations.Param; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* 角色-表单按钮权限配置数据访问操作接口。 |
||||||
|
* |
||||||
|
* @author chenchuchuan |
||||||
|
* @date 2026-07-17 |
||||||
|
*/ |
||||||
|
public interface RoleFormButtonMapper extends BaseDaoMapper<RoleFormButton> { |
||||||
|
|
||||||
|
/** |
||||||
|
* 分页条件查询。 |
||||||
|
*/ |
||||||
|
List<RoleFormButton> getListByFilter( |
||||||
|
@Param("filter") RoleFormButton filter, |
||||||
|
@Param("orderBy") String orderBy); |
||||||
|
} |
||||||
@ -0,0 +1,21 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
||||||
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||||
|
<mapper namespace="apelet.tenantadmin.tenant.dao.RoleFormButtonMapper"> |
||||||
|
|
||||||
|
<select id="getListByFilter" |
||||||
|
resultType="apelet.tenantadmin.tenant.model.RoleFormButton"> |
||||||
|
SELECT * FROM xy_sys_role_form_button |
||||||
|
WHERE 1=1 |
||||||
|
<if test="filter.roleId != null"> |
||||||
|
AND role_id = #{filter.roleId} |
||||||
|
</if> |
||||||
|
<if test="filter.formId != null"> |
||||||
|
AND form_id = #{filter.formId} |
||||||
|
</if> |
||||||
|
<if test="orderBy != null and orderBy != ''"> |
||||||
|
ORDER BY ${orderBy} |
||||||
|
</if> |
||||||
|
</select> |
||||||
|
|
||||||
|
</mapper> |
||||||
@ -0,0 +1,35 @@ |
|||||||
|
package apelet.tenantadmin.tenant.dto; |
||||||
|
|
||||||
|
import lombok.Data; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* 角色表单按钮权限保存入参。 |
||||||
|
* |
||||||
|
* @author chenchuchuan |
||||||
|
* @date 2026-07-17 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
public class RoleFormButtonDto { |
||||||
|
|
||||||
|
/** 角色ID(必填) */ |
||||||
|
private Long roleId; |
||||||
|
|
||||||
|
/** 表单ID(必填) */ |
||||||
|
private Long formId; |
||||||
|
|
||||||
|
/** 主键ID(编辑时传,新增时不传) */ |
||||||
|
private Long id; |
||||||
|
|
||||||
|
/** 按钮勾选列表 */ |
||||||
|
private List<ButtonItem> buttonList; |
||||||
|
|
||||||
|
@Data |
||||||
|
public static class ButtonItem { |
||||||
|
/** 按钮名称 */ |
||||||
|
private String name; |
||||||
|
/** 是否勾选 */ |
||||||
|
private Boolean checked; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,69 @@ |
|||||||
|
package apelet.tenantadmin.tenant.model; |
||||||
|
|
||||||
|
import apelet.common.core.base.mapper.BaseModelMapper; |
||||||
|
import apelet.common.core.base.model.BaseModel; |
||||||
|
import apelet.common.core.validator.UpdateGroup; |
||||||
|
import apelet.tenantadmin.tenant.vo.RoleFormButtonVo; |
||||||
|
import com.baomidou.mybatisplus.annotation.TableField; |
||||||
|
import com.baomidou.mybatisplus.annotation.TableId; |
||||||
|
import com.baomidou.mybatisplus.annotation.TableName; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.EqualsAndHashCode; |
||||||
|
import org.mapstruct.Mapper; |
||||||
|
import org.mapstruct.factory.Mappers; |
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull; |
||||||
|
import java.io.Serializable; |
||||||
|
import java.util.Date; |
||||||
|
|
||||||
|
/** |
||||||
|
* 角色-表单按钮权限配置实体对象。 |
||||||
|
* |
||||||
|
* @author chenchuchuan |
||||||
|
* @date 2026-07-17 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
@EqualsAndHashCode(callSuper = true) |
||||||
|
@TableName("xy_sys_role_form_button") |
||||||
|
public class RoleFormButton extends BaseModel implements Serializable { |
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L; |
||||||
|
|
||||||
|
@TableId(value = "id") |
||||||
|
@NotNull(message = "数据验证失败,id不能为空!", groups = {UpdateGroup.class}) |
||||||
|
private Long id; |
||||||
|
|
||||||
|
/** 角色ID */ |
||||||
|
@TableField(value = "role_id") |
||||||
|
@NotNull(message = "数据验证失败,角色ID不能为空!") |
||||||
|
private Long roleId; |
||||||
|
|
||||||
|
/** 在线表单ID */ |
||||||
|
@TableField(value = "form_id") |
||||||
|
@NotNull(message = "数据验证失败,表单ID不能为空!") |
||||||
|
private Long formId; |
||||||
|
|
||||||
|
/** 按钮配置JSON */ |
||||||
|
@TableField(value = "button_config") |
||||||
|
private String buttonConfig; |
||||||
|
|
||||||
|
@TableField(value = "create_by") |
||||||
|
private String createBy; |
||||||
|
|
||||||
|
@TableField(value = "create_time") |
||||||
|
private Date createTime; |
||||||
|
|
||||||
|
@TableField(value = "update_by") |
||||||
|
private String updateBy; |
||||||
|
|
||||||
|
@TableField(value = "update_time") |
||||||
|
private Date updateTime; |
||||||
|
|
||||||
|
@Mapper |
||||||
|
public interface RoleFormButtonModelMapper |
||||||
|
extends BaseModelMapper<RoleFormButtonVo, RoleFormButton> { |
||||||
|
} |
||||||
|
|
||||||
|
public static final RoleFormButtonModelMapper INSTANCE = |
||||||
|
Mappers.getMapper(RoleFormButtonModelMapper.class); |
||||||
|
} |
||||||
@ -0,0 +1,69 @@ |
|||||||
|
package apelet.tenantadmin.tenant.service; |
||||||
|
|
||||||
|
import apelet.common.core.base.service.IBaseService; |
||||||
|
import apelet.common.core.object.CallResult; |
||||||
|
import apelet.tenantadmin.tenant.dto.RoleFormButtonDto; |
||||||
|
import apelet.tenantadmin.tenant.model.RoleFormButton; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
/** |
||||||
|
* 角色-表单按钮权限配置服务接口。 |
||||||
|
* |
||||||
|
* @author chenchuchuan |
||||||
|
* @date 2026-07-17 |
||||||
|
*/ |
||||||
|
public interface IRoleFormButtonService |
||||||
|
extends IBaseService<RoleFormButton, Long> { |
||||||
|
|
||||||
|
/** |
||||||
|
* 分页条件查询。 |
||||||
|
*/ |
||||||
|
List<RoleFormButton> getListByFilter(RoleFormButton filter, String orderBy); |
||||||
|
|
||||||
|
// ========== 核心业务接口 ==========
|
||||||
|
|
||||||
|
/** |
||||||
|
* 查询按钮权限配置的VO(含表单所有按钮 + 勾选状态的合并结果)。 |
||||||
|
* |
||||||
|
* @param roleId 角色ID。 |
||||||
|
* @param formId 在线表单ID。 |
||||||
|
* @return 包含 formId, roleId, id(配置记录ID), buttonList(含name+checked的列表)。 |
||||||
|
*/ |
||||||
|
Map<String, Object> getButtonConfigVo(Long roleId, Long formId); |
||||||
|
|
||||||
|
/** |
||||||
|
* 批量保存按钮权限配置(同一事务内全部成功或全部回滚)。 |
||||||
|
* |
||||||
|
* @param dtoList 保存入参列表。 |
||||||
|
* @return 保存结果。 |
||||||
|
*/ |
||||||
|
CallResult batchSaveButtonConfig(List<RoleFormButtonDto> dtoList); |
||||||
|
|
||||||
|
/** |
||||||
|
* 保存单条按钮权限配置(仅供内部批量方法调用,不做事务注解)。 |
||||||
|
* |
||||||
|
* @param dto 保存入参。 |
||||||
|
* @return 保存结果。 |
||||||
|
*/ |
||||||
|
CallResult saveButtonConfig(RoleFormButtonDto dto); |
||||||
|
|
||||||
|
/** |
||||||
|
* 根据角色ID查询该角色下所有绑定的按钮权限配置。 |
||||||
|
* |
||||||
|
* @param roleId 角色ID。 |
||||||
|
* @return 按钮权限配置列表。 |
||||||
|
*/ |
||||||
|
List<RoleFormButton> listByRoleId(Long roleId); |
||||||
|
|
||||||
|
/** |
||||||
|
* 根据角色ID和表单ID查询唯一配置记录。 |
||||||
|
*/ |
||||||
|
RoleFormButton getByRoleIdAndFormId(Long roleId, Long formId); |
||||||
|
|
||||||
|
/** |
||||||
|
* 删除角色下绑定的所有按钮权限配置(角色删除时调用)。 |
||||||
|
*/ |
||||||
|
void removeByRoleId(Long roleId); |
||||||
|
} |
||||||
@ -0,0 +1,84 @@ |
|||||||
|
package apelet.tenantadmin.tenant.service.impl; |
||||||
|
|
||||||
|
import apelet.common.core.object.TokenData; |
||||||
|
import apelet.common.online.service.FormButtonPermissionChecker; |
||||||
|
import apelet.tenantadmin.tenant.model.RoleFormButton; |
||||||
|
import apelet.tenantadmin.tenant.service.IRoleFormButtonService; |
||||||
|
import apelet.tenantadmin.tenant.util.WidgetJsonButtonParser; |
||||||
|
import apelet.tenantadmin.upms.dao.SysUserRoleMapper; |
||||||
|
import apelet.tenantadmin.upms.model.SysUserRole; |
||||||
|
import com.alibaba.fastjson.JSON; |
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.stereotype.Component; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
import java.util.stream.Collectors; |
||||||
|
|
||||||
|
/** |
||||||
|
* 按钮权限检查器实现。 |
||||||
|
* 通过当前用户的所有角色,查询 xy_sys_role_form_button 表, |
||||||
|
* 判断是否有指定表单-按钮的权限。 |
||||||
|
* |
||||||
|
* @author chenchuchuan |
||||||
|
* @date 2026-07-17 |
||||||
|
*/ |
||||||
|
@Slf4j |
||||||
|
@Component |
||||||
|
public class FormButtonPermissionCheckerImpl implements FormButtonPermissionChecker { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private SysUserRoleMapper sysUserRoleMapper; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private IRoleFormButtonService roleFormButtonService; |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasPermission(Long formId, String buttonName) { |
||||||
|
try { |
||||||
|
// 1. 获取当前登录用户ID
|
||||||
|
TokenData tokenData = TokenData.takeFromRequest(); |
||||||
|
if (tokenData == null) { |
||||||
|
log.warn("TokenData 为空,无法校验按钮权限"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
Long userId = tokenData.getUserId(); |
||||||
|
if (userId == null) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
// 2. 获取用户的所有角色
|
||||||
|
List<SysUserRole> userRoles = sysUserRoleMapper.selectList( |
||||||
|
new LambdaQueryWrapper<SysUserRole>() |
||||||
|
.eq(SysUserRole::getUserId, userId)); |
||||||
|
if (userRoles.isEmpty()) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
List<Long> roleIds = userRoles.stream() |
||||||
|
.map(SysUserRole::getRoleId) |
||||||
|
.collect(Collectors.toList()); |
||||||
|
|
||||||
|
// 3. 遍历角色,检查是否有任一角色授权了该表单的该按钮
|
||||||
|
for (Long roleId : roleIds) { |
||||||
|
RoleFormButton config = |
||||||
|
roleFormButtonService.getByRoleIdAndFormId(roleId, formId); |
||||||
|
if (config != null && config.getButtonConfig() != null) { |
||||||
|
List<WidgetJsonButtonParser.ButtonInfo> buttons = |
||||||
|
JSON.parseArray(config.getButtonConfig(), |
||||||
|
WidgetJsonButtonParser.ButtonInfo.class); |
||||||
|
for (WidgetJsonButtonParser.ButtonInfo btn : buttons) { |
||||||
|
if (buttonName.equals(btn.getName()) |
||||||
|
&& Boolean.TRUE.equals(btn.getEnabled())) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (Exception e) { |
||||||
|
log.error("校验按钮权限时发生异常", e); |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,182 @@ |
|||||||
|
package apelet.tenantadmin.tenant.service.impl; |
||||||
|
|
||||||
|
import apelet.common.core.base.dao.BaseDaoMapper; |
||||||
|
import apelet.common.core.base.service.BaseService; |
||||||
|
import apelet.common.core.object.CallResult; |
||||||
|
import apelet.common.online.model.OnlineForm; |
||||||
|
import apelet.common.online.service.OnlineFormService; |
||||||
|
import apelet.common.sequence.wrapper.IdGeneratorWrapper; |
||||||
|
import apelet.tenantadmin.tenant.dao.RoleFormButtonMapper; |
||||||
|
import apelet.tenantadmin.tenant.dto.RoleFormButtonDto; |
||||||
|
import apelet.tenantadmin.tenant.model.RoleFormButton; |
||||||
|
import apelet.tenantadmin.tenant.service.IRoleFormButtonService; |
||||||
|
import apelet.tenantadmin.tenant.util.WidgetJsonButtonParser; |
||||||
|
import com.alibaba.fastjson.JSON; |
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
import org.springframework.transaction.annotation.Transactional; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* 角色-表单按钮权限配置服务实现。 |
||||||
|
* |
||||||
|
* @author chenchuchuan |
||||||
|
* @date 2026-07-17 |
||||||
|
*/ |
||||||
|
@Service |
||||||
|
@Slf4j |
||||||
|
public class RoleFormButtonServiceImpl |
||||||
|
extends BaseService<RoleFormButton, Long> |
||||||
|
implements IRoleFormButtonService { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private RoleFormButtonMapper mapper; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private IdGeneratorWrapper idGenerator; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private OnlineFormService onlineFormService; |
||||||
|
|
||||||
|
@Override |
||||||
|
protected BaseDaoMapper<RoleFormButton> mapper() { |
||||||
|
return mapper; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<RoleFormButton> getListByFilter( |
||||||
|
RoleFormButton filter, String orderBy) { |
||||||
|
return mapper.getListByFilter(filter, orderBy); |
||||||
|
} |
||||||
|
|
||||||
|
// ========== 核心:查询按钮配置VO ==========
|
||||||
|
@Override |
||||||
|
public Map<String, Object> getButtonConfigVo(Long roleId, Long formId) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
result.put("roleId", roleId); |
||||||
|
result.put("formId", formId); |
||||||
|
|
||||||
|
// 1. 获取 widgetJson,提取所有开启的按钮
|
||||||
|
OnlineForm onlineForm = onlineFormService.getById(formId); |
||||||
|
if (onlineForm == null) { |
||||||
|
result.put("buttonList", Collections.emptyList()); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
List<WidgetJsonButtonParser.ButtonInfo> enabledButtons = |
||||||
|
WidgetJsonButtonParser.extractEnabledButtons(onlineForm.getWidgetJson()); |
||||||
|
|
||||||
|
// 2. 查询已存储的配置
|
||||||
|
RoleFormButton config = getByRoleIdAndFormId(roleId, formId); |
||||||
|
|
||||||
|
// 3. 解析已勾选的按钮名称集合
|
||||||
|
Set<String> checkedNames = new HashSet<>(); |
||||||
|
if (config != null && config.getButtonConfig() != null) { |
||||||
|
List<WidgetJsonButtonParser.ButtonInfo> savedButtons = |
||||||
|
JSON.parseArray(config.getButtonConfig(), |
||||||
|
WidgetJsonButtonParser.ButtonInfo.class); |
||||||
|
for (WidgetJsonButtonParser.ButtonInfo btn : savedButtons) { |
||||||
|
if (Boolean.TRUE.equals(btn.getEnabled())) { |
||||||
|
checkedNames.add(btn.getName()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 4. 合并:表单所有开启的按钮 + 是否勾选
|
||||||
|
List<Map<String, Object>> buttonList = new ArrayList<>(); |
||||||
|
for (WidgetJsonButtonParser.ButtonInfo btn : enabledButtons) { |
||||||
|
Map<String, Object> item = new HashMap<>(); |
||||||
|
item.put("name", btn.getName()); |
||||||
|
item.put("checked", checkedNames.contains(btn.getName())); |
||||||
|
buttonList.add(item); |
||||||
|
} |
||||||
|
|
||||||
|
result.put("id", config != null ? config.getId() : null); |
||||||
|
result.put("buttonList", buttonList); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
// ========== 核心:批量保存按钮配置(事务) ==========
|
||||||
|
@Override |
||||||
|
@Transactional(rollbackFor = Exception.class) |
||||||
|
public CallResult batchSaveButtonConfig(List<RoleFormButtonDto> dtoList) { |
||||||
|
for (RoleFormButtonDto dto : dtoList) { |
||||||
|
CallResult result = this.saveButtonConfig(dto); |
||||||
|
if (!result.isSuccess()) { |
||||||
|
return result; |
||||||
|
} |
||||||
|
} |
||||||
|
return CallResult.ok(); |
||||||
|
} |
||||||
|
|
||||||
|
// ========== 核心:保存单条按钮配置(无独立事务,由外层统一管理) ==========
|
||||||
|
@Override |
||||||
|
public CallResult saveButtonConfig(RoleFormButtonDto dto) { |
||||||
|
// 1. 必填校验
|
||||||
|
if (dto.getRoleId() == null) { |
||||||
|
return CallResult.error("数据验证失败,角色ID不能为空!"); |
||||||
|
} |
||||||
|
if (dto.getFormId() == null) { |
||||||
|
return CallResult.error("数据验证失败,表单ID不能为空!"); |
||||||
|
} |
||||||
|
|
||||||
|
// 2. 构建 button_config JSON
|
||||||
|
List<Map<String, Object>> configList = new ArrayList<>(); |
||||||
|
if (dto.getButtonList() != null) { |
||||||
|
for (RoleFormButtonDto.ButtonItem item : dto.getButtonList()) { |
||||||
|
Map<String, Object> configItem = new HashMap<>(); |
||||||
|
configItem.put("name", item.getName()); |
||||||
|
configItem.put("enabled", Objects.nonNull(item.getChecked()) && item.getChecked()); |
||||||
|
configList.add(configItem); |
||||||
|
} |
||||||
|
} |
||||||
|
String buttonConfigJson = JSON.toJSONString(configList); |
||||||
|
|
||||||
|
// 3. 查询是否已存在配置(role_id + form_id 唯一)
|
||||||
|
RoleFormButton existing = |
||||||
|
getByRoleIdAndFormId(dto.getRoleId(), dto.getFormId()); |
||||||
|
|
||||||
|
if (existing != null) { |
||||||
|
// 更新
|
||||||
|
existing.setButtonConfig(buttonConfigJson); |
||||||
|
existing.setUpdateTime(new Date()); |
||||||
|
this.updateById(existing); |
||||||
|
} else { |
||||||
|
// 新增
|
||||||
|
RoleFormButton entity = new RoleFormButton(); |
||||||
|
entity.setRoleId(dto.getRoleId()); |
||||||
|
entity.setFormId(dto.getFormId()); |
||||||
|
entity.setButtonConfig(buttonConfigJson); |
||||||
|
entity.setId(idGenerator.nextLongId()); |
||||||
|
this.save(entity); |
||||||
|
} |
||||||
|
|
||||||
|
return CallResult.ok(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<RoleFormButton> listByRoleId(Long roleId) { |
||||||
|
LambdaQueryWrapper<RoleFormButton> qw = new LambdaQueryWrapper<>(); |
||||||
|
qw.eq(RoleFormButton::getRoleId, roleId); |
||||||
|
return this.list(qw); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public RoleFormButton getByRoleIdAndFormId(Long roleId, Long formId) { |
||||||
|
LambdaQueryWrapper<RoleFormButton> qw = new LambdaQueryWrapper<>(); |
||||||
|
qw.eq(RoleFormButton::getRoleId, roleId) |
||||||
|
.eq(RoleFormButton::getFormId, formId); |
||||||
|
return this.getOne(qw); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
@Transactional(rollbackFor = Exception.class) |
||||||
|
public void removeByRoleId(Long roleId) { |
||||||
|
LambdaQueryWrapper<RoleFormButton> qw = new LambdaQueryWrapper<>(); |
||||||
|
qw.eq(RoleFormButton::getRoleId, roleId); |
||||||
|
this.remove(qw); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,93 @@ |
|||||||
|
package apelet.tenantadmin.tenant.util; |
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON; |
||||||
|
import com.alibaba.fastjson.JSONArray; |
||||||
|
import com.alibaba.fastjson.JSONObject; |
||||||
|
import lombok.AllArgsConstructor; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.HashSet; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
/** |
||||||
|
* widgetJson 按钮解析工具类。 |
||||||
|
* 从在线表单的 widgetJson 中提取所有 operationList 下的按钮。 |
||||||
|
* |
||||||
|
* @author chenchuchuan |
||||||
|
* @date 2026-07-17 |
||||||
|
*/ |
||||||
|
@Slf4j |
||||||
|
public class WidgetJsonButtonParser { |
||||||
|
|
||||||
|
/** |
||||||
|
* 按钮信息DTO(内部类,轻量)。 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
@AllArgsConstructor |
||||||
|
@NoArgsConstructor |
||||||
|
public static class ButtonInfo { |
||||||
|
/** 按钮名称 */ |
||||||
|
private String name; |
||||||
|
/** 是否在设计器中开启 */ |
||||||
|
private Boolean enabled; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 从 widgetJson 中提取所有开启的按钮(去重,按name)。 |
||||||
|
* |
||||||
|
* @param widgetJson 在线表单的 widget_json 字段值。 |
||||||
|
* @return 按钮列表(只包含 enabled=true 的按钮,按 name 去重)。 |
||||||
|
*/ |
||||||
|
public static List<ButtonInfo> extractEnabledButtons(String widgetJson) { |
||||||
|
List<ButtonInfo> allButtons = extractAllButtons(widgetJson); |
||||||
|
List<ButtonInfo> result = new ArrayList<>(); |
||||||
|
Set<String> seen = new HashSet<>(); |
||||||
|
for (ButtonInfo btn : allButtons) { |
||||||
|
if (Boolean.TRUE.equals(btn.getEnabled()) && seen.add(btn.getName())) { |
||||||
|
result.add(btn); |
||||||
|
} |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 从 widgetJson 中提取所有按钮(不去重,不过滤)。 |
||||||
|
* 仅提取 pc.operationList 和 mobile.operationList 两个顶层数组, |
||||||
|
* 不递归 tableWidget、widgetList、childWidgetList 等子节点下的 operationList。 |
||||||
|
* |
||||||
|
* @param widgetJson 在线表单的 widget_json 字段值。 |
||||||
|
* @return 全部按钮列表。 |
||||||
|
*/ |
||||||
|
public static List<ButtonInfo> extractAllButtons(String widgetJson) { |
||||||
|
List<ButtonInfo> result = new ArrayList<>(); |
||||||
|
if (widgetJson == null || widgetJson.isEmpty()) { |
||||||
|
return result; |
||||||
|
} |
||||||
|
try { |
||||||
|
JSONObject root = JSON.parseObject(widgetJson); |
||||||
|
// 仅取 pc 和 mobile 两端的顶层 operationList
|
||||||
|
for (String device : new String[]{"pc", "mobile"}) { |
||||||
|
JSONObject deviceJson = root.getJSONObject(device); |
||||||
|
if (deviceJson == null) continue; |
||||||
|
JSONArray operationList = deviceJson.getJSONArray("operationList"); |
||||||
|
if (operationList != null) { |
||||||
|
for (int i = 0; i < operationList.size(); i++) { |
||||||
|
JSONObject btn = operationList.getJSONObject(i); |
||||||
|
String name = btn.getString("name"); |
||||||
|
Boolean enabled = btn.getBoolean("enabled"); |
||||||
|
if (name != null) { |
||||||
|
result.add(new ButtonInfo(name, enabled != null ? enabled : false)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (Exception e) { |
||||||
|
log.error("解析 widgetJson 失败", e); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,17 @@ |
|||||||
|
package apelet.tenantadmin.tenant.vo; |
||||||
|
|
||||||
|
import apelet.tenantadmin.tenant.model.RoleFormButton; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.EqualsAndHashCode; |
||||||
|
|
||||||
|
/** |
||||||
|
* 角色-表单按钮权限配置VO对象。 |
||||||
|
* |
||||||
|
* @author chenchuchuan |
||||||
|
* @date 2026-07-17 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
@EqualsAndHashCode(callSuper = true) |
||||||
|
public class RoleFormButtonVo extends RoleFormButton { |
||||||
|
private static final long serialVersionUID = 1L; |
||||||
|
} |
||||||
@ -0,0 +1,20 @@ |
|||||||
|
package apelet.common.online.service; |
||||||
|
|
||||||
|
/** |
||||||
|
* 在线表单按钮权限检查器接口。 |
||||||
|
* 由 tenant-admin 模块实现并注册为 Spring Bean。 |
||||||
|
* |
||||||
|
* @author chenchuchuan |
||||||
|
* @date 2026-07-17 |
||||||
|
*/ |
||||||
|
public interface FormButtonPermissionChecker { |
||||||
|
|
||||||
|
/** |
||||||
|
* 检查当前用户是否有指定表单上指定按钮的操作权限。 |
||||||
|
* |
||||||
|
* @param formId 在线表单ID (zz_online_form.form_id)。 |
||||||
|
* @param buttonName 按钮名称(对应 operationList 中的 name 字段)。 |
||||||
|
* @return true-有权限,false-无权限。 |
||||||
|
*/ |
||||||
|
boolean hasPermission(Long formId, String buttonName); |
||||||
|
} |
||||||
Loading…
Reference in new issue