app平台广告

This commit is contained in:
zjf committed 2026-06-30 18:26:46 +08:00
1 parent ac4e081070
commit dca8a595e6
12 files changed
+547

No files matched your search

@@ -0,0 +1,18 @@
package com.bsd.pjcloud.integrated.constant.platformad;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum PlatformAdMediaTypeEnum {
IMAGE("IMAGE", "图片"),
VIDEO("VIDEO", "视频");
private final String code;
private final String label;
}
@@ -0,0 +1,18 @@
package com.bsd.pjcloud.integrated.constant.platformad;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum PlatformAdSlotEnum {
MERCHANT_CAROUSEL("MERCHANT_CAROUSEL", "商家列表轮播"),
MY_BANNER("MY_BANNER", "我的页面横幅");
private final String code;
private final String label;
}
@@ -0,0 +1,83 @@
package com.bsd.pjcloud.integrated.controller;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bsd.pjcloud.common.api.encrypt.annotation.crypto.ApiCryptoAes;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.common.log.annotation.SysLog;
import com.bsd.pjcloud.common.security.util.SecurityUtils;
import com.bsd.pjcloud.integrated.dto.platformad.PlatformAdSaveDTO;
import com.bsd.pjcloud.integrated.entity.PlatformAdEntity;
import com.bsd.pjcloud.integrated.service.PlatformAdService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.http.HttpHeaders;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequiredArgsConstructor
@RequestMapping("/platform-ad")
@Tag(description = "platform-ad", name = "平台自营广告")
@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
public class PlatformAdController {
private final PlatformAdService platformAdService;
@GetMapping("/page")
@PreAuthorize("@pms.hasPermission('integrated_platformAd_view')")
@Operation(summary = "分页查询")
public R<Page<PlatformAdEntity>> page(@ParameterObject Page page, @ParameterObject PlatformAdEntity query) {
return R.ok(platformAdService.page(page, Wrappers.<PlatformAdEntity>lambdaQuery()
.eq(StrUtil.isNotBlank(query.getSlotCode()), PlatformAdEntity::getSlotCode, query.getSlotCode())
.like(StrUtil.isNotBlank(query.getTitle()), PlatformAdEntity::getTitle, query.getTitle())
.eq(StrUtil.isNotBlank(query.getStatus()), PlatformAdEntity::getStatus, query.getStatus())
.orderByDesc(PlatformAdEntity::getSortOrder, PlatformAdEntity::getCreateTime)));
}
@GetMapping("/{id}")
@PreAuthorize("@pms.hasPermission('integrated_platformAd_view')")
@Operation(summary = "详情")
public R getById(@PathVariable Long id) {
return R.ok(platformAdService.getDetail(id));
}
@PostMapping
@SysLog("新增平台广告")
@PreAuthorize("@pms.hasPermission('integrated_platformAd_add')")
@Operation(summary = "新增")
public R save(@RequestBody PlatformAdSaveDTO dto) {
return R.ok(platformAdService.saveAd(dto));
}
@PutMapping
@SysLog("修改平台广告")
@PreAuthorize("@pms.hasPermission('integrated_platformAd_edit')")
@Operation(summary = "修改")
public R update(@RequestBody PlatformAdSaveDTO dto) {
return R.ok(platformAdService.updateAd(dto));
}
@DeleteMapping
@SysLog("删除平台广告")
@PreAuthorize("@pms.hasPermission('integrated_platformAd_del')")
@Operation(summary = "删除")
public R remove(@RequestBody Long[] ids) {
return R.ok(platformAdService.removeBatchByIds(java.util.Arrays.asList(ids)));
}
@ApiCryptoAes
@GetMapping("/app/list")
@Operation(summary = "App按展示位查询广告")
public R<List<com.bsd.pjcloud.integrated.vo.platformad.PlatformAdAppVO>> appList(@RequestParam String slot) {
Long deptId = SecurityUtils.getUser().getDeptId();
return R.ok(platformAdService.listForApp(slot, deptId));
}
}
@@ -0,0 +1,18 @@
package com.bsd.pjcloud.integrated.dto.platformad;
import com.bsd.pjcloud.integrated.entity.PlatformAdEntity;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = true)
@Schema(description = "平台广告保存")
public class PlatformAdSaveDTO extends PlatformAdEntity {
@Schema(description = "绑定部门ID,deptScope=1时必填")
private List<Long> deptIds;
}
@@ -0,0 +1,24 @@
package com.bsd.pjcloud.integrated.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@TableName("platform_ad_dept")
@EqualsAndHashCode(callSuper = true)
@Schema(description = "平台广告部门绑定")
public class PlatformAdDeptEntity extends Model<PlatformAdDeptEntity> {
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private Long adId;
private Long deptId;
}
@@ -0,0 +1,89 @@
package com.bsd.pjcloud.integrated.entity;
import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.bsd.pjcloud.common.core.util.TenantTable;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDateTime;
@Data
@TenantTable
@TableName("platform_ad")
@EqualsAndHashCode(callSuper = true)
@Schema(description = "平台自营广告")
public class PlatformAdEntity extends Model<PlatformAdEntity> {
@TableId(type = IdType.ASSIGN_ID)
@Schema(description = "主键")
private Long id;
@Schema(description = "展示位")
private String slotCode;
@Schema(description = "标题")
private String title;
@Schema(description = "副标题")
private String subtitle;
@Schema(description = "IMAGE/VIDEO")
private String mediaType;
@Schema(description = "媒体地址")
private String mediaUrl;
@Schema(description = "视频封面")
private String coverUrl;
@Schema(description = "图片是否跳转小程序")
private String jumpEnabled;
@Schema(description = "小程序原始ID")
private String miniAppId;
@Schema(description = "小程序路径")
private String miniAppPath;
@Schema(description = "0正式1开发2体验")
private String miniAppEnv;
@Schema(description = "extraData JSON")
private String miniAppExtra;
@Schema(description = "排序")
private Integer sortOrder;
@Schema(description = "0上架1下架")
private String status;
@Schema(description = "生效开始")
private LocalDateTime startTime;
@Schema(description = "生效结束")
private LocalDateTime endTime;
@Schema(description = "0全部部门1指定部门")
private String deptScope;
@TableField(fill = FieldFill.INSERT)
private String createBy;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private String updateBy;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableLogic
@TableField(fill = FieldFill.INSERT)
private String delFlag;
private Long tenantId;
}
@@ -0,0 +1,10 @@
package com.bsd.pjcloud.integrated.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.bsd.pjcloud.integrated.entity.PlatformAdDeptEntity;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface PlatformAdDeptMapper extends BaseMapper<PlatformAdDeptEntity> {
}
@@ -0,0 +1,10 @@
package com.bsd.pjcloud.integrated.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.bsd.pjcloud.integrated.entity.PlatformAdEntity;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface PlatformAdMapper extends BaseMapper<PlatformAdEntity> {
}
@@ -0,0 +1,21 @@
package com.bsd.pjcloud.integrated.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.bsd.pjcloud.integrated.dto.platformad.PlatformAdSaveDTO;
import com.bsd.pjcloud.integrated.entity.PlatformAdEntity;
import com.bsd.pjcloud.integrated.vo.platformad.PlatformAdAppVO;
import com.bsd.pjcloud.integrated.vo.platformad.PlatformAdDetailVO;
import java.util.List;
public interface PlatformAdService extends IService<PlatformAdEntity> {
List<PlatformAdAppVO> listForApp(String slotCode, Long userDeptId);
PlatformAdDetailVO getDetail(Long id);
boolean saveAd(PlatformAdSaveDTO dto);
boolean updateAd(PlatformAdSaveDTO dto);
}
@@ -0,0 +1,207 @@
package com.bsd.pjcloud.integrated.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bsd.pjcloud.admin.api.entity.SysDept;
import com.bsd.pjcloud.admin.api.feign.RemoteDeptService;
import com.bsd.pjcloud.common.core.exception.CheckedException;
import com.bsd.pjcloud.common.core.util.RetOps;
import com.bsd.pjcloud.integrated.constant.platformad.PlatformAdMediaTypeEnum;
import com.bsd.pjcloud.integrated.dto.platformad.PlatformAdSaveDTO;
import com.bsd.pjcloud.integrated.entity.PlatformAdDeptEntity;
import com.bsd.pjcloud.integrated.entity.PlatformAdEntity;
import com.bsd.pjcloud.integrated.mapper.PlatformAdDeptMapper;
import com.bsd.pjcloud.integrated.mapper.PlatformAdMapper;
import com.bsd.pjcloud.integrated.service.PlatformAdService;
import com.bsd.pjcloud.integrated.vo.platformad.PlatformAdAppVO;
import com.bsd.pjcloud.integrated.vo.platformad.PlatformAdDetailVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
public class PlatformAdServiceImpl extends ServiceImpl<PlatformAdMapper, PlatformAdEntity> implements PlatformAdService {
private static final String DEPT_SCOPE_ALL = "0";
private static final String DEPT_SCOPE_CUSTOM = "1";
private static final String STATUS_ON = "0";
private final PlatformAdDeptMapper platformAdDeptMapper;
private final RemoteDeptService remoteDeptService;
@Override
public List<PlatformAdAppVO> listForApp(String slotCode, Long userDeptId) {
if (StrUtil.isBlank(slotCode)) {
return Collections.emptyList();
}
LocalDateTime now = LocalDateTime.now();
List<PlatformAdEntity> ads = list(Wrappers.<PlatformAdEntity>lambdaQuery()
.eq(PlatformAdEntity::getSlotCode, slotCode)
.eq(PlatformAdEntity::getStatus, STATUS_ON)
.and(w -> w.isNull(PlatformAdEntity::getStartTime).or().le(PlatformAdEntity::getStartTime, now))
.and(w -> w.isNull(PlatformAdEntity::getEndTime).or().ge(PlatformAdEntity::getEndTime, now))
.orderByDesc(PlatformAdEntity::getSortOrder, PlatformAdEntity::getCreateTime));
if (CollUtil.isEmpty(ads)) {
return Collections.emptyList();
}
List<Long> adIds = ads.stream().map(PlatformAdEntity::getId).collect(Collectors.toList());
Map<Long, List<Long>> adDeptMap = platformAdDeptMapper.selectList(Wrappers.<PlatformAdDeptEntity>lambdaQuery()
.in(PlatformAdDeptEntity::getAdId, adIds))
.stream()
.collect(Collectors.groupingBy(PlatformAdDeptEntity::getAdId,
Collectors.mapping(PlatformAdDeptEntity::getDeptId, Collectors.toList())));
return ads.stream()
.filter(ad -> matchDeptScope(ad, adDeptMap.get(ad.getId()), userDeptId))
.map(this::toAppVo)
.collect(Collectors.toList());
}
private boolean isCustomDeptScope(String deptScope) {
return "1".equals(String.valueOf(deptScope));
}
private boolean matchDeptScope(PlatformAdEntity ad, List<Long> boundDeptIds, Long userDeptId) {
if (!isCustomDeptScope(ad.getDeptScope())) {
return true;
}
if (CollUtil.isEmpty(boundDeptIds) || userDeptId == null) {
return false;
}
for (Long boundDeptId : boundDeptIds) {
if (Objects.equals(userDeptId, boundDeptId)) {
return true;
}
List<SysDept> descendants = RetOps.of(remoteDeptService.getInnerDescendantList(boundDeptId))
.getData()
.orElseGet(Collections::emptyList);
boolean inTree = descendants.stream().anyMatch(d -> Objects.equals(d.getDeptId(), userDeptId));
if (inTree) {
return true;
}
}
return false;
}
private PlatformAdAppVO toAppVo(PlatformAdEntity entity) {
PlatformAdAppVO vo = new PlatformAdAppVO();
BeanUtil.copyProperties(entity, vo);
return vo;
}
@Override
public PlatformAdDetailVO getDetail(Long id) {
PlatformAdEntity entity = getById(id);
if (entity == null) {
return null;
}
PlatformAdDetailVO vo = new PlatformAdDetailVO();
BeanUtil.copyProperties(entity, vo);
List<Long> deptIds = platformAdDeptMapper.selectList(Wrappers.<PlatformAdDeptEntity>lambdaQuery()
.eq(PlatformAdDeptEntity::getAdId, id))
.stream()
.map(PlatformAdDeptEntity::getDeptId)
.collect(Collectors.toList());
vo.setDeptIds(deptIds);
return vo;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean saveAd(PlatformAdSaveDTO dto) {
validateSave(dto);
normalizeSave(dto);
boolean ok = save(dto);
if (ok) {
saveDeptBindings(dto.getId(), dto);
}
return ok;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean updateAd(PlatformAdSaveDTO dto) {
if (dto.getId() == null) {
throw new CheckedException("广告ID不能为空");
}
validateSave(dto);
normalizeSave(dto);
boolean ok = updateById(dto);
platformAdDeptMapper.delete(Wrappers.<PlatformAdDeptEntity>lambdaQuery()
.eq(PlatformAdDeptEntity::getAdId, dto.getId()));
saveDeptBindings(dto.getId(), dto);
return ok;
}
private void validateSave(PlatformAdSaveDTO dto) {
if (StrUtil.isBlank(dto.getSlotCode())) {
throw new CheckedException("展示位不能为空");
}
if (StrUtil.isBlank(dto.getMediaType()) || StrUtil.isBlank(dto.getMediaUrl())) {
throw new CheckedException("请上传广告素材");
}
if (isCustomDeptScope(dto.getDeptScope()) && CollUtil.isEmpty(dto.getDeptIds())) {
throw new CheckedException("请选择绑定部门");
}
if (PlatformAdMediaTypeEnum.VIDEO.getCode().equals(dto.getMediaType())) {
dto.setJumpEnabled("0");
}
if ("1".equals(dto.getJumpEnabled())) {
if (StrUtil.isBlank(dto.getMiniAppId())) {
throw new CheckedException("请填写小程序原始ID");
}
}
}
private void normalizeSave(PlatformAdSaveDTO dto) {
if (isCustomDeptScope(dto.getDeptScope())) {
dto.setDeptScope(DEPT_SCOPE_CUSTOM);
} else {
dto.setDeptScope(DEPT_SCOPE_ALL);
dto.setDeptIds(null);
}
if (!"1".equals(dto.getJumpEnabled())) {
dto.setJumpEnabled("0");
dto.setMiniAppId(null);
dto.setMiniAppPath(null);
dto.setMiniAppEnv(null);
dto.setMiniAppExtra(null);
}
if (dto.getSortOrder() == null) {
dto.setSortOrder(0);
}
if (StrUtil.isBlank(dto.getStatus())) {
dto.setStatus(STATUS_ON);
}
if (StrUtil.isBlank(dto.getMiniAppEnv())) {
dto.setMiniAppEnv("0");
}
}
private void saveDeptBindings(Long adId, PlatformAdSaveDTO dto) {
if (!isCustomDeptScope(dto.getDeptScope()) || CollUtil.isEmpty(dto.getDeptIds())) {
return;
}
for (Long deptId : dto.getDeptIds()) {
if (deptId == null) {
continue;
}
PlatformAdDeptEntity row = new PlatformAdDeptEntity();
row.setAdId(adId);
row.setDeptId(deptId);
platformAdDeptMapper.insert(row);
}
}
}
@@ -0,0 +1,32 @@
package com.bsd.pjcloud.integrated.vo.platformad;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
@Schema(description = "App端平台广告")
public class PlatformAdAppVO {
private Long id;
private String title;
private String subtitle;
private String mediaType;
private String mediaUrl;
private String coverUrl;
private String jumpEnabled;
private String miniAppId;
private String miniAppPath;
private String miniAppEnv;
private String miniAppExtra;
}
@@ -0,0 +1,17 @@
package com.bsd.pjcloud.integrated.vo.platformad;
import com.bsd.pjcloud.integrated.entity.PlatformAdEntity;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = true)
@Schema(description = "平台广告详情")
public class PlatformAdDetailVO extends PlatformAdEntity {
private List<Long> deptIds;
}