权限过滤

This commit is contained in:
zjf committed 2026-08-10 15:43:11 +08:00
1 parent a023c5c52b
commit 3083b6b0b8
32 files changed
+338 -28

No files matched your search

@@ -75,6 +75,13 @@ public class BoxesBookingEntity extends Model<BoxesBookingEntity> {
@Schema(description="备注信息")
private String remark;
/**
* 创建人
*/
@TableField(fill = FieldFill.INSERT)
@Schema(description="创建人")
private String createBy;
/**
* 创建时间
*/
@@ -8,6 +8,7 @@ import lombok.EqualsAndHashCode;
import com.bsd.pjcloud.common.core.util.TenantTable;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
/**
* 采购记录表
@@ -84,6 +85,13 @@ public class CanteenInventoryRecordsEntity extends Model<CanteenInventoryRecords
@Schema(description="商户编号")
private Long merchantId;
/**
* 非管理员列表隔离:允许的商户 ID 集合(仅查询用,非表字段)
*/
@TableField(exist = false)
@Schema(description = "数据隔离商户ID列表", hidden = true)
private List<Long> scopeMerchantIds;
/**
* 部门id
*/
@@ -14,6 +14,7 @@ import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.common.log.annotation.SysLog;
import com.bsd.pjcloud.canteen.entity.BoxesInfoEntity;
import com.bsd.pjcloud.canteen.service.BoxesInfoService;
import com.bsd.pjcloud.canteen.util.CanteenMerchantScopeHelper;
import com.bsd.pjcloud.common.security.util.SecurityUtils;
import io.swagger.v3.oas.annotations.Parameter;
import org.springframework.beans.BeanUtils;
@@ -49,6 +50,8 @@ public class BoxesInfoController {
private final BoxesBookingService boxesBookingService;
private final CanteenMerchantScopeHelper merchantScopeHelper;
/**
* 分页查询
*
@@ -65,6 +68,7 @@ public class BoxesInfoController {
wrapper.eq(StrUtil.isNotBlank(boxesInfo.getTableNumber()), BoxesInfoEntity::getTableNumber, boxesInfo.getTableNumber());
wrapper.eq(ObjectUtil.isNotEmpty(boxesInfo.getStatus()), BoxesInfoEntity::getStatus, boxesInfo.getStatus());
wrapper.eq(ObjectUtil.isNotEmpty(boxesInfo.getTableType()), BoxesInfoEntity::getTableType, boxesInfo.getTableType());
merchantScopeHelper.applyMerchantIdScope(wrapper, boxesInfo.getMerchantId(), BoxesInfoEntity::getMerchantId);
return R.ok(boxesInfoService.pageScope(page, wrapper));
}
@@ -92,7 +96,10 @@ public class BoxesInfoController {
@PostMapping
@PreAuthorize("@pms.hasPermission('canteen_boxesInfo_add')")
public R save(@RequestBody BoxesInfoEntity boxesInfo) {
boxesInfo.setDeptId(SecurityUtils.getUser().getDeptId());
merchantScopeHelper.fillDeptIdByMerchantId(boxesInfo.getMerchantId(), boxesInfo::setDeptId);
if (boxesInfo.getDeptId() == null) {
boxesInfo.setDeptId(SecurityUtils.getUser().getDeptId());
}
return R.ok(boxesInfoService.saveInfo(boxesInfo));
}
@@ -107,6 +114,7 @@ public class BoxesInfoController {
@PutMapping
@PreAuthorize("@pms.hasPermission('canteen_boxesInfo_edit')")
public R updateById(@RequestBody BoxesInfoEntity boxesInfo) {
merchantScopeHelper.fillDeptIdByMerchantId(boxesInfo.getMerchantId(), boxesInfo::setDeptId);
return R.ok(boxesInfoService.updateById(boxesInfo));
}
@@ -13,6 +13,7 @@ import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.common.log.annotation.SysLog;
import com.bsd.pjcloud.canteen.entity.CanteenErpCategoryEntity;
import com.bsd.pjcloud.canteen.service.CanteenErpCategoryService;
import com.bsd.pjcloud.canteen.util.CanteenMerchantScopeHelper;
import com.bsd.pjcloud.common.security.util.SecurityUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import com.bsd.pjcloud.common.excel.annotation.ResponseExcel;
@@ -42,6 +43,8 @@ public class CanteenErpCategoryController {
private final CanteenErpCategoryService canteenErpCategoryService;
private final CanteenMerchantScopeHelper merchantScopeHelper;
/**
* 分页查询
* @param page 分页对象
@@ -54,6 +57,7 @@ public class CanteenErpCategoryController {
public R getCanteenErpCategoryPage(@ParameterObject Page page, @ParameterObject CanteenErpCategoryEntity canteenErpCategory) {
LambdaQueryWrapper<CanteenErpCategoryEntity> wrapper = Wrappers.lambdaQuery();
wrapper.eq(StrUtil.isNotBlank(canteenErpCategory.getName()),CanteenErpCategoryEntity::getName,canteenErpCategory.getName());
merchantScopeHelper.applyMerchantIdScope(wrapper, canteenErpCategory.getMerchantId(), CanteenErpCategoryEntity::getMerchantId);
return R.ok(canteenErpCategoryService.pageScope(page, wrapper));
}
@@ -80,7 +84,10 @@ public class CanteenErpCategoryController {
@PostMapping
@PreAuthorize("@pms.hasPermission('canteen_canteenErpCategory_add')" )
public R save(@RequestBody CanteenErpCategoryEntity canteenErpCategory) {
canteenErpCategory.setDeptId(SecurityUtils.getUser().getDeptId());
merchantScopeHelper.fillDeptIdByMerchantId(canteenErpCategory.getMerchantId(), canteenErpCategory::setDeptId);
if (canteenErpCategory.getDeptId() == null) {
canteenErpCategory.setDeptId(SecurityUtils.getUser().getDeptId());
}
return R.ok(canteenErpCategoryService.save(canteenErpCategory));
}
@@ -94,6 +101,7 @@ public class CanteenErpCategoryController {
@PutMapping
@PreAuthorize("@pms.hasPermission('canteen_canteenErpCategory_edit')" )
public R updateById(@RequestBody CanteenErpCategoryEntity canteenErpCategory) {
merchantScopeHelper.fillDeptIdByMerchantId(canteenErpCategory.getMerchantId(), canteenErpCategory::setDeptId);
return R.ok(canteenErpCategoryService.updateById(canteenErpCategory));
}
@@ -13,6 +13,7 @@ import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.common.log.annotation.SysLog;
import com.bsd.pjcloud.canteen.entity.CanteenOnlineCategoryEntity;
import com.bsd.pjcloud.canteen.service.CanteenOnlineCategoryService;
import com.bsd.pjcloud.canteen.util.CanteenMerchantScopeHelper;
import org.springframework.security.access.prepost.PreAuthorize;
import com.bsd.pjcloud.common.excel.annotation.ResponseExcel;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
@@ -40,6 +41,8 @@ public class CanteenOnlineCategoryController {
private final CanteenOnlineCategoryService canteenOnlineCategoryService;
private final CanteenMerchantScopeHelper merchantScopeHelper;
/**
* 分页查询
* @param page 分页对象
@@ -52,6 +55,7 @@ public class CanteenOnlineCategoryController {
public R getCanteenOnlineCategoryPage(@ParameterObject Page page, @ParameterObject CanteenOnlineCategoryEntity canteenOnlineCategory) {
LambdaQueryWrapper<CanteenOnlineCategoryEntity> wrapper = Wrappers.lambdaQuery();
wrapper.like(StrUtil.isNotBlank(canteenOnlineCategory.getName()),CanteenOnlineCategoryEntity::getName,canteenOnlineCategory.getName());
merchantScopeHelper.applyMerchantIdScope(wrapper, canteenOnlineCategory.getMerchantId(), CanteenOnlineCategoryEntity::getMerchantId);
return R.ok(canteenOnlineCategoryService.pageScope(page, wrapper));
}
@@ -130,6 +134,7 @@ public class CanteenOnlineCategoryController {
public R getById() {
LambdaQueryWrapper<CanteenOnlineCategoryEntity> canteenOnlineCategoryEntityLambdaQueryWrapper = new LambdaQueryWrapper<>();
canteenOnlineCategoryEntityLambdaQueryWrapper.eq(CanteenOnlineCategoryEntity::getStatus,"0");
merchantScopeHelper.applyMerchantIdScope(canteenOnlineCategoryEntityLambdaQueryWrapper, null, CanteenOnlineCategoryEntity::getMerchantId);
List<CanteenOnlineCategoryEntity> list = canteenOnlineCategoryService.listScope(canteenOnlineCategoryEntityLambdaQueryWrapper);
List<CanteenOnlineCategorySimpleVO> bean = BeanUtils.toBean(list, CanteenOnlineCategorySimpleVO.class);
return R.ok(bean);
@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bsd.pjcloud.canteen.entity.CanteenOnlineSpuChoiceGroupEntity;
import com.bsd.pjcloud.canteen.service.CanteenOnlineSpuChoiceGroupService;
import com.bsd.pjcloud.canteen.util.CanteenMerchantScopeHelper;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.common.core.constant.enums.MerchantTypeEnum;
import com.bsd.pjcloud.common.log.annotation.SysLog;
@@ -34,6 +35,7 @@ public class CanteenOnlineSpuChoiceGroupController {
private final CanteenOnlineSpuChoiceGroupService choiceGroupService;
private final RemoteMchService remoteMchService;
private final CanteenMerchantScopeHelper merchantScopeHelper;
@GetMapping("/page")
@Operation(summary = "分页查询分组", description = "走数据权限 selectPageByScope;merchantId 不传则按数据权限返回可见范围内的全部分组,传了则按商户筛选")
@@ -42,8 +44,8 @@ public class CanteenOnlineSpuChoiceGroupController {
@RequestParam(required = false) String name,
Page page) {
LambdaQueryWrapper<CanteenOnlineSpuChoiceGroupEntity> wrapper = Wrappers.lambdaQuery();
wrapper.eq(merchantId != null, CanteenOnlineSpuChoiceGroupEntity::getMerchantId, merchantId)
.like(name != null && !name.trim().isEmpty(), CanteenOnlineSpuChoiceGroupEntity::getName, name.trim())
merchantScopeHelper.applyMerchantIdScope(wrapper, merchantId, CanteenOnlineSpuChoiceGroupEntity::getMerchantId);
wrapper.like(name != null && !name.trim().isEmpty(), CanteenOnlineSpuChoiceGroupEntity::getName, name.trim())
.orderByAsc(CanteenOnlineSpuChoiceGroupEntity::getSort)
.orderByDesc(CanteenOnlineSpuChoiceGroupEntity::getId);
return R.ok(choiceGroupService.pageByScope(page, wrapper));
@@ -23,6 +23,7 @@ import com.bsd.pjcloud.canteen.entity.CanteenOnlineSpuEntity;
import com.bsd.pjcloud.canteen.entity.CanteenOnlineSpuChoiceGroupEntity;
import com.bsd.pjcloud.canteen.service.CanteenOnlineSpuChoiceGroupService;
import com.bsd.pjcloud.canteen.service.CanteenOnlineSpuService;
import com.bsd.pjcloud.canteen.util.CanteenMerchantScopeHelper;
import com.bsd.pjcloud.common.security.util.SecurityUtils;
import com.bsd.pjcloud.common.core.constant.enums.MerchantTypeEnum;
import com.bsd.pjcloud.wallet.api.feign.RemoteMchService;
@@ -61,6 +62,7 @@ public class CanteenOnlineSpuController {
private final CanteenOnlineSpuService canteenOnlineSpuService;
private final CanteenOnlineSpuChoiceGroupService canteenOnlineSpuChoiceGroupService;
private final RemoteMchService remoteMchService;
private final CanteenMerchantScopeHelper merchantScopeHelper;
/**
* 模板选择线上菜品分页(用于加工模版选择菜品弹窗)
@@ -96,6 +98,7 @@ public class CanteenOnlineSpuController {
wrapper.like(StrUtil.isNotBlank(canteenOnlineSpu.getName()), CanteenOnlineSpuEntity::getName, canteenOnlineSpu.getName());
wrapper.eq(Objects.nonNull(canteenOnlineSpu.getCategoryId()), CanteenOnlineSpuEntity::getCategoryId, canteenOnlineSpu.getCategoryId());
wrapper.eq(Objects.nonNull(canteenOnlineSpu.getSpuType()), CanteenOnlineSpuEntity::getSpuType, canteenOnlineSpu.getSpuType());
merchantScopeHelper.applyMerchantIdScope(wrapper, canteenOnlineSpu.getMerchantId(), CanteenOnlineSpuEntity::getMerchantId);
// 根据菜品类型筛选
if (Objects.nonNull(dishType)) {
@@ -12,6 +12,7 @@ import com.bsd.pjcloud.canteen.entity.CanteenProductionRecordEntity;
import com.bsd.pjcloud.canteen.mapper.*;
import com.bsd.pjcloud.canteen.service.CanteenInventoryRecordsService;
import com.bsd.pjcloud.canteen.service.CanteenStockService;
import com.bsd.pjcloud.canteen.util.CanteenMerchantScopeHelper;
import com.bsd.pjcloud.canteen.vo.erp.CanteenProductionRecordPageVO;
import com.bsd.pjcloud.canteen.vo.erp.InventoryRecordItemVo;
import com.bsd.pjcloud.canteen.vo.erp.InventoryRecordVo;
@@ -48,13 +49,18 @@ public class CanteenInventoryRecordsServiceImpl extends ServiceImpl<CanteenInven
private final CanteenStockService canteenStockService;
private final CanteenErpMaterialMapper canteenErpMaterialMapper;
private final CanteenMerchantScopeHelper merchantScopeHelper;
@Override
@Transactional
public Object saveCanteenInventoryRecordsdDTO(CanteenInventoryRecordsdDTO canteenInventoryRecordsdDTO) {
Long deptId = SecurityUtils.getUser().getDeptId();
CanteenInventoryRecordsEntity canteenInventoryRecordsEntity= BeanUtils.toBean(canteenInventoryRecordsdDTO, CanteenInventoryRecordsEntity.class);
canteenInventoryRecordsEntity.setDeptId(deptId);
merchantScopeHelper.fillDeptIdByMerchantId(canteenInventoryRecordsEntity.getMerchantId(), canteenInventoryRecordsEntity::setDeptId);
if (canteenInventoryRecordsEntity.getDeptId() == null) {
canteenInventoryRecordsEntity.setDeptId(SecurityUtils.getUser().getDeptId());
}
canteenInventoryRecordsEntity.setCheckStatus(TaskCheckStatusEnum.PADDING.getCode());
// canteenInventoryRecordsEntity.setCheckStatus(TaskCheckStatusEnum.RESULT.getCode());
baseMapper.insert(canteenInventoryRecordsEntity);
@@ -67,7 +73,7 @@ public class CanteenInventoryRecordsServiceImpl extends ServiceImpl<CanteenInven
// List<UpdateStockDTO> updateStockDTOS = new ArrayList<>();
for (CanteenInventoryRecordsItemEntity canteenInventoryRecordsItemEntity : canteenInventoryRecordsItemEntityList){
canteenInventoryRecordsItemEntity.setInventoryId(id);
canteenInventoryRecordsItemEntity.setDeptId(deptId);
canteenInventoryRecordsItemEntity.setDeptId(canteenInventoryRecordsEntity.getDeptId());
String orderType = canteenInventoryRecordsEntity.getOrderType();
canteenInventoryRecordsItemEntity.setOrderType(orderType);
// UpdateStockDTO updateStockDTO = new UpdateStockDTO();
@@ -96,7 +102,13 @@ public class CanteenInventoryRecordsServiceImpl extends ServiceImpl<CanteenInven
@Override
public Page<CanteenProductionRecordPageVO> pageScope(Page page, CanteenInventoryRecordsEntity canteenInventoryRecords) {
if (canteenInventoryRecords == null) {
canteenInventoryRecords = new CanteenInventoryRecordsEntity();
}
merchantScopeHelper.prepareXmlMerchantFilter(
canteenInventoryRecords.getMerchantId(),
canteenInventoryRecords::setMerchantId,
canteenInventoryRecords::setScopeMerchantIds);
return baseMapper.selectPageDataByScope(page,canteenInventoryRecords, DataScope.of());
}
@@ -24,6 +24,7 @@ import com.bsd.pjcloud.canteen.mapper.CanteenOnlineComboItemMapper;
import com.bsd.pjcloud.canteen.mapper.CanteenOnlineSpuMapper;
import com.bsd.pjcloud.canteen.service.CanteenOnlineSpuChoiceGroupService;
import com.bsd.pjcloud.canteen.service.CanteenOnlineSpuService;
import com.bsd.pjcloud.canteen.util.CanteenMerchantScopeHelper;
import com.bsd.pjcloud.canteen.util.MealSegmentCategoryUtils;
import com.bsd.pjcloud.canteen.vo.app.CanteenOnlineSpuAppVO;
import com.bsd.pjcloud.canteen.vo.app.OnlineSpuChoiceGroupRuleVO;
@@ -81,6 +82,8 @@ public class CanteenOnlineSpuServiceImpl extends ServiceImpl<CanteenOnlineSpuMap
private final CanteenOnlineComboItemMapper comboItemMapper;
private final CanteenMerchantScopeHelper merchantScopeHelper;
@Override
public CanteenOnlineSpuEntity getDetail(Long id) {
CanteenOnlineSpuEntity entity = baseMapper.selectById(id);
@@ -628,8 +631,9 @@ public class CanteenOnlineSpuServiceImpl extends ServiceImpl<CanteenOnlineSpuMap
public Page<CanteenOnlineSpuSimpleVO> getCanteenOnlineSpuSimplePageScope(Page page, CanteenOnlineSpuEntity canteenOnlineSpu) {
LambdaQueryWrapper<CanteenOnlineSpuEntity> wrapper = new LambdaQueryWrapper<>();
wrapper.like(StrUtil.isNotBlank(canteenOnlineSpu.getName()), CanteenOnlineSpuEntity::getName, canteenOnlineSpu.getName())
.eq(Objects.nonNull(canteenOnlineSpu.getCategoryId()), CanteenOnlineSpuEntity::getCategoryId, canteenOnlineSpu.getCategoryId())
.eq(Objects.nonNull(canteenOnlineSpu.getMerchantId()), CanteenOnlineSpuEntity::getMerchantId, canteenOnlineSpu.getMerchantId())
.eq(Objects.nonNull(canteenOnlineSpu.getCategoryId()), CanteenOnlineSpuEntity::getCategoryId, canteenOnlineSpu.getCategoryId());
merchantScopeHelper.applyMerchantIdScope(wrapper, canteenOnlineSpu.getMerchantId(), CanteenOnlineSpuEntity::getMerchantId);
wrapper
// 套餐组成只可选单品(spu_type 为空或 1)
.and(w -> w.isNull(CanteenOnlineSpuEntity::getSpuType).or().eq(CanteenOnlineSpuEntity::getSpuType, 1))
.eq(CanteenOnlineSpuEntity::getStatus, 0)
@@ -170,6 +170,7 @@ public class CanteenSpuServiceImpl extends ServiceImpl<CanteenSpuMapper, Canteen
wrapper.eq(Objects.nonNull(canteenSpu.getCategoryId()), CanteenSpuEntity::getCategoryId, canteenSpu.getCategoryId());
// 套餐组成只可选单品(spu_type 为空或 1)
wrapper.and(w -> w.isNull(CanteenSpuEntity::getSpuType).or().eq(CanteenSpuEntity::getSpuType, 1));
merchantScopeHelper.applyMerchantIdScope(wrapper, canteenSpu.getMerchantId(), CanteenSpuEntity::getMerchantId);
wrapper.orderByAsc(CanteenSpuEntity::getSort).orderByDesc(CanteenSpuEntity::getId);
Page<CanteenSpuEntity> pageData = baseMapper.selectPageByScope(page, wrapper, DataScope.of());
@@ -189,6 +190,7 @@ public class CanteenSpuServiceImpl extends ServiceImpl<CanteenSpuMapper, Canteen
LambdaQueryWrapper<CanteenSpuEntity> wrapper = new LambdaQueryWrapper<>();
wrapper.like(StrUtil.isNotBlank(canteenSpu.getName()), CanteenSpuEntity::getName, canteenSpu.getName());
wrapper.eq(Objects.nonNull(canteenSpu.getCategoryId()), CanteenSpuEntity::getCategoryId, canteenSpu.getCategoryId());
merchantScopeHelper.applyMerchantIdScope(wrapper, canteenSpu.getMerchantId(), CanteenSpuEntity::getMerchantId);
wrapper.orderByAsc(CanteenSpuEntity::getSort).orderByDesc(CanteenSpuEntity::getId);
// 查询SPU分页数据
@@ -131,6 +131,35 @@ public class CanteenMerchantScopeHelper {
wrapper.in(merchantIdColumn, allowed);
}
/**
* 供自定义 XML 分页使用:写入 merchantId 或 scopeMerchantIds。
*/
public void prepareXmlMerchantFilter(Long queryMerchantId, java.util.function.Consumer<Long> setMerchantId,
java.util.function.Consumer<List<Long>> setScopeMerchantIds) {
if (canViewAllMerchants()) {
if (queryMerchantId != null && setMerchantId != null) {
setMerchantId.accept(queryMerchantId);
}
return;
}
List<Long> allowed = resolveAllowedMerchantIds();
if (CollUtil.isEmpty(allowed)) {
if (setMerchantId != null) {
setMerchantId.accept(-1L);
}
return;
}
if (queryMerchantId != null) {
if (setMerchantId != null) {
setMerchantId.accept(allowed.contains(queryMerchantId) ? queryMerchantId : -1L);
}
return;
}
if (setScopeMerchantIds != null) {
setScopeMerchantIds.accept(allowed);
}
}
/**
* 按商户回填 deptId(写入时与商户部门对齐,保证 DataScope 与商户隔离一致)
*/
@@ -20,6 +20,7 @@
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
<result property="deptId" column="dept_id"/>
<result property="createBy" column="create_by"/>
<result property="processInstanceId" column="process_instance_id"/>
<result property="checkReason" column="check_reason"/>
</resultMap>
@@ -42,6 +42,7 @@
m.name,
m.unit,
m.dept_id,
m.create_by,
m.material_type AS materialType,
m.category_id,
m.nutrition_tags AS nutritionTags,
@@ -32,7 +32,11 @@
<select id="selectPageDataByScope"
resultType="com.bsd.pjcloud.canteen.vo.erp.CanteenProductionRecordPageVO">
SELECT r.id, r.inventory_code,r.inventory_date, COALESCE(GROUP_CONCAT(m.name ORDER BY m.name SEPARATOR ','), '') AS product_name,r.remark,r.total_amount,s.supplier_name,
r.check_status FROM `canteen_inventory_records` r
r.check_status,
<!-- 数据权限拦截器外层按 dept_id / create_by 过滤,须透传到临时结果集 -->
r.dept_id,
r.create_by
FROM `canteen_inventory_records` r
LEFT JOIN canteen_inventory_records_item i
on r.id=i.inventory_id
LEFT JOIN canteen_erp_material m
@@ -47,6 +51,15 @@
<if test="canteenInventoryRecords.inventoryDate != null and canteenInventoryRecords.inventoryDate != ''">
and cpr.production_time = #{inventoryDate}
</if>
<if test="canteenInventoryRecords.merchantId != null">
and r.merchant_id = #{canteenInventoryRecords.merchantId}
</if>
<if test="canteenInventoryRecords.scopeMerchantIds != null and canteenInventoryRecords.scopeMerchantIds.size() > 0">
and r.merchant_id in
<foreach collection="canteenInventoryRecords.scopeMerchantIds" item="mid" open="(" separator="," close=")">
#{mid}
</foreach>
</if>
</where>
GROUP BY r.id
order by r.create_time desc
@@ -552,7 +552,7 @@ public class HardOrderController {
@Operation(summary = "线上订餐统计", description = "按食堂统计线上订餐订单的菜品份数仅用 template_type=2 的线上模板,排除退款")
@PostMapping("/online-canteen-stats")
@PreAuthorize("@pms.hasPermission('hard_hardwareOrder_view')")
// @PreAuthorize("@pms.hasPermission('hard_hardwareOrder_view')")
public R<List<HardOnlineCanteenStatsVo>> onlineCanteenStats(@RequestBody HardOnlineCanteenStatsQueryDto query) {
if (query.getMchIds() == null || query.getMchIds().isEmpty()) {
query.setMchIds(null);
@@ -108,6 +108,12 @@ public class SmErpUnitEntity extends Model<SmErpUnitEntity> {
@Schema(description="创建者")
private String createBy;
/**
* 部门id(DataScope 过滤字段)
*/
@Schema(description="部门id")
private Long deptId;
/**
* 创建时间
*/
@@ -12,6 +12,7 @@ import com.bsd.pjcloud.common.log.annotation.SysLog;
import com.bsd.pjcloud.common.security.util.SecurityUtils;
import com.bsd.pjcloud.supermarket.entity.MallCategoryEntity;
import com.bsd.pjcloud.supermarket.service.MallCategoryService;
import com.bsd.pjcloud.supermarket.util.SupermarketMerchantScopeHelper;
import com.bsd.pjcloud.supermarket.vo.mall.MallCategoryTreeVo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
@@ -40,6 +41,8 @@ public class MallCategoryController {
private final MallCategoryService MallCategoryService;
private final SupermarketMerchantScopeHelper merchantScopeHelper;
/**
* 分页查询
* @param page 分页对象
@@ -52,8 +55,7 @@ public class MallCategoryController {
public R getMallCategoryPage(@ParameterObject Page page, @ParameterObject MallCategoryEntity MallCategory) {
LambdaQueryWrapper<MallCategoryEntity> wrapper = Wrappers.lambdaQuery();
wrapper.eq(StrUtil.isNotBlank(MallCategory.getName()),MallCategoryEntity::getName,MallCategory.getName());
// 添加商户ID过滤条件
wrapper.eq(MallCategory.getMerchantId() != null, MallCategoryEntity::getMerchantId, MallCategory.getMerchantId());
merchantScopeHelper.applyMerchantIdScope(wrapper, MallCategory.getMerchantId(), MallCategoryEntity::getMerchantId);
return R.ok(MallCategoryService.pageScope(page, wrapper));
}
@@ -10,6 +10,7 @@ import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.common.log.annotation.SysLog;
import com.bsd.pjcloud.supermarket.entity.MallMerchantEntity;
import com.bsd.pjcloud.supermarket.service.MallMerchantService;
import com.bsd.pjcloud.supermarket.util.SupermarketMerchantScopeHelper;
import org.springframework.security.access.prepost.PreAuthorize;
import com.bsd.pjcloud.common.excel.annotation.ResponseExcel;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
@@ -38,6 +39,8 @@ public class MallMerchantController {
private final MallMerchantService mallMerchantService;
private final SupermarketMerchantScopeHelper merchantScopeHelper;
/**
* 分页查询
* @param page 分页对象
@@ -52,6 +55,16 @@ public class MallMerchantController {
wrapper.like(StrUtil.isNotBlank(mallMerchant.getName()),MallMerchantEntity::getName,mallMerchant.getName());
wrapper.like(StrUtil.isNotBlank(mallMerchant.getContactName()),MallMerchantEntity::getContactName,mallMerchant.getContactName());
wrapper.eq(StrUtil.isNotBlank(mallMerchant.getContactPhone()),MallMerchantEntity::getContactPhone,mallMerchant.getContactPhone());
if (!merchantScopeHelper.canViewAllMerchants()) {
// mall_merchant 与钱包商户通过部门关联隔离
Long deptId = com.bsd.pjcloud.common.security.util.SecurityUtils.getUser() != null
? com.bsd.pjcloud.common.security.util.SecurityUtils.getUser().getDeptId() : null;
if (deptId == null) {
wrapper.apply("1 = 0");
} else {
wrapper.eq(MallMerchantEntity::getDeptId, deptId);
}
}
return R.ok(mallMerchantService.page(page, wrapper));
}
@@ -12,6 +12,7 @@ import com.bsd.pjcloud.supermarket.entity.MallProductEntity;
import com.bsd.pjcloud.supermarket.entity.MallProductSkuEntity;
import com.bsd.pjcloud.supermarket.service.MallProductService;
import com.bsd.pjcloud.supermarket.service.MallProductSkuService;
import com.bsd.pjcloud.supermarket.util.SupermarketMerchantScopeHelper;
import com.bsd.pjcloud.supermarket.dto.MallProductCreateDTO;
import com.bsd.pjcloud.supermarket.dto.MallProductStockChangeDTO;
import com.bsd.pjcloud.supermarket.vo.mall.MallProductDetailAppVo;
@@ -46,6 +47,7 @@ public class MallProductController {
private final MallProductService mallProductService;
private final MallProductSkuService mallProductSkuService;
private final SupermarketMerchantScopeHelper merchantScopeHelper;
/**
* 分页查询(管理端)
@@ -60,8 +62,8 @@ public class MallProductController {
LambdaQueryWrapper<MallProductEntity> wrapper = Wrappers.lambdaQuery();
wrapper.eq(Objects.nonNull(mallProduct.getCategoryId()),MallProductEntity::getCategoryId,mallProduct.getCategoryId());
wrapper.like(StrUtil.isNotBlank(mallProduct.getTitle()),MallProductEntity::getTitle,mallProduct.getTitle());
wrapper.eq(Objects.nonNull(mallProduct.getMerchantId()),MallProductEntity::getMerchantId,mallProduct.getMerchantId());
wrapper.eq(StrUtil.isNotBlank(mallProduct.getStatus()),MallProductEntity::getStatus,mallProduct.getStatus());
merchantScopeHelper.applyMerchantIdScope(wrapper, mallProduct.getMerchantId(), MallProductEntity::getMerchantId);
// 如果是 Feign 调用,返回 MallProductListAppVo 格式
Page<MallProductEntity> resultPage = mallProductService.page(page, wrapper);
@@ -14,6 +14,7 @@ import com.bsd.pjcloud.supermarket.vo.ShopSpuPageVo;
import com.bsd.pjcloud.supermarket.entity.ShopSkuEntity;
import com.bsd.pjcloud.supermarket.service.ShopSpuService;
import com.bsd.pjcloud.supermarket.service.ShopSkuService;
import com.bsd.pjcloud.supermarket.util.SupermarketMerchantScopeHelper;
import org.springframework.security.access.prepost.PreAuthorize;
import com.bsd.pjcloud.common.excel.annotation.ResponseExcel;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
@@ -44,6 +45,7 @@ public class ShopSpuController {
private final ShopSpuService shopSpuService;
private final ShopSkuService shopSkuService;
private final SupermarketMerchantScopeHelper merchantScopeHelper;
/**
* 分页查询
@@ -57,6 +59,23 @@ public class ShopSpuController {
public R getShopSpuPage(@ParameterObject Page page, @ParameterObject ShopSpuEntity shopSpu) {
LambdaQueryWrapper<ShopSpuEntity> wrapper = Wrappers.lambdaQuery();
wrapper.like(StrUtil.isNotBlank(shopSpu.getProductName()),ShopSpuEntity::getProductName,shopSpu.getProductName());
if (!merchantScopeHelper.canViewAllMerchants()) {
java.util.List<Long> allowed = merchantScopeHelper.resolveAllowedMerchantIds();
if (allowed == null || allowed.isEmpty()) {
wrapper.apply("1 = 0");
} else {
wrapper.and(w -> {
for (int i = 0; i < allowed.size(); i++) {
Long mid = allowed.get(i);
if (i == 0) {
w.apply("FIND_IN_SET({0}, merchant_ids)", mid);
} else {
w.or().apply("FIND_IN_SET({0}, merchant_ids)", mid);
}
}
});
}
}
return R.ok(shopSpuService.pageScope(page, wrapper));
}
@@ -0,0 +1,150 @@
package com.bsd.pjcloud.supermarket.util;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.bsd.pjcloud.admin.api.entity.SysDept;
import com.bsd.pjcloud.admin.api.entity.SysRole;
import com.bsd.pjcloud.admin.api.feign.RemoteDataScopeService;
import com.bsd.pjcloud.admin.api.feign.RemoteDeptService;
import com.bsd.pjcloud.common.core.constant.CommonRoleConstant;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.common.core.util.RetOps;
import com.bsd.pjcloud.common.data.datascope.DataScopeTypeEnum;
import com.bsd.pjcloud.common.security.service.PjcloudUser;
import com.bsd.pjcloud.common.security.util.SecurityUtils;
import com.bsd.pjcloud.wallet.api.feign.RemoteMchService;
import com.bsd.pjcloud.wallet.api.vo.MchManageVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
* 超市/商城后台商户数据隔离:数据权限为「全部」或 ROLE_ADMIN 可见全部;其余账号仅可见本部门及下级关联商户。
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class SupermarketMerchantScopeHelper {
private final RemoteMchService remoteMchService;
private final RemoteDeptService remoteDeptService;
private final RemoteDataScopeService remoteDataScopeService;
/**
* 是否可查看全部商户数据(管理员 / 数据权限=全部)
*/
public boolean canViewAllMerchants() {
PjcloudUser user = SecurityUtils.getUser();
if (user == null) {
return false;
}
List<Long> roleIds = SecurityUtils.getRoleIds();
if (CollUtil.isEmpty(roleIds)) {
return false;
}
List<SysRole> roleList = RetOps.of(remoteDataScopeService.getRoleList(roleIds))
.getData()
.orElseGet(Collections::emptyList);
if (CollUtil.isEmpty(roleList)) {
return false;
}
for (SysRole role : roleList) {
if (role == null) {
continue;
}
if (StrUtil.equals(role.getRoleCode(), CommonRoleConstant.ROLE_ADMIN)) {
return true;
}
if (Objects.equals(role.getDsType(), DataScopeTypeEnum.ALL.getType())) {
return true;
}
}
return false;
}
/**
* 当前登录用户可访问的商户 ID 列表(部门及下级 → mch_manage)
*/
public List<Long> resolveAllowedMerchantIds() {
PjcloudUser user = SecurityUtils.getUser();
if (user == null || user.getDeptId() == null) {
return Collections.emptyList();
}
Long rootDeptId = user.getDeptId();
List<Long> deptIds;
R<List<SysDept>> deptR = remoteDeptService.getDescendantList(rootDeptId);
if (deptR != null && deptR.isOk() && CollUtil.isNotEmpty(deptR.getData())) {
deptIds = deptR.getData().stream().map(SysDept::getDeptId).filter(Objects::nonNull).distinct().toList();
}
else {
deptIds = List.of(rootDeptId);
}
R<List<MchManageVo>> mchR = remoteMchService.getByDeptIds(deptIds);
if (mchR == null || !mchR.isOk() || CollUtil.isEmpty(mchR.getData())) {
return Collections.emptyList();
}
return mchR.getData().stream()
.map(MchManageVo::getId)
.filter(Objects::nonNull)
.distinct()
.collect(Collectors.toList());
}
/**
* 列表查询商户隔离:管理员可不传 merchantId 看全部;非管理员强制限制在可访问商户内。
*/
public <T> void applyMerchantIdScope(LambdaQueryWrapper<T> wrapper, Long queryMerchantId,
SFunction<T, ?> merchantIdColumn) {
if (canViewAllMerchants()) {
if (queryMerchantId != null) {
wrapper.eq(merchantIdColumn, queryMerchantId);
}
return;
}
List<Long> allowed = resolveAllowedMerchantIds();
if (CollUtil.isEmpty(allowed)) {
wrapper.apply("1 = 0");
return;
}
if (queryMerchantId != null) {
if (allowed.contains(queryMerchantId)) {
wrapper.eq(merchantIdColumn, queryMerchantId);
}
else {
wrapper.apply("1 = 0");
}
return;
}
wrapper.in(merchantIdColumn, allowed);
}
/**
* 按商户回填 deptId
*/
public void fillDeptIdByMerchantId(Long merchantId, Consumer<Long> deptIdSetter) {
if (merchantId == null || deptIdSetter == null) {
return;
}
try {
R<MchManageVo> r = remoteMchService.getById(merchantId);
if (r != null && r.isOk() && ObjectUtil.isNotEmpty(r.getData()) && r.getData().getDeptId() != null) {
deptIdSetter.accept(r.getData().getDeptId());
}
}
catch (Exception e) {
log.warn("按商户回填部门失败, merchantId={}", merchantId, e);
}
}
}
@@ -65,7 +65,9 @@
THEN item.quantity * u.package_num
ELSE item.quantity
END
END), 0) AS opening_qty
END), 0) AS opening_qty,
MAX(spu.dept_id) AS dept_id,
MAX(spu.create_by) AS create_by
FROM sm_erp_spu spu
LEFT JOIN sm_erp_stock stock ON stock.erp_spu_id = spu.id
LEFT JOIN sm_erp_inventory_records_item item ON item.erp_spu_id = spu.id
@@ -50,8 +50,8 @@
spu.id AS product_id,
spu.product_code,
spu.product_name,
spu.dept_id,
spu.create_by,
MAX(spu.dept_id) AS dept_id,
MAX(spu.create_by) AS create_by,
cat.name AS category_name,
base.spec AS spec,
base.unit AS unit,
@@ -60,7 +60,9 @@
THEN item.account_number * u.package_num ELSE item.account_number END
END)
)
), 0) / 100.0 AS diff_amount
), 0) / 100.0 AS diff_amount,
MAX(spu.dept_id) AS dept_id,
MAX(spu.create_by) AS create_by
FROM sm_erp_inventory_records_item item
LEFT JOIN sm_erp_inventory_records r ON r.id = item.inventory_id
LEFT JOIN sm_erp_spu spu ON spu.id = item.erp_spu_id
@@ -133,8 +133,9 @@
- ABS(COALESCE(SUM(CASE WHEN r.inventory_type = '6' THEN item.total_amount END), 0)) / 100.0) * 100
ELSE 0
END AS profit_margin,
COUNT(DISTINCT CASE WHEN r.inventory_type IN ('5', '6') THEN r.id END) AS sales_count
COUNT(DISTINCT CASE WHEN r.inventory_type IN ('5', '6') THEN r.id END) AS sales_count,
MAX(spu.dept_id) AS dept_id,
MAX(spu.create_by) AS create_by
FROM sm_erp_spu spu
LEFT JOIN sm_erp_inventory_records_item item ON item.erp_spu_id = spu.id
LEFT JOIN sm_erp_inventory_records r ON r.id = item.inventory_id AND r.del_flag = '0' AND r.inventory_type IN ('5', '6')
@@ -32,8 +32,8 @@
spu.id AS product_id,
spu.product_code,
spu.product_name,
spu.dept_id,
spu.create_by,
MAX(spu.dept_id) AS dept_id,
MAX(spu.create_by) AS create_by,
cat.name AS category_name,
base.spec AS spec,
base.unit AS unit,
@@ -32,7 +32,12 @@
</resultMap>
<select id="selectInventoryTypeSumPageByScope"
resultType="com.bsd.pjcloud.supermarket.vo.inventoryrecord.InventoryRecordSumVo">
SELECT erp_spu_id ,sum(total_amount) as inventoryPrice,sum(quantity) as inventoryNum FROM sm_erp_inventory_records_item
SELECT erp_spu_id,
sum(total_amount) as inventoryPrice,
sum(quantity) as inventoryNum,
MAX(dept_id) as dept_id,
MAX(create_by) as create_by
FROM sm_erp_inventory_records_item
where order_type = #{inventoryDetailQueryDTO.orderType}
GROUP BY erp_spu_id
@@ -46,7 +46,8 @@
u.retail_price,
supp.supplier_name,
r.inventory_date,
r.dept_id
r.dept_id,
r.create_by
FROM sm_erp_inventory_records_item i
LEFT JOIN sm_erp_inventory_records r
on i.inventory_id = r.id
@@ -83,7 +83,8 @@
u.package_num,
u.retail_price/100 as retail_price,
u.promotion_price/100 as promotion_price,
es.dept_id
es.dept_id,
es.create_by
FROM sm_erp_spu es
left join sm_erp_unit u
on es.id = u.spu_id and u.is_base=1
@@ -16,6 +16,7 @@
<result property="promotionPrice" column="promotion_price"/>
<result property="costPrice" column="cost_price"/>
<result property="createBy" column="create_by"/>
<result property="deptId" column="dept_id"/>
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
@@ -22,7 +22,7 @@
</resultMap>
<select id="selectSmErpPageScopeVo" resultType="com.bsd.pjcloud.supermarket.vo.sm.smspu.SmSpuPageVo">
select esp.id as erp_spu_id,esp.product_code,esp.bar_code,esp.product_name,esp.category_id,
esp.pic_url,esp.sort,esp.status,esp.merchant_id,esp.dept_id,
esp.pic_url,esp.sort,esp.status,esp.merchant_id,esp.dept_id,esp.create_by,
sp.create_time,sp.id,sp.slider_pic_urls,
eca.name as category_name
from sm_spu sp
@@ -41,7 +41,9 @@
COALESCE(item.quantity, 0) AS physical_qty,
0 AS diff_qty,
0 AS diff_amount,
r.remark
r.remark,
r.dept_id,
r.create_by
FROM sm_erp_inventory_records r
INNER JOIN sm_erp_inventory_records_item item ON item.inventory_id = r.id