Merge branch 'feature/REQ-2106' into 'master'

Feature/req 2106

See merge request universal/infrastructure/backend/nanopart!33
This commit is contained in:
金海洋 2024-04-24 09:28:01 +00:00
commit ec1712c040
53 changed files with 1937 additions and 622 deletions

View File

@ -1,82 +1,84 @@
// package cn.axzo.nanopart.api;
//
// import cn.axzo.framework.domain.web.result.ApiPageResult;
// import cn.axzo.framework.domain.web.result.ApiResult;
// import cn.axzo.nanopart.api.request.CreateApplicationVersionReq;
// import cn.axzo.nanopart.api.request.GetVersionUpdateRemindContentReq;
// import cn.axzo.nanopart.api.request.PageApplicationVersionReq;
// import cn.axzo.nanopart.api.request.UpdateApplicationVersionReq;
// import cn.axzo.nanopart.api.response.GetVersionUpdateRemindContentResp;
// import cn.axzo.nanopart.api.response.PageApplicationVersionResp;
// import org.springframework.cloud.openfeign.FeignClient;
// import org.springframework.web.bind.annotation.GetMapping;
// import org.springframework.web.bind.annotation.PostMapping;
// import org.springframework.web.bind.annotation.RequestBody;
// import org.springframework.web.bind.annotation.RequestParam;
//
// import javax.validation.Valid;
//
// /**
// * @author chenwenjian
// * @version 1.0
// * @date 2024/4/2 10:21
// */
// @FeignClient(name = "nanopart", url = "${axzo.service.nanopart:http://nanopart:8080}")
// public interface ApplicationVersionApi {
//
// /**
// * 创建
// * <p>
// * 版本号+平台+操作系统不可重复
// * </p>
// *
// * @param req {@link CreateApplicationVersionReq}
// * @return 版本记录id
// */
// @PostMapping("/api/applicationVersion/create")
// ApiResult<Long> create(@RequestBody @Valid CreateApplicationVersionReq req);
//
// /**
// * 更新
// *
// * @param req {@link UpdateApplicationVersionReq}
// * @return void
// */
// @PostMapping("/api/applicationVersion/update")
// ApiResult<Void> update(@RequestBody @Valid UpdateApplicationVersionReq req);
//
// /**
// * 删除
// *
// * @param id 版本记录id
// * @return void
// */
// @GetMapping("/api/applicationVersion/delete")
// ApiResult<Void> deleteById(@RequestParam("id") Long id, @RequestParam("personId") Long personId);
//
// /**
// * 分页查询
// *
// * @param req {@link PageApplicationVersionReq}
// * @return 按照版本号字典序倒排
// */
// @PostMapping("/api/applicationVersion/page")
// ApiPageResult<PageApplicationVersionResp> page(@RequestBody @Valid PageApplicationVersionReq req);
//
// /**
// * 获取版本更新提醒内容
// * <p>
// * 1. 获取最新配置的提示内容记录
// * - 对于cms直接返回最新配置版本号最高的一条记录看是否配置了弹窗提示
// * - 对于app根据版本号和操作系统看该版本号是否配置了弹窗提示
// * 2. 检查当前用户是否已经提示
// * - 若已提示则不再提示直接返回null
// * - 若还没有提示则返回该条提示内容记录
// * </p>
// *
// * @param req {@link GetVersionUpdateRemindContentReq}
// * @return 版本更新提醒内容
// */
// @PostMapping("/api/applicationVersion/getVersionUpdateRemindContent")
// ApiResult<GetVersionUpdateRemindContentResp> getVersionUpdateRemindContent(@RequestBody @Valid GetVersionUpdateRemindContentReq req);
// }
package cn.axzo.nanopart.api;
import cn.axzo.framework.domain.web.result.ApiPageResult;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.nanopart.api.request.CreateApplicationVersionReq;
import cn.axzo.nanopart.api.request.GetVersionUpdateRemindContentReq;
import cn.axzo.nanopart.api.request.PageApplicationVersionReq;
import cn.axzo.nanopart.api.request.UpdateApplicationVersionReq;
import cn.axzo.nanopart.api.response.GetVersionUpdateRemindContentResp;
import cn.axzo.nanopart.api.response.PageApplicationVersionResp;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import javax.validation.Valid;
/**
* 版本记录相关api
*
* @author chenwenjian
* @version 1.0
* @date 2024/4/2 10:21
*/
@FeignClient(name = "nanopart", url = "${axzo.service.nanopart:http://nanopart:8080}")
public interface ApplicationVersionApi {
/**
* 创建
* <p>
* 版本号+平台+操作系统不可重复
* </p>
*
* @param req {@link CreateApplicationVersionReq}
* @return 版本记录id
*/
@PostMapping("/api/applicationVersion/create")
ApiResult<Long> create(@RequestBody @Valid CreateApplicationVersionReq req);
/**
* 更新
*
* @param req {@link UpdateApplicationVersionReq}
* @return void
*/
@PostMapping("/api/applicationVersion/update")
ApiResult<Void> update(@RequestBody @Valid UpdateApplicationVersionReq req);
/**
* 删除
*
* @param id 版本记录id
* @return void
*/
@GetMapping("/api/applicationVersion/delete")
ApiResult<Void> deleteById(@RequestParam("id") Long id, @RequestParam(value = "personId") Long personId);
/**
* 分页查询
*
* @param req {@link PageApplicationVersionReq}
* @return 按照版本号字典序倒排
*/
@PostMapping("/api/applicationVersion/page")
ApiPageResult<PageApplicationVersionResp> page(@RequestBody @Valid PageApplicationVersionReq req);
/**
* 获取版本更新提醒内容
* <p>
* 1. 获取最新配置的提示内容记录
* - 对于cms直接返回最新配置版本号最高的一条记录看是否配置了弹窗提示
* - 对于app根据版本号和操作系统看该版本号是否配置了弹窗提示
* 2. 检查当前用户是否已经提示
* - 若已提示则不再提示直接返回null
* - 若还没有提示则返回该条提示内容记录并记录为已提示
* </p>
*
* @param req {@link GetVersionUpdateRemindContentReq}
* @return 版本更新提醒内容
*/
@PostMapping("/api/applicationVersion/getVersionUpdateRemindContent")
ApiResult<GetVersionUpdateRemindContentResp> getVersionUpdateRemindContent(@RequestBody @Valid GetVersionUpdateRemindContentReq req);
}

View File

@ -1,72 +1,72 @@
// package cn.axzo.nanopart.api;
//
// import cn.axzo.framework.domain.web.result.ApiPageResult;
// import cn.axzo.framework.domain.web.result.ApiResult;
// import cn.axzo.nanopart.api.request.CreateBannerReq;
// import cn.axzo.nanopart.api.request.DetailBannerReq;
// import cn.axzo.nanopart.api.request.PageBannerReq;
// import cn.axzo.nanopart.api.request.UpdateBannerReq;
// import cn.axzo.nanopart.api.request.UpdateStatusReq;
// import cn.axzo.nanopart.api.response.DetailBannerResp;
// import cn.axzo.nanopart.api.response.PageBannerResp;
// import org.springframework.cloud.openfeign.FeignClient;
// import org.springframework.web.bind.annotation.PostMapping;
// import org.springframework.web.bind.annotation.RequestBody;
//
// import javax.validation.Valid;
//
// /**
// * @author chenwenjian
// * @version 1.0
// * @date 2024/4/2 10:19
// */
// @FeignClient(name = "nanopart", url = "${axzo.service.nanopart:http://nanopart:8080}")
// public interface BannerApi {
//
// /**
// * 分页查询banner
// *
// * @param req {@link PageBannerReq}
// * @return 按照站点code(code)自增排序后列表 {@link PageBannerResp}
// */
// @PostMapping("/api/banner/page")
// ApiPageResult<PageBannerResp> page(@RequestBody @Valid PageBannerReq req);
//
// /**
// * 创建banner
// *
// * @param req {@link CreateBannerReq}
// * @return bannerId
// */
// @PostMapping("/api/banner/create")
// ApiResult<Long> create(@RequestBody @Valid CreateBannerReq req);
//
// /**
// * 更新banner
// *
// * @param req {@link UpdateBannerReq}
// * @return void
// */
// @PostMapping("/api/banner/update")
// ApiResult<Void> update(@RequestBody @Valid UpdateBannerReq req);
//
// /**
// * 更新banner状态
// *
// * @param req {@link UpdateStatusReq}
// * @return void
// */
// @PostMapping("/api/banner/updateStatus")
// ApiResult<Void> updateStatus(@RequestBody @Valid UpdateStatusReq req);
//
// /**
// * 详情
// *
// * @param req 广告位唯一的id或code {@link DetailBannerReq}
// * @return {@link DetailBannerResp}
// */
// @PostMapping("/api/banner/detail")
// ApiResult<DetailBannerResp> detail(@RequestBody @Valid DetailBannerReq req);
//
//
// }
package cn.axzo.nanopart.api;
import cn.axzo.framework.domain.web.result.ApiPageResult;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.nanopart.api.request.CreateBannerReq;
import cn.axzo.nanopart.api.request.DetailBannerReq;
import cn.axzo.nanopart.api.request.PageBannerReq;
import cn.axzo.nanopart.api.request.UpdateBannerReq;
import cn.axzo.nanopart.api.request.UpdateStatusReq;
import cn.axzo.nanopart.api.response.DetailBannerResp;
import cn.axzo.nanopart.api.response.PageBannerResp;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import javax.validation.Valid;
/**
* 广告位相关 api
*
* @author chenwenjian
* @version 1.0
* @date 2024/4/2 10:19
*/
@FeignClient(name = "nanopart", url = "${axzo.service.nanopart:http://nanopart:8080}")
public interface BannerApi {
/**
* 分页查询banner
*
* @param req {@link PageBannerReq}
* @return 按照站点code(code)自增排序后列表 {@link PageBannerResp}
*/
@PostMapping("/api/banner/page")
ApiPageResult<PageBannerResp> page(@RequestBody @Valid PageBannerReq req);
/**
* 创建banner
*
* @param req {@link CreateBannerReq}
* @return bannerId
*/
@PostMapping("/api/banner/create")
ApiResult<Long> create(@RequestBody @Valid CreateBannerReq req);
/**
* 更新banner
*
* @param req {@link UpdateBannerReq}
* @return void
*/
@PostMapping("/api/banner/update")
ApiResult<Void> update(@RequestBody @Valid UpdateBannerReq req);
/**
* 更新banner状态
*
* @param req {@link UpdateStatusReq}
* @return void
*/
@PostMapping("/api/banner/updateStatus")
ApiResult<Void> updateStatus(@RequestBody @Valid UpdateStatusReq req);
/**
* 详情
*
* @param req 广告位唯一的id或code {@link DetailBannerReq}
* @return {@link DetailBannerResp}
*/
@PostMapping("/api/banner/detail")
ApiResult<DetailBannerResp> detail(@RequestBody @Valid DetailBannerReq req);
}

View File

@ -1,28 +1,30 @@
// package cn.axzo.nanopart.api;
//
// import cn.axzo.framework.domain.web.result.ApiPageResult;
// import cn.axzo.nanopart.api.request.PageBannerOperationLogReq;
// import cn.axzo.nanopart.api.response.PageBannerOperationLogResp;
// import org.springframework.cloud.openfeign.FeignClient;
// import org.springframework.web.bind.annotation.PostMapping;
// import org.springframework.web.bind.annotation.RequestBody;
//
// import javax.validation.Valid;
//
// /**
// * @author chenwenjian
// * @version 1.0
// * @date 2024/4/2 10:21
// */
// @FeignClient(name = "nanopart", url = "${axzo.service.nanopart:http://nanopart:8080}")
// public interface BannerOperationLogApi {
//
// /**
// * 分页查询
// *
// * @param req {@link PageBannerOperationLogReq}
// * @return 按照操作时间倒叙排序
// */
// @PostMapping("/api/bannerOperationLog/page")
// ApiPageResult<PageBannerOperationLogResp> page(@RequestBody @Valid PageBannerOperationLogReq req);
// }
package cn.axzo.nanopart.api;
import cn.axzo.framework.domain.web.result.ApiPageResult;
import cn.axzo.nanopart.api.request.PageBannerOperationLogReq;
import cn.axzo.nanopart.api.response.PageBannerOperationLogResp;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import javax.validation.Valid;
/**
* 广告位和素材操作日志
*
* @author chenwenjian
* @version 1.0
* @date 2024/4/2 10:21
*/
@FeignClient(name = "nanopart", url = "${axzo.service.nanopart:http://nanopart:8080}")
public interface BannerOperationLogApi {
/**
* 分页查询
*
* @param req {@link PageBannerOperationLogReq}
* @return 按照操作时间倒叙排序
*/
@PostMapping("/api/bannerOperationLog/page")
ApiPageResult<PageBannerOperationLogResp> page(@RequestBody @Valid PageBannerOperationLogReq req);
}

View File

@ -1,8 +1,15 @@
package cn.axzo.nanopart.api;
import cn.axzo.framework.domain.web.result.ApiPageResult;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.nanopart.api.request.CreateMaterialReq;
import cn.axzo.nanopart.api.request.DetailMaterialReq;
import cn.axzo.nanopart.api.request.ListMaterialByBannerCodeReq;
import cn.axzo.nanopart.api.request.PageMaterialReq;
import cn.axzo.nanopart.api.request.UpdateMaterialReq;
import cn.axzo.nanopart.api.request.UpdateStatusReq;
import cn.axzo.nanopart.api.response.MaterialResp;
import cn.axzo.nanopart.api.response.PageMaterialResp;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@ -11,6 +18,8 @@ import javax.validation.Valid;
import java.util.List;
/**
* 素材管理相关 api
*
* @author chenwenjian
* @version 1.0
* @date 2024/4/2 10:20
@ -18,59 +27,56 @@ import java.util.List;
@FeignClient(name = "nanopart", url = "${axzo.service.nanopart:http://nanopart:8080}")
public interface MaterialApi {
// /**
// * 分页查询
// *
// * @param req {@link PageMaterialReq}}
// * @return 根据上下架状态上架下架优先级正序数字由小到大排列后素材列表
// */
// @PostMapping("/api/material/page")
// ApiPageResult<PageMaterialResp> page(@RequestBody @Valid PageMaterialReq req);
//
// /**
// * 创建
// *
// * @param req {@link CreateMaterialReq}
// * @return 素材id
// */
// @PostMapping("/api/material/create")
// ApiResult<Long> create(@RequestBody @Valid CreateMaterialReq req);
//
// /**
// * 更新
// *
// * @param req {@link UpdateMaterialReq}
// * @return
// */
// @PostMapping("/api/material/update")
// ApiResult<Void> update(@RequestBody @Valid UpdateMaterialReq req);
//
// /**
// * 更新banner状态
// *
// * @param req {@link UpdateStatusReq}
// * @return void
// */
// @PostMapping("/api/material/updateStatus")
// ApiResult<Void> updateStatus(@RequestBody @Valid UpdateStatusReq req);
//
// /**
// * 详情
// *
// * @param req {@link UpdateMaterialReq}
// * @return 素材详情
// */
// @PostMapping("/api/material/detail")
// ApiResult<MaterialResp> detail(@RequestBody @Valid DetailMaterialReq req);
/**
* 分页查询
*
* @param req {@link PageMaterialReq}}
* @return 根据上下架状态上架下架优先级正序数字由小到大排列后素材列表
*/
@PostMapping("/api/material/page")
ApiPageResult<PageMaterialResp> page(@RequestBody @Valid PageMaterialReq req);
/**
* 创建
*
* @param req {@link CreateMaterialReq}
* @return 素材id
*/
@PostMapping("/api/material/create")
ApiResult<Long> create(@RequestBody @Valid CreateMaterialReq req);
/**
* 更新
*
* @param req {@link UpdateMaterialReq}
* @return
*/
@PostMapping("/api/material/update")
ApiResult<Void> update(@RequestBody @Valid UpdateMaterialReq req);
/**
* 更新banner状态
*
* @param req {@link UpdateStatusReq}
* @return
*/
@PostMapping("/api/material/updateStatus")
ApiResult<Void> updateStatus(@RequestBody @Valid UpdateStatusReq req);
/**
* 详情
*
* @param req {@link UpdateMaterialReq}
* @return 素材详情
*/
@PostMapping("/api/material/detail")
ApiResult<MaterialResp> detail(@RequestBody @Valid DetailMaterialReq req);
/**
* 根据广告位编码bannerCode查询素材
* <p>
* 对于cms和cmp需要传入当前登录人所在的workspaceIdouId和所担任的jobCode
* </p>
* <p>
* 1. 通过广告位code获取该广告位下的所有素材默认查询上架状态且在有效期范围内的素材
* 2. 根据广告位投放人群进行过滤
* 2. 根据广告位投放人群进行过滤对于cms/cmp需要根据当前登录人登录企业情况进行过滤
* 3. 根据广告位投放规则频次进行过滤
* 4. 将最终的素材根据优先级priority升序创建时间createAt降序排序
* </p>
@ -80,5 +86,4 @@ public interface MaterialApi {
*/
@PostMapping("/api/material/listByBannerCode")
ApiResult<List<MaterialResp>> listMaterialByBannerCode(@RequestBody @Valid ListMaterialByBannerCodeReq req);
}

View File

@ -10,4 +10,14 @@ package cn.axzo.nanopart.api.constant;
public class NanopartConstant {
public static final String BASIC_FEIGN_PACKAGE = "cn.axzo";
/**
* 请求上下文日志ID
*/
public static final String CONTEXT_TRACE_ID = "ctxLogId";
/**
* 版本号简单校验正则表达式
*/
public static final String VERSION_SIMPLE_PATTERN = "^\\d+\\.\\d+\\.\\d+$";
}

View File

@ -39,6 +39,9 @@ public class AspectRatioDto {
if (this.getWidth() <= 0 || this.getWidth() > 100) {
throw new ServiceException("请设置合适的占位图宽高比例");
}
}else {
this.setWidth(0);
this.setHeight(0);
}
}
}

View File

@ -16,6 +16,7 @@ import java.util.Map;
@NoArgsConstructor
@AllArgsConstructor
public class JoinedWorkspaceOuJob {
/**
* 加入的项目部及在该项目部下担任的所有岗位
*/
@ -26,4 +27,14 @@ public class JoinedWorkspaceOuJob {
*/
private Map<Long, List<String>> ouJobMap;
/**
* 加入的单位及在该单位加入的项目部
*/
private Map<Long, List<Long>> ouWorkspaceMap;
/**
* 加入的项目部及在该项目部加入的单位
*/
private Map<Long, List<Long>> workspaceOuMap;
}

View File

@ -0,0 +1,43 @@
package cn.axzo.nanopart.api.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import java.sql.Time;
import java.util.Arrays;
/**
* 广告位展示时间段类型
*
* @author chenwenjian
* @version 1.0
* @date 2024/4/12 17:17
*/
@Getter
@AllArgsConstructor
public enum DisplayTimeTypeEnum {
ALL_DAY("ALL_DAY", "全天", Time.valueOf("00:00:00").getTime(), Time.valueOf("23:59:59").getTime()),
WORKING("WORKING", "上班时间(5:00-18:00)", Time.valueOf("05:00:00").getTime(), Time.valueOf("18:00:00").getTime()),
BREAKING("BREAKING", "休息时间(18:00-22:00)", Time.valueOf("18:00:00").getTime(), Time.valueOf("22:00:00").getTime()),
CUSTOM("CUSTOM", "自定义", null, null);
private final String name;
private final String desc;
private final Long startTime;
private final Long endTime;
public static DisplayTimeTypeEnum getType(String name) {
if (StringUtils.isEmpty(name)) {
return null;
}
return Arrays.stream(values())
.filter(item -> item.name.equals(name))
.findFirst()
.orElse(null);
}
}

View File

@ -0,0 +1,41 @@
package cn.axzo.nanopart.api.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import java.util.Arrays;
/**
* 素材或广告位操作日志类型
*
* @author chenwenjian
* @version 1.0
* @date 2024/4/18 10:39
*/
@Getter
@AllArgsConstructor
public enum LogOperationTypeEnum {
CREATE("create", "新增"),
UPDATE("update", "编辑"),
DELETE("delete", "删除"),
UPDATE_STATUS("updateStatus", "更新状态");
private final String type;
private final String desc;
public static LogOperationTypeEnum getLogOperationType(String type) {
if (StringUtils.isEmpty(type)) {
return null;
}
return Arrays.stream(values())
.filter(item -> item.type.equals(type))
.findFirst()
.orElse(null);
}
}

View File

@ -16,6 +16,7 @@ import java.util.Arrays;
@Getter
@AllArgsConstructor
public enum MaterialDisplayFrequencyTypeEnum {
NO_LIMIT("NO_LIMIT", "不限制"),
VALIDITY_PERIOD("VALIDITY_PERIOD", "有效期内"),
EVERY_DAY("EVERY_DAY", "每天"),
EVERY_WEEK("EVERY_WEEK", "每周"),

View File

@ -1,14 +1,14 @@
package cn.axzo.nanopart.api.enums;
import cn.axzo.nanopart.api.dto.JoinedWorkspaceOuJob;
import cn.hutool.json.JSONUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
/**
@ -18,34 +18,138 @@ import java.util.stream.Collectors;
* @version 1.0
* @date 2024/4/9 16:46
*/
@Slf4j
@Getter
@AllArgsConstructor
public enum MaterialTargetUserTypeEnum {
ALL("ALL_USER", "全部用户") {
ALL("ALL", "全部用户") {
@Override
public boolean isDeliverRequired(List<Long> workspaceIds, List<Long> ouIds, List<String> jobCodes, JoinedWorkspaceOuJob workspaceOuJob) {
public boolean isDeliverRequired(List<Long> workspaceIds, List<Long> ouIds, List<String> jobCodes,
Long loginWorkspaceId, Long loginOuid,
JoinedWorkspaceOuJob workspaceOuJob) {
log.info("投放全部用户");
return true;
}
},
PROJECT("PROJECT", "按照项目部") {
@Override
public boolean isDeliverRequired(List<Long> workspaceIds, List<Long> ouIds, List<String> jobCodes, JoinedWorkspaceOuJob workspaceOuJob) {
// 若workspaceIds和jobCodes都为空则表示不限制否则需要满足配置的workspaceIds和jobCodes与用户加入的workspaceJob的keyvalue均存在交集
public boolean isDeliverRequired(List<Long> workspaceIds, List<Long> ouIds, List<String> jobCodes,
Long loginWorkspaceId, Long loginOuid,
JoinedWorkspaceOuJob workspaceOuJob) {
Map<Long, List<String>> workspaceJobMap = workspaceOuJob.getWorkspaceJobMap();
return CollectionUtils.isEmpty(workspaceIds) ? CollectionUtils.isEmpty(jobCodes) || jobCodes.stream().anyMatch(jobCode -> workspaceJobMap.values().stream().flatMap(List::stream).distinct().collect(Collectors.toList()).contains(jobCode))
: workspaceIds.stream().anyMatch(workspaceId -> workspaceJobMap.get(workspaceId).stream().anyMatch(jobCodes::contains));
log.info("投放项目部:{},投放岗位岗位:{},当前登录单位:{},用户加入项目部及担任岗位:{},单位加入的项目部:{},项目部下的单位:{}",
JSONUtil.toJsonStr(ouIds), JSONUtil.toJsonStr(jobCodes),
loginOuid,
JSONUtil.toJsonStr(workspaceJobMap),
JSONUtil.toJsonStr(workspaceOuJob.getOuWorkspaceMap()),
JSONUtil.toJsonStr(workspaceOuJob.getWorkspaceOuMap()));
// 配置全部项目部
if (CollectionUtils.isEmpty(workspaceIds)) {
// 未加入任何项目部
if (Objects.isNull(workspaceJobMap) || workspaceJobMap.isEmpty()) {
return false;
}
if (CollectionUtils.isEmpty(jobCodes)) {
return true;
}else {
if (Objects.isNull(loginOuid) || loginOuid == 0 || CollectionUtils.isEmpty(workspaceOuJob.getOuWorkspaceMap().get(loginOuid))){
return jobCodes.stream().anyMatch(jobCode -> workspaceJobMap.values().stream().anyMatch(jobCodeList -> jobCodeList.contains(jobCode)));
}else {
return workspaceOuJob.getOuWorkspaceMap().get(loginOuid).stream().anyMatch(w -> !CollectionUtils.isEmpty(workspaceJobMap.get(w)) && jobCodes.stream().anyMatch(jobCode -> workspaceJobMap.get(w).contains(jobCode)));
}
}
}
// 若配置了具体项目部
if (Objects.isNull(loginOuid) || loginOuid == 0L) {
// 加入的全部项目部与配置的项目部有交集
if (workspaceIds.stream().anyMatch(workspaceJobMap::containsKey)) {
if (CollectionUtils.isEmpty(jobCodes)) {
return true;
}
return workspaceIds.stream().anyMatch(workspaceId -> workspaceJobMap.get(workspaceId).stream().anyMatch(jobCodes::contains));
}
return false;
} else {
// 给定了具体登录单位
// 登录了具体的单位且以纯单位身份登录
if (CollectionUtils.isEmpty(workspaceOuJob.getOuWorkspaceMap().get(loginOuid))) {
return false;
}
// 以项目部下单位登录
// 加入的全部项目部与配置的项目部有交集
if (workspaceIds.stream().anyMatch(w -> workspaceOuJob.getOuWorkspaceMap().get(loginOuid).stream().anyMatch(w::equals))) {
if (CollectionUtils.isEmpty(jobCodes)) {
return true;
}
return workspaceIds.stream().anyMatch(workspaceId -> workspaceJobMap.get(workspaceId).stream().anyMatch(jobCodes::contains));
}
return false;
}
}
},
UNIT("UNIT", "按照企业") {
UNIT("UNIT", "按照单位") {
@Override
public boolean isDeliverRequired(List<Long> workspaceIds, List<Long> ouIds, List<String> jobCodes, JoinedWorkspaceOuJob workspaceOuJob) {
// 若workspaceIds和jobCodes都为空则表示不限制否则需要满足配置的workspaceIds和jobCodes与用户加入的workspaceJob的keyvalue均存在交集
public boolean isDeliverRequired(List<Long> workspaceIds, List<Long> ouIds, List<String> jobCodes,
Long loginWorkspaceId, Long loginOuid,
JoinedWorkspaceOuJob workspaceOuJob) {
Map<Long, List<String>> ouJobMap = workspaceOuJob.getOuJobMap();
return CollectionUtils.isEmpty(ouIds) ? CollectionUtils.isEmpty(jobCodes) || jobCodes.stream().anyMatch(jobCode -> ouJobMap.values().stream().flatMap(List::stream).distinct().collect(Collectors.toList()).contains(jobCode))
: ouIds.stream().anyMatch(ouId -> ouJobMap.get(ouId).stream().anyMatch(jobCodes::contains));
log.info("投放单位:{},投放岗位岗位:{},当前登录单位:{},用户加入单位及担任岗位:{}",
JSONUtil.toJsonStr(ouIds), JSONUtil.toJsonStr(jobCodes),
loginOuid,
JSONUtil.toJsonStr(ouJobMap));
// 判断配置的单位和岗位是否为空
if (CollectionUtils.isEmpty(ouIds)) {
// 若配置的单位为空即配置了全部单位
if (CollectionUtils.isEmpty(jobCodes)) {
// 若配置的岗位也为空即配置了所有岗位则不限制投放
return true;
} else {
// 若配置了具体岗位检查用户加入的所有单位下的岗位是否包含任一配置岗位
if (Objects.isNull(loginOuid) || loginOuid == 0L) {
return jobCodes.stream().anyMatch(jobCode -> ouJobMap.values().stream()
.flatMap(List::stream)
.distinct()
.collect(Collectors.toList())
.contains(jobCode));
} else {
return jobCodes.stream().anyMatch(jobCode -> ouJobMap.get(loginOuid).stream().anyMatch(jobCodes::contains));
}
}
}
// 若配置了具体单位
if (Objects.isNull(loginOuid) || loginOuid == 0L) {
// 若登录单位为空工人APP登录检查用户加入的单位是否与配置单位有交集
if (ouIds.stream().anyMatch(ouJobMap::containsKey)) {
if (CollectionUtils.isEmpty(jobCodes)) {
return true;
}
return ouIds.stream().anyMatch(o -> ouJobMap.get(o).stream().anyMatch(jobCodes::contains));
}
return false;
} else {
// 若登录单位不为空管理APP或CMS登录检查登录单位是否与配置单位有交集
if (!ouIds.contains(loginOuid)) {
return false;
}
if (CollectionUtils.isEmpty(jobCodes)) {
// 若配置了所有岗位由于登录单位已满足条件此时无需再检查岗位
return true;
} else {
// 若配置了具体岗位检查登录单位下担任的岗位是否包含任一配置岗位
return !CollectionUtils.isEmpty(ouJobMap.get(loginOuid)) && jobCodes.stream().anyMatch(jobCode -> ouJobMap.get(loginOuid).stream().anyMatch(jobCodes::contains));
}
}
}
};
@ -54,15 +158,19 @@ public enum MaterialTargetUserTypeEnum {
private final String desc;
/**
* 是否需要投放
* 根据目标人权类型确认是否需要投放
*
* @param workspaceIds 配置的投放项目部
* @param ouIds 配置的投放单位
* @param jobCodes 配置的投放岗位
* @param workspaceOuJob 用户参与的项目部和单位及其岗位
* @param workspaceIds 配置的投放项目部
* @param ouIds 配置的投放单位
* @param jobCodes 配置的投放岗位
* @param loginWorkspaceId 当前登录的项目部
* @param loginOuid 当前登录的单位
* @param workspaceOuJob 用户参与的项目部和单位及其岗位
* @return 是否需要投放
*/
public abstract boolean isDeliverRequired(List<Long> workspaceIds, List<Long> ouIds, List<String> jobCodes, JoinedWorkspaceOuJob workspaceOuJob);
public abstract boolean isDeliverRequired(List<Long> workspaceIds, List<Long> ouIds, List<String> jobCodes,
Long loginWorkspaceId, Long loginOuid,
JoinedWorkspaceOuJob workspaceOuJob);
public static MaterialTargetUserTypeEnum getByCode(String code) {
if (StringUtils.isEmpty(code)) {

View File

@ -17,9 +17,9 @@ import java.util.Arrays;
@AllArgsConstructor
public enum OpSystemTypeEnum {
ANDROID("Android", "安卓"),
ANDROID("ANDROID", "安卓"),
IOS("iOS", "苹果"),
IOS("IOS", "苹果"),
PC("PC", "电脑");

View File

@ -15,9 +15,9 @@ import java.util.Arrays;
@AllArgsConstructor
public enum RecodeTypeEnum {
BANNER("BANNER", "广告位操作类型"),
BANNER("BANNER", "广告"),
MATERIAL("MATERIAL", "素材操作类型"),
MATERIAL("MATERIAL", "素材"),
;
private final String type;

View File

@ -0,0 +1,53 @@
package cn.axzo.nanopart.api.request;
import cn.axzo.nanopart.api.enums.OpSystemTypeEnum;
import cn.axzo.nanopart.api.enums.PlatformTypeEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotNull;
/**
* @author chenwenjian
* @version 1.0
* @date 2024/4/12 10:15
*/
@Data
@Builder
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class CreateApplicationVersionReadLogReq {
/**
* 阅读人
*/
@NotNull(message = "阅读人不能为空")
private Long personId;
/**
* 版本id
*/
@NotNull(message = "版本记录id不能为空")
private Long versionId;
/**
* 版本号
*/
private String version;
/**
* 平台
* {@link PlatformTypeEnum}
*/
private PlatformTypeEnum platform;
/**
* 操作系统
* {@link OpSystemTypeEnum}
*/
private OpSystemTypeEnum opSystem;
}

View File

@ -2,7 +2,7 @@ package cn.axzo.nanopart.api.request;
import cn.axzo.nanopart.api.enums.OpSystemTypeEnum;
import cn.axzo.nanopart.api.enums.PlatformTypeEnum;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONArray;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -46,7 +46,7 @@ public class CreateApplicationVersionReq {
/**
* 发布时间
*/
@NotNull(message ="发版时间不能为空")
@NotNull(message = "发版时间不能为空")
private Date releaseTime;
/**
@ -57,11 +57,19 @@ public class CreateApplicationVersionReq {
/**
* 跳转地址
* eg: {
* "H5": "http://www.baidu.com/defalut.html"
* }
* eg:
* [
* {
* "label": "H5",
* "value": "http://www.baidu.com/defalut.html"
* },
* {
* "label": "iOS",
* "value": "http://www.baidu.com/defalut.html"
* }
* ]
*/
private JSONObject jumpUrl;
private JSONArray jumpUrl;
/**
* 更新后是否弹窗提醒0不提醒1提醒默认0

View File

@ -2,9 +2,9 @@ package cn.axzo.nanopart.api.request;
import cn.axzo.nanopart.api.dto.AspectRatioDto;
import cn.axzo.nanopart.api.enums.CarouselStatusEnum;
import cn.axzo.nanopart.api.enums.DisplayTimeTypeEnum;
import cn.axzo.nanopart.api.enums.PlatformTypeEnum;
import cn.axzo.nanopart.api.enums.StatusEnum;
import com.alibaba.fastjson.JSONArray;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -12,11 +12,10 @@ import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.time.LocalTime;
import java.util.List;
/**
* @author chenwenjian
@ -33,12 +32,14 @@ public class CreateBannerReq {
/**
* 广告位名称
*/
@Length(max = 50)
@NotBlank(message = "广告位名称不能为空")
private String name;
/**
* 广告位编码
*/
@Length(max = 8)
@Length(max = 20)
@NotBlank(message = "站点code不能为空")
private String code;
@ -52,7 +53,8 @@ public class CreateBannerReq {
/**
* 标签内置标签弹窗banner
*/
private JSONArray tag;
@NotEmpty(message = "标签不能为空")
private List<String> tag;
/**
* 轮播状态取值OPENED, CLOSED默认为ClOSED
@ -63,9 +65,6 @@ public class CreateBannerReq {
/**
* 最大轮播数量限制1-6
*/
@Min(value = 1, message = "轮播上线数量不能小于1")
@Max(value = 6, message = "轮播上限数量不能超过6")
@NotNull(message = "轮播上限数量不能为空")
private int maxCarouselLimit;
/**
@ -81,21 +80,23 @@ public class CreateBannerReq {
/**
* 播放时长0表示关闭状态范围1-120s
*/
@Min(value = 0)
@Max(value = 120)
private float playDuration;
/**
* 展示时间段类型取值全天ALL_DAY,上班时间WORKING休息时间BREAKING自定义CUSTOM默认全天
*/
@NotNull(message = "展示时间段类型不能为空")
private DisplayTimeTypeEnum displayTimeType = DisplayTimeTypeEnum.ALL_DAY;
/**
* 展示时间段-开始时间
*/
@NotNull(message = "展示时间段不能为空")
private LocalTime startTime;
private Long startTime;
/**
* 展示时间段-结束时间
*/
@NotNull(message = "展示时间段不能为空")
private LocalTime endTime;
private Long endTime;
/**
* 长宽比默认选择不限制即limit=false

View File

@ -0,0 +1,40 @@
package cn.axzo.nanopart.api.request;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.util.List;
/**
* @author chenwenjian
* @version 1.0
* @date 2024/4/11 10:38
*/
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class CreateMaterialPutLogReq {
/**
* 请求id
*/
private String requestId;
/**
* 用户personId
*/
private Long personId;
/**
* 广告位编码
*/
private String bannerCode;
/**
* 投放的素材id列表
*/
private List<Long> materialIds;
}

View File

@ -2,7 +2,9 @@ package cn.axzo.nanopart.api.request;
import cn.axzo.nanopart.api.enums.MaterialDisplayFrequencyTypeEnum;
import cn.axzo.nanopart.api.enums.MaterialTargetUserTypeEnum;
import cn.axzo.nanopart.api.enums.MaterialTypeEnum;
import cn.axzo.nanopart.api.enums.StatusEnum;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import lombok.Builder;
@ -33,24 +35,27 @@ public class CreateMaterialReq {
/**
* 广告位编码
*/
@Length(max = 150, message = "bannerCode长度不能超过150")
@NotBlank(message = "bannerCode不能为空")
private String bannerCode;
/**
* 名称
*/
@Length(max = 150, message = "素材名称长度不能超过150字")
@NotBlank(message = "素材名称不能为空")
private String name;
/**
* 有效期-开始时间
*/
@NotNull(message = "有效期-开始时间不能为空")
private Date startTime;
/**
* 有效期-结束时间
*/
@NotNull(message = "有效期-结束时间不能为空")
private Date endTime;
/**
@ -66,6 +71,11 @@ public class CreateMaterialReq {
*/
private StatusEnum status;
/**
* 素材类型取值IMAGE, VIDEO, AUDIO
*/
private MaterialTypeEnum materialType;
/**
* 占位图支持jpgjpegpnggif限定大小为200k
* eg: {
@ -91,27 +101,25 @@ public class CreateMaterialReq {
/**
* 跳转地址
* eg: {
* "APP": {
* "Android": "http://www.baidu.com/defalut.html",
* "iOS": "http://www.baidu.com/defalut.html",
* "h5": "http://www.baidu.com/defalut.html"
* eg:
* [
* {
* "label": "H5",
* "value": "http://www.baidu.com/defalut.html"
* },
* "Applet": {
* "applet": "http://www.baidu.com/defalut.html",
* "h5": "http://www.baidu.com/defalut.html"
* },
* "PC": {
* "h5": "http://www.baidu.com/defalut.html"
* }
* {
* "label": "iOS",
* "value": "http://www.baidu.com/defalut.html"
* }
* ]
*/
private JSONObject jumpUrl;
private JSONArray jumpUrl;
/**
* 目标投放对象类型呢取值ALL_USER, PROJECT, UNIT
* {@link MaterialTargetUserTypeEnum}
*/
@NotNull(message = "目标投放对象类型不能为空")
private MaterialTargetUserTypeEnum targetUserType;
/**
@ -130,9 +138,10 @@ public class CreateMaterialReq {
private List<Long> ouIds;
/**
* 单用户显示频次类型有效期内:VALIDITY_PERIOD,每天:EVERY_DAY,每周:EVERY_WEEK,每月:EVERY_MONTH
* 单用户显示频次类型不限:NO_LIMIT,有效期内:VALIDITY_PERIOD,每天:EVERY_DAY,每周:EVERY_WEEK,每月:EVERY_MONTH
* {@link MaterialDisplayFrequencyTypeEnum}
*/
@NotNull(message = "单用户显示频次类型不能为空")
private MaterialDisplayFrequencyTypeEnum displayFrequencyType;
/**

View File

@ -0,0 +1,41 @@
package cn.axzo.nanopart.api.request;
import cn.axzo.nanopart.api.enums.PlatformTypeEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
/**
* @author chenwenjian
* @version 1.0
* @date 2024/4/11 14:18
*/
@Data
@Builder
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class GetApplicationVersionReadLogReq {
/**
* 阅读人
*/
private Long personId;
/**
* 版本id
*/
private Long versionId;
/**
* 版本号
*/
private String version;
/**
* 平台
*/
private PlatformTypeEnum platform;
}

View File

@ -7,7 +7,6 @@ import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
import java.util.List;
/**
* @author chenwenjian
@ -30,24 +29,23 @@ public class ListMaterialByBannerCodeReq {
/**
* 当前登录人的personId
*/
// @NotNull(message = "personId不能为空")
private Long personId;
/**
* 项目部id用于筛选相关运营素材是否配置给了该项目部人员
* 当前登录项目部id用于筛选相关运营素材是否配置给了该项目部人员
*/
private List<Long> workspaceIds;
private Long workspaceId;
/**
* 单位id用于筛选相关运营素材是否配置给了该单位人员
* 当前登录单位id用于筛选相关运营素材是否配置给了该单位人员
*/
private List<Long> ouIds;
private Long ouId;
/**
* 岗位编码搭配{@code workspaceIds}{@code unitIds}使用
* 用于筛选相关运营素材是否配置给了指定项目部下指定岗位人员
* 或指定单位下指定岗位人员
*/
private List<String> jobCodes;
private String jobCode;
}

View File

@ -1,6 +1,6 @@
package cn.axzo.nanopart.api.request;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONArray;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -46,11 +46,18 @@ public class UpdateApplicationVersionReq {
/**
* 跳转地址
* eg: {
* "H5": "http://www.baidu.com/defalut.html"
* }
* eg: [
* {
* "label": "H5",
* "value": "http://www.baidu.com/defalut.html"
* },
* {
* "label": "iOS",
* "value": "http://www.baidu.com/defalut.html"
* }
* ]
*/
private JSONObject jumpUrl;
private JSONArray jumpUrl;
/**
* 更新后是否弹窗提醒0不提醒1提醒默认0

View File

@ -2,18 +2,17 @@ package cn.axzo.nanopart.api.request;
import cn.axzo.nanopart.api.dto.AspectRatioDto;
import cn.axzo.nanopart.api.enums.CarouselStatusEnum;
import cn.axzo.nanopart.api.enums.DisplayTimeTypeEnum;
import cn.axzo.nanopart.api.enums.StatusEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.time.LocalTime;
/**
* @author chenwenjian
@ -36,6 +35,7 @@ public class UpdateBannerReq {
/**
* 广告位名称
*/
@Length(max = 50)
@NotBlank(message = "广告位名称不能为空")
private String name;
@ -43,34 +43,43 @@ public class UpdateBannerReq {
* 轮播状态取值OPENED, CLOSED默认为ClOSED
* {@link CarouselStatusEnum}
*/
@NotNull(message = "轮播状态不能为空")
private CarouselStatusEnum carouselStatus;
/**
* 最大轮播数量限制1-6
*/
@Min(value = 1)
@Max(value = 6)
private int maxCarouselLimit;
/**
* 播放时长0表示关闭状态范围1-120s
*/
@Min(value = 0)
@Max(value = 120)
private float playDuration;
/**
* 展示时间段类型取值全天ALL_DAY,上班时间WORKING休息时间BREAKING自定义CUSTOM默认全天
*/
@NotNull(message = "展示时间段类型不能为空")
private DisplayTimeTypeEnum displayTimeType = DisplayTimeTypeEnum.ALL_DAY;
/**
* 展示时间段-开始时间
*/
@NotNull(message = "展示时间段不能为空")
private LocalTime startTime;
private Long startTime;
/**
* 展示时间段-结束时间
*/
@NotNull(message = "展示时间段不能为空")
private LocalTime endTime;
private Long endTime;
/**
* iOS适配版本搭配展示终端terminal为APP时使用
*/
private String iosVersion;
/**
* Android适配版本搭配展示终端terminal为APP时使用
*/
private String androidVersion;
/**
* 长宽比

View File

@ -1,14 +1,13 @@
package cn.axzo.nanopart.api.response;
import cn.axzo.nanopart.api.enums.CarouselStatusEnum;
import cn.axzo.nanopart.api.enums.DisplayTimeTypeEnum;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.time.LocalTime;
/**
* @author chenwenjian
* @version 1.0
@ -37,14 +36,19 @@ public class DetailBannerResp extends PageBannerResp {
*/
private float playDuration;
/**
* 展示时间段类型取值全天ALL_DAY,上班时间WORKING休息时间BREAKING自定义CUSTOM默认全天
*/
private DisplayTimeTypeEnum displayTimeType;
/**
* 展示时间段-开始时间
*/
private LocalTime startTime;
private Long startTime;
/**
* 展示时间段-结束时间
*/
private LocalTime endTime;
private Long endTime;
}

View File

@ -2,6 +2,7 @@ package cn.axzo.nanopart.api.response;
import cn.axzo.nanopart.api.enums.OpSystemTypeEnum;
import cn.axzo.nanopart.api.enums.PlatformTypeEnum;
import com.alibaba.fastjson.JSONArray;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -48,4 +49,25 @@ public class GetVersionUpdateRemindContentResp {
* 版本描述
*/
private String description;
/**
* 跳转地址
* eg:
* [
* {
* "label": "H5",
* "value": "http://www.baidu.com/defalut.html"
* },
* {
* "label": "iOS",
* "value": "http://www.baidu.com/defalut.html"
* }
* ]
*/
private JSONArray jumpUrl;
/**
* 图片地址url
*/
private String imageUrl;
}

View File

@ -3,6 +3,8 @@ package cn.axzo.nanopart.api.response;
import cn.axzo.nanopart.api.enums.MaterialDisplayFrequencyTypeEnum;
import cn.axzo.nanopart.api.enums.MaterialTargetUserTypeEnum;
import cn.axzo.nanopart.api.enums.MaterialTypeEnum;
import cn.axzo.nanopart.api.enums.PlatformTypeEnum;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import lombok.Builder;
@ -11,6 +13,7 @@ import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.util.Date;
import java.util.List;
/**
@ -27,7 +30,7 @@ import java.util.List;
public class MaterialResp extends PageMaterialResp {
/**
* 素材类型取值IMAGE, VIDEO, APPLET
* 素材类型取值IMAGE, VIDEO, AUDIO
*/
private MaterialTypeEnum materialType;
@ -53,22 +56,19 @@ public class MaterialResp extends PageMaterialResp {
/**
* 跳转地址
* eg: {
* "APP": {
* "Android": "http://www.baidu.com/defalut.html",
* "iOS": "http://www.baidu.com/defalut.html",
* "h5": "http://www.baidu.com/defalut.html"
* },
* "Applet": {
* "applet": "http://www.baidu.com/defalut.html",
* "h5": "http://www.baidu.com/defalut.html"
* },
* "PC": {
* "h5": "http://www.baidu.com/defalut.html"
* }
* }
* eg:
* [
* {
* "label": "H5",
* "value": "http://www.baidu.com/defalut.html"
* },
* {
* "label": "iOS",
* "value": "http://www.baidu.com/defalut.html"
* }
* ]
*/
private JSONObject jumpUrl;
private JSONArray jumpUrl;
/**
* 目标投放对象类型呢取值ALL_USER, PROJECT, UNIT
@ -108,9 +108,43 @@ public class MaterialResp extends PageMaterialResp {
*/
private Long createBy;
/**
* 创建人姓名
*/
private String createByName;
/**
* 更新人
*/
private Long updateBy;
/**
* 更新人姓名
*/
private String updateByName;
/**
* 所属终端取值CMS:安心筑CMSCMCMP安心筑工人端APP安心筑管理端APP
* <p>
* 素材
* </p>
* {@link PlatformTypeEnum}
*/
private PlatformTypeEnum terminal;
/**
* 创建时间
*/
private Date createAt;
/**
* 目标投放项目部或企业
*/
private String targetWorkspaceOrUnit;
/**
* 目标投放岗位
*/
private String targetUserJobCode;
}

View File

@ -2,7 +2,7 @@ package cn.axzo.nanopart.api.response;
import cn.axzo.nanopart.api.enums.OpSystemTypeEnum;
import cn.axzo.nanopart.api.enums.PlatformTypeEnum;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONArray;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -23,6 +23,8 @@ import java.util.Date;
@AllArgsConstructor
public class PageApplicationVersionResp {
private Long id;
/**
* 版本号
*/
@ -52,11 +54,19 @@ public class PageApplicationVersionResp {
/**
* 跳转地址
* eg: {
* "H5": "http://www.baidu.com/defalut.html"
* }
* eg:
* [
* {
* "label": "H5",
* "value": "http://www.baidu.com/defalut.html"
* },
* {
* "label": "iOS",
* "value": "http://www.baidu.com/defalut.html"
* }
* ]
*/
private JSONObject jumpUrl;
private JSONArray jumpUrl;
/**
* 更新后是否弹窗提醒0不提醒1提醒默认0
@ -71,5 +81,5 @@ public class PageApplicationVersionResp {
/**
* 更新人
*/
private Long updateBy;
private String updateBy;
}

View File

@ -44,6 +44,11 @@ public class PageBannerOperationLogResp {
*/
private Long updateBy;
/**
* 操作人名称
*/
private String updateByName;
/**
* 操作类型
*/
@ -58,4 +63,14 @@ public class PageBannerOperationLogResp {
* 旧数据
*/
private JSONObject oldData;
/**
* 操作类型
*/
private String operationTypeDesc;
/**
* 操作内容
*/
private String operationContent;
}

View File

@ -74,5 +74,10 @@
<groupId>cn.axzo.maokai</groupId>
<artifactId>maokai-api</artifactId>
</dependency>
<dependency>
<groupId>cn.axzo.basics</groupId>
<artifactId>basics-profiles-api</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,32 @@
package cn.axzo.nanopart.server.common;
import cn.axzo.framework.domain.ServiceException;
import cn.axzo.nanopart.api.constant.NanopartConstant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
/**
* TODO 待统一优化需要统一版本号命名规则
* 版本号规则校验器
*
* @author chenwenjian
* @version 1.0
* @date 2024/4/17 20:21
*/
@Slf4j
public class ApplicationVersionValidator {
/**
* 对给定版本号进行简单正则校验
*
* @param version 版本号
*/
public static void checkVersionSimple(String version) {
if (StringUtils.isNotBlank(version)) {
if (!version.matches(NanopartConstant.VERSION_SIMPLE_PATTERN)) {
log.warn("版本号校验不通过version = {}",version);
throw new ServiceException("请输入正确的版本号");
}
}
}
}

View File

@ -1,57 +1,65 @@
// package cn.axzo.nanopart.server.controller;
//
// import cn.axzo.framework.domain.web.result.ApiPageResult;
// import cn.axzo.framework.domain.web.result.ApiResult;
// import cn.axzo.nanopart.api.ApplicationVersionApi;
// import cn.axzo.nanopart.api.request.CreateApplicationVersionReq;
// import cn.axzo.nanopart.api.request.GetVersionUpdateRemindContentReq;
// import cn.axzo.nanopart.api.request.PageApplicationVersionReq;
// import cn.axzo.nanopart.api.request.UpdateApplicationVersionReq;
// import cn.axzo.nanopart.api.response.GetVersionUpdateRemindContentResp;
// import cn.axzo.nanopart.api.response.PageApplicationVersionResp;
// import cn.axzo.nanopart.server.service.ApplicationVersionService;
// import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
// import lombok.RequiredArgsConstructor;
// import lombok.extern.slf4j.Slf4j;
// import org.springframework.web.bind.annotation.RestController;
//
// /**
// * @author chenwenjian
// * @version 1.0
// * @date 2024/4/3 16:39
// */
// @Slf4j
// @RestController
// @RequiredArgsConstructor
// public class ApplicationVersionController implements ApplicationVersionApi {
//
// private final ApplicationVersionService applicationVersionService;
//
// @Override
// public ApiResult<Long> create(CreateApplicationVersionReq req) {
// return ApiResult.ok(applicationVersionService.create(req));
// }
//
// @Override
// public ApiResult<Void> update(UpdateApplicationVersionReq req) {
// applicationVersionService.update(req);
// return ApiResult.ok();
// }
//
// @Override
// public ApiResult<Void> deleteById(Long id, Long personId) {
// applicationVersionService.deleteById(id, personId);
// return ApiResult.ok();
// }
//
// @Override
// public ApiPageResult<PageApplicationVersionResp> page(PageApplicationVersionReq req) {
// Page<PageApplicationVersionResp> pageData = applicationVersionService.page(req);
// return ApiPageResult.ok(pageData);
// }
//
// @Override
// public ApiResult<GetVersionUpdateRemindContentResp> getVersionUpdateRemindContent(GetVersionUpdateRemindContentReq req) {
// return ApiResult.ok(applicationVersionService.getVersionUpdateRemindContent(req));
// }
// }
package cn.axzo.nanopart.server.controller;
import cn.axzo.framework.domain.ServiceException;
import cn.axzo.framework.domain.web.result.ApiPageResult;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.nanopart.api.ApplicationVersionApi;
import cn.axzo.nanopart.api.request.CreateApplicationVersionReq;
import cn.axzo.nanopart.api.request.GetVersionUpdateRemindContentReq;
import cn.axzo.nanopart.api.request.PageApplicationVersionReq;
import cn.axzo.nanopart.api.request.UpdateApplicationVersionReq;
import cn.axzo.nanopart.api.response.GetVersionUpdateRemindContentResp;
import cn.axzo.nanopart.api.response.PageApplicationVersionResp;
import cn.axzo.nanopart.server.service.ApplicationVersionService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RestController;
import java.util.Objects;
/**
* 版本记录操作
*
* @author chenwenjian
* @version 1.0
* @date 2024/4/3 16:39
*/
@Slf4j
@RestController
@RequiredArgsConstructor
public class ApplicationVersionController implements ApplicationVersionApi {
private final ApplicationVersionService applicationVersionService;
@Override
public ApiResult<Long> create(CreateApplicationVersionReq req) {
return ApiResult.ok(applicationVersionService.create(req));
}
@Override
public ApiResult<Void> update(UpdateApplicationVersionReq req) {
applicationVersionService.update(req);
return ApiResult.ok();
}
@Override
public ApiResult<Void> deleteById(Long id, Long personId) {
applicationVersionService.deleteById(id, personId);
return ApiResult.ok();
}
@Override
public ApiPageResult<PageApplicationVersionResp> page(PageApplicationVersionReq req) {
Page<PageApplicationVersionResp> pageData = applicationVersionService.page(req);
return ApiPageResult.ok(pageData);
}
@Override
public ApiResult<GetVersionUpdateRemindContentResp> getVersionUpdateRemindContent(GetVersionUpdateRemindContentReq req) {
if (Objects.isNull(req.getPersonId()) || req.getPersonId() == 0) {
throw new ServiceException("personId不能为空");
}
return ApiResult.ok(applicationVersionService.getVersionUpdateRemindContent(req));
}
}

View File

@ -1,58 +1,60 @@
// package cn.axzo.nanopart.server.controller;
//
// import cn.axzo.framework.domain.web.result.ApiPageResult;
// import cn.axzo.framework.domain.web.result.ApiResult;
// import cn.axzo.nanopart.api.BannerApi;
// import cn.axzo.nanopart.api.request.CreateBannerReq;
// import cn.axzo.nanopart.api.request.DetailBannerReq;
// import cn.axzo.nanopart.api.request.PageBannerReq;
// import cn.axzo.nanopart.api.request.UpdateBannerReq;
// import cn.axzo.nanopart.api.request.UpdateStatusReq;
// import cn.axzo.nanopart.api.response.DetailBannerResp;
// import cn.axzo.nanopart.api.response.PageBannerResp;
// import cn.axzo.nanopart.server.service.BannerService;
// import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
// import lombok.RequiredArgsConstructor;
// import lombok.extern.slf4j.Slf4j;
// import org.springframework.web.bind.annotation.RestController;
//
// /**
// * @author chenwenjian
// * @version 1.0
// * @date 2024/4/3 16:30
// */
// @Slf4j
// @RestController
// @RequiredArgsConstructor
// public class BannerController implements BannerApi {
//
// private final BannerService bannerService;
//
// @Override
// public ApiPageResult<PageBannerResp> page(PageBannerReq req) {
// Page<PageBannerResp> pageData = bannerService.page(req);
// return ApiPageResult.ok(pageData);
// }
//
// @Override
// public ApiResult<Long> create(CreateBannerReq req) {
// return ApiResult.ok(bannerService.create(req));
// }
//
// @Override
// public ApiResult<Void> update(UpdateBannerReq req) {
// bannerService.update(req);
// return ApiResult.ok();
// }
//
// @Override
// public ApiResult<Void> updateStatus(UpdateStatusReq req) {
// bannerService.updateStatus(req);
// return ApiResult.ok();
// }
//
// @Override
// public ApiResult<DetailBannerResp> detail(DetailBannerReq req) {
// return ApiResult.ok(bannerService.detail(req));
// }
// }
package cn.axzo.nanopart.server.controller;
import cn.axzo.framework.domain.web.result.ApiPageResult;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.nanopart.api.BannerApi;
import cn.axzo.nanopart.api.request.CreateBannerReq;
import cn.axzo.nanopart.api.request.DetailBannerReq;
import cn.axzo.nanopart.api.request.PageBannerReq;
import cn.axzo.nanopart.api.request.UpdateBannerReq;
import cn.axzo.nanopart.api.request.UpdateStatusReq;
import cn.axzo.nanopart.api.response.DetailBannerResp;
import cn.axzo.nanopart.api.response.PageBannerResp;
import cn.axzo.nanopart.server.service.BannerService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RestController;
/**
* 广告位操作
*
* @author chenwenjian
* @version 1.0
* @date 2024/4/3 16:30
*/
@Slf4j
@RestController
@RequiredArgsConstructor
public class BannerController implements BannerApi {
private final BannerService bannerService;
@Override
public ApiPageResult<PageBannerResp> page(PageBannerReq req) {
Page<PageBannerResp> pageData = bannerService.page(req);
return ApiPageResult.ok(pageData);
}
@Override
public ApiResult<Long> create(CreateBannerReq req) {
return ApiResult.ok(bannerService.create(req));
}
@Override
public ApiResult<Void> update(UpdateBannerReq req) {
bannerService.update(req);
return ApiResult.ok();
}
@Override
public ApiResult<Void> updateStatus(UpdateStatusReq req) {
bannerService.updateStatus(req);
return ApiResult.ok();
}
@Override
public ApiResult<DetailBannerResp> detail(DetailBannerReq req) {
return ApiResult.ok(bannerService.detail(req));
}
}

View File

@ -1,24 +1,38 @@
// package cn.axzo.nanopart.server.controller;
//
// import cn.axzo.framework.domain.web.result.ApiPageResult;
// import cn.axzo.nanopart.api.BannerOperationLogApi;
// import cn.axzo.nanopart.api.request.PageBannerOperationLogReq;
// import cn.axzo.nanopart.api.response.PageBannerOperationLogResp;
// import lombok.RequiredArgsConstructor;
// import lombok.extern.slf4j.Slf4j;
// import org.springframework.web.bind.annotation.RestController;
//
// /**
// * @author chenwenjian
// * @version 1.0
// * @date 2024/4/3 16:40
// */
// @Slf4j
// @RestController
// @RequiredArgsConstructor
// public class BannerOperationLogController implements BannerOperationLogApi {
// @Override
// public ApiPageResult<PageBannerOperationLogResp> page(PageBannerOperationLogReq req) {
// return null;
// }
// }
package cn.axzo.nanopart.server.controller;
import cn.axzo.framework.domain.web.result.ApiPageResult;
import cn.axzo.nanopart.api.BannerOperationLogApi;
import cn.axzo.nanopart.api.request.PageBannerOperationLogReq;
import cn.axzo.nanopart.api.response.PageBannerOperationLogResp;
import cn.axzo.nanopart.server.service.BannerOperationLogService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RestController;
/**
* 广告位和素材操作日志
*
* @author chenwenjian
* @version 1.0
* @date 2024/4/3 16:40
*/
@Slf4j
@RestController
@RequiredArgsConstructor
public class BannerOperationLogController implements BannerOperationLogApi {
private final BannerOperationLogService bannerOperationLogService;
/**
* 分页查询
*
* @param req {@link PageBannerOperationLogReq}
* @return 按照时间倒序排序后的列表
*/
@Override
public ApiPageResult<PageBannerOperationLogResp> page(PageBannerOperationLogReq req) {
Page<PageBannerOperationLogResp> pageData = bannerOperationLogService.page(req);
return ApiPageResult.ok(pageData);
}
}

View File

@ -1,17 +1,31 @@
package cn.axzo.nanopart.server.controller;
import cn.axzo.framework.domain.ServiceException;
import cn.axzo.framework.domain.web.result.ApiPageResult;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.nanopart.api.MaterialApi;
import cn.axzo.nanopart.api.constant.NanopartConstant;
import cn.axzo.nanopart.api.request.CreateMaterialReq;
import cn.axzo.nanopart.api.request.DetailMaterialReq;
import cn.axzo.nanopart.api.request.ListMaterialByBannerCodeReq;
import cn.axzo.nanopart.api.request.PageMaterialReq;
import cn.axzo.nanopart.api.request.UpdateMaterialReq;
import cn.axzo.nanopart.api.request.UpdateStatusReq;
import cn.axzo.nanopart.api.response.MaterialResp;
import cn.axzo.nanopart.api.response.PageMaterialResp;
import cn.axzo.nanopart.server.service.MaterialService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RestController;
import java.util.Collections;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Objects;
/**
* 素材操作
*
* @author chenwenjian
* @version 1.0
* @date 2024/4/3 16:31
@ -21,38 +35,56 @@ import java.util.List;
@RequiredArgsConstructor
public class MaterialController implements MaterialApi {
// private final MaterialService materialService;
//
// @Override
// public ApiPageResult<PageMaterialResp> page(PageMaterialReq req) {
// Page<PageMaterialResp> pageData = materialService.page(req);
// return ApiPageResult.ok(pageData);
// }
//
// @Override
// public ApiResult<Long> create(CreateMaterialReq req) {
// return ApiResult.ok(materialService.create(req));
// }
//
// @Override
// public ApiResult<Void> update(UpdateMaterialReq req) {
// materialService.update(req);
// return ApiResult.ok();
// }
//
// @Override
// public ApiResult<Void> updateStatus(UpdateStatusReq req) {
// materialService.updateStatus(req);
// return ApiResult.ok();
// }
//
// @Override
// public ApiResult<MaterialResp> detail(DetailMaterialReq req) {
// return ApiResult.ok(materialService.detail(req));
// }
private final MaterialService materialService;
private final HttpServletRequest request;
@Override
public ApiPageResult<PageMaterialResp> page(PageMaterialReq req) {
Page<PageMaterialResp> pageData = materialService.page(req);
return ApiPageResult.ok(pageData);
}
@Override
public ApiResult<Long> create(CreateMaterialReq req) {
return ApiResult.ok(materialService.create(req));
}
@Override
public ApiResult<Void> update(UpdateMaterialReq req) {
materialService.update(req);
return ApiResult.ok();
}
@Override
public ApiResult<Void> updateStatus(UpdateStatusReq req) {
materialService.updateStatus(req);
return ApiResult.ok();
}
@Override
public ApiResult<MaterialResp> detail(DetailMaterialReq req) {
return ApiResult.ok(materialService.detail(req));
}
/**
* 根据广告位编码bannerCode查询素材
* <p>
* 1. 通过广告位code获取该广告位下的所有素材默认查询上架状态且在有效期范围内的素材
* 2. 根据广告位投放人群进行过滤对于cms/cmp需要根据当前登录人登录企业情况进行过滤
* 3. 根据广告位投放规则频次进行过滤
* 4. 将最终的素材根据优先级priority升序创建时间createAt降序排序
* </p>
*
* @param req {@link ListMaterialByBannerCodeReq}
* @return 根据优先级priority升序创建时间createAt降序排序后的列表
*/
@Override
public ApiResult<List<MaterialResp>> listMaterialByBannerCode(ListMaterialByBannerCodeReq req) {
return ApiResult.ok(Collections.emptyList());
String traceId = request.getHeader(NanopartConstant.CONTEXT_TRACE_ID);
if (Objects.isNull(req.getPersonId()) || req.getPersonId() == 0L) {
throw new ServiceException("personId不能为空");
}
return ApiResult.ok(materialService.listMaterialByBannerCode(req, traceId));
}
}

View File

@ -3,6 +3,7 @@ package cn.axzo.nanopart.server.domain;
import cn.axzo.nanopart.api.enums.OpSystemTypeEnum;
import cn.axzo.nanopart.api.enums.PlatformTypeEnum;
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
@ -64,12 +65,20 @@ public class ApplicationVersion extends BaseEntity<ApplicationVersion> {
/**
* 跳转地址
* eg: {
* "H5": "http://www.baidu.com/defalut.html"
* }
* eg:
* [
* {
* "label": "H5",
* "value": "http://www.baidu.com/defalut.html"
* },
* {
* "label": "iOS",
* "value": "http://www.baidu.com/defalut.html"
* }
* ]
*/
@TableField(value = "jump_url", typeHandler = FastjsonTypeHandler.class)
private JSONObject jumpUrl;
private JSONArray jumpUrl;
/**
* 更新后是否弹窗提醒0不提醒1提醒默认0

View File

@ -0,0 +1,70 @@
package cn.axzo.nanopart.server.domain;
import cn.axzo.nanopart.api.enums.OpSystemTypeEnum;
import cn.axzo.nanopart.api.enums.PlatformTypeEnum;
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
/**
* @author chenwenjian
* @version 1.0
* @date 2024/4/11 14:10
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
@TableName(value = "application_version_read_log", autoResultMap = true)
public class ApplicationVersionReadLog extends BaseEntity<ApplicationVersionReadLog> {
/**
* 阅读人
*/
@TableField(value = "person_id")
private Long personId;
/**
* 版本id
*/
@TableField(value = "version_id")
private Long versionId;
/**
* 版本号
*/
@TableField(value = "version")
private String version;
/**
* 平台
*/
@TableField(value = "platform")
private PlatformTypeEnum platform;
/**
* 操作系统
* {@link OpSystemTypeEnum}
*/
@TableField(value = "op_system")
private OpSystemTypeEnum opSystem;
/**
* 创建人
*/
@TableField(value = "create_by")
private Long createBy;
/**
* 更新人
*/
@TableField(value = "update_by")
private Long updateBy;
}

View File

@ -1,8 +1,9 @@
package cn.axzo.nanopart.server.domain;
import cn.axzo.nanopart.api.enums.StatusEnum;
import cn.axzo.nanopart.api.enums.CarouselStatusEnum;
import cn.axzo.nanopart.api.enums.DisplayTimeTypeEnum;
import cn.axzo.nanopart.api.enums.PlatformTypeEnum;
import cn.axzo.nanopart.api.enums.StatusEnum;
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
@ -17,7 +18,7 @@ import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.time.LocalTime;
import java.sql.Time;
/**
* 运营广告位
@ -66,17 +67,23 @@ public class Banner extends BaseEntity<Banner> {
@TableField(value = "status")
private StatusEnum status;
/**
* 展示时间段类型取值全天ALL_DAY,上班时间WORKING休息时间BREAKING自定义CUSTOM
*/
@TableField(value = "display_time_type")
private DisplayTimeTypeEnum displayTimeType;
/**
* 展示时间段-开始时间
*/
@TableField(value = "start_time")
private LocalTime startTime;
private Time startTime;
/**
* 展示时间段-结束时间
*/
@TableField(value = "end_time")
private LocalTime endTime;
private Time endTime;
/**
* 轮播状态取值OPENED, CLOSED

View File

@ -6,6 +6,7 @@ import cn.axzo.nanopart.api.enums.MaterialTypeEnum;
import cn.axzo.nanopart.api.enums.StatusEnum;
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
import cn.axzo.pokonyan.config.mybatisplus.type.LongListTypeHandler;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
@ -72,7 +73,7 @@ public class Material extends BaseEntity<Material> {
private StatusEnum status;
/**
* 素材类型取值IMAGE, VIDEO, APPLET
* 素材类型取值IMAGE, VIDEO, AUDIO
*/
@TableField(value = "material_type")
private MaterialTypeEnum materialType;
@ -103,23 +104,20 @@ public class Material extends BaseEntity<Material> {
/**
* 跳转地址
* eg: {
* "APP": {
* "Android": "http://www.baidu.com/defalut.html",
* "iOS": "http://www.baidu.com/defalut.html",
* "h5": "http://www.baidu.com/defalut.html"
* },
* "Applet": {
* "applet": "http://www.baidu.com/defalut.html",
* "h5": "http://www.baidu.com/defalut.html"
* },
* "PC": {
* "h5": "http://www.baidu.com/defalut.html"
* }
* }
* eg:
* [
* {
* "label": "H5",
* "value": "http://www.baidu.com/defalut.html"
* },
* {
* "label": "iOS",
* "value": "http://www.baidu.com/defalut.html"
* }
* ]
*/
@TableField(value = "jump_url", typeHandler = FastjsonTypeHandler.class)
private JSONObject jumpUrl;
private JSONArray jumpUrl;
/**
* 目标投放对象类型呢取值ALL_USER, PROJECT, UNIT

View File

@ -0,0 +1,53 @@
package cn.axzo.nanopart.server.domain;
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
import cn.axzo.pokonyan.config.mybatisplus.type.LongListTypeHandler;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.util.List;
/**
* 素材投放日志记录
*
* @author chenwenjian
* @version 1.0
* @date 2024/4/10 18:36
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
@TableName(value = "material_put_log", autoResultMap = true)
public class MaterialPutLog extends BaseEntity<MaterialPutLog> {
/**
* 请求id
*/
@TableField(value = "request_id")
private String requestId;
/**
* 用户personId
*/
@TableField(value = "person_id")
private Long personId;
/**
* 广告位编码
*/
@TableField(value = "banner_code")
private String bannerCode;
/**
* 投放的素材id列表
*/
@TableField(value = "material_ids", typeHandler = LongListTypeHandler.class)
private List<Long> materialIds;
}

View File

@ -0,0 +1,14 @@
package cn.axzo.nanopart.server.mapper;
import cn.axzo.nanopart.server.domain.ApplicationVersionReadLog;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* @author chenwenjian
* @version 1.0
* @date 2024/4/11 14:14
*/
@Mapper
public interface ApplicationVersionReadLogDao extends BaseMapper<ApplicationVersionReadLog> {
}

View File

@ -0,0 +1,14 @@
package cn.axzo.nanopart.server.mapper;
import cn.axzo.nanopart.server.domain.MaterialPutLog;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* @author chenwenjian
* @version 1.0
* @date 2024/4/10 18:40
*/
@Mapper
public interface MaterialPutLogDao extends BaseMapper<MaterialPutLog> {
}

View File

@ -0,0 +1,63 @@
package cn.axzo.nanopart.server.rpc;
import cn.axzo.basics.profiles.api.UserProfileServiceApi;
import cn.axzo.basics.profiles.dto.basic.PersonProfileDto;
import cn.azxo.framework.common.logger.MethodAroundLog;
import cn.azxo.framework.common.model.CommonResponse;
import cn.hutool.core.collection.CollectionUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
/**
* @author chenwenjian
* @version 1.0
* @date 2024/4/17 19:39
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class ProfileGateway {
private final UserProfileServiceApi userProfileServiceApi;
/**
* 通过personId获取用户档案
*
* @param personId
* @return
*/
@MethodAroundLog(target = "pudge", source = "nanopart", value = "获取用户档案")
public PersonProfileDto getProfile(Long personId) {
if (Objects.isNull(personId)) {
return null;
}
CommonResponse<PersonProfileDto> personProfile = userProfileServiceApi.getPersonProfile(personId);
if (Objects.nonNull(personProfile) && personProfile.getCode() == 200) {
return personProfile.getData();
}
return null;
}
/**
* 通过personId获取用户档案
*
* @param personIds
* @return
*/
@MethodAroundLog(target = "pudge", source = "nanopart", value = "获取用户档案")
public List<PersonProfileDto> getProfiles(List<Long> personIds) {
if (CollectionUtil.isEmpty(personIds)) {
return Collections.emptyList();
}
CommonResponse<List<PersonProfileDto>> personProfiles = userProfileServiceApi.getPersonProfiles(personIds);
if (Objects.nonNull(personProfiles) && personProfiles.getCode() == 200) {
return personProfiles.getData();
}
return Collections.emptyList();
}
}

View File

@ -0,0 +1,16 @@
package cn.axzo.nanopart.server.service;
import cn.axzo.nanopart.api.request.CreateApplicationVersionReadLogReq;
import cn.axzo.nanopart.server.domain.ApplicationVersionReadLog;
/**
* @author chenwenjian
* @version 1.0
* @date 2024/4/11 14:15
*/
public interface ApplicationVersionReadLogService {
Long create(CreateApplicationVersionReadLogReq req);
ApplicationVersionReadLog getByIdWithPersonId(Long personId, Long id);
}

View File

@ -23,4 +23,5 @@ public interface ApplicationVersionService {
Page<PageApplicationVersionResp> page(PageApplicationVersionReq req);
GetVersionUpdateRemindContentResp getVersionUpdateRemindContent(GetVersionUpdateRemindContentReq req);
}

View File

@ -1,6 +1,9 @@
package cn.axzo.nanopart.server.service;
import cn.axzo.nanopart.api.request.CreateBannerOperationLogReq;
import cn.axzo.nanopart.api.request.PageBannerOperationLogReq;
import cn.axzo.nanopart.api.response.PageBannerOperationLogResp;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
/**
* @author chenwenjian
@ -10,4 +13,6 @@ import cn.axzo.nanopart.api.request.CreateBannerOperationLogReq;
public interface BannerOperationLogService {
Long create(CreateBannerOperationLogReq req);
Page<PageBannerOperationLogResp> page(PageBannerOperationLogReq req);
}

View File

@ -0,0 +1,13 @@
package cn.axzo.nanopart.server.service;
import cn.axzo.nanopart.api.request.CreateMaterialPutLogReq;
/**
* @author chenwenjian
* @version 1.0
* @date 2024/4/10 18:41
*/
public interface MaterialPutLogService {
Long create(CreateMaterialPutLogReq req);
}

View File

@ -28,7 +28,7 @@ public interface MaterialService {
* @param req {@link ListMaterialByBannerCodeReq}
* @return 根据优先级priority升序创建时间createAt降序排序后的列表
*/
List<MaterialResp> listMaterialByBannerCode(ListMaterialByBannerCodeReq req);
List<MaterialResp> listMaterialByBannerCode(ListMaterialByBannerCodeReq req,String traceId);
Page<PageMaterialResp> page(PageMaterialReq req);

View File

@ -0,0 +1,39 @@
package cn.axzo.nanopart.server.service.impl;
import cn.axzo.nanopart.api.request.CreateApplicationVersionReadLogReq;
import cn.axzo.nanopart.server.domain.ApplicationVersionReadLog;
import cn.axzo.nanopart.server.mapper.ApplicationVersionReadLogDao;
import cn.axzo.nanopart.server.service.ApplicationVersionReadLogService;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @author chenwenjian
* @version 1.0
* @date 2024/4/11 14:15
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class ApplicationVersionReadLogServiceImpl extends ServiceImpl<ApplicationVersionReadLogDao, ApplicationVersionReadLog> implements ApplicationVersionReadLogService {
@Override
public Long create(CreateApplicationVersionReadLogReq req) {
ApplicationVersionReadLog versionReadLog = BeanUtil.copyProperties(req, ApplicationVersionReadLog.class);
save(versionReadLog);
return versionReadLog.getId();
}
@Override
public ApplicationVersionReadLog getByIdWithPersonId(Long personId, Long id) {
return lambdaQuery()
.eq(ApplicationVersionReadLog::getIsDelete, 0)
.eq(ApplicationVersionReadLog::getPersonId, personId)
.eq(ApplicationVersionReadLog::getVersionId, id)
.last("limit 1")
.one();
}
}

View File

@ -1,19 +1,43 @@
package cn.axzo.nanopart.server.service.impl;
import cn.axzo.basics.common.BeanMapper;
import cn.axzo.basics.profiles.dto.basic.BasicDto;
import cn.axzo.basics.profiles.dto.basic.PersonProfileDto;
import cn.axzo.framework.domain.ServiceException;
import cn.axzo.nanopart.api.enums.PlatformTypeEnum;
import cn.axzo.nanopart.api.request.CreateApplicationVersionReadLogReq;
import cn.axzo.nanopart.api.request.CreateApplicationVersionReq;
import cn.axzo.nanopart.api.request.GetVersionUpdateRemindContentReq;
import cn.axzo.nanopart.api.request.PageApplicationVersionReq;
import cn.axzo.nanopart.api.request.UpdateApplicationVersionReq;
import cn.axzo.nanopart.api.response.GetVersionUpdateRemindContentResp;
import cn.axzo.nanopart.api.response.PageApplicationVersionResp;
import cn.axzo.nanopart.server.mapper.ApplicationVersionDao;
import cn.axzo.nanopart.server.domain.ApplicationVersion;
import cn.axzo.nanopart.server.domain.ApplicationVersionReadLog;
import cn.axzo.nanopart.server.mapper.ApplicationVersionDao;
import cn.axzo.nanopart.server.rpc.ProfileGateway;
import cn.axzo.nanopart.server.service.ApplicationVersionReadLogService;
import cn.axzo.nanopart.server.service.ApplicationVersionService;
import cn.axzo.pokonyan.dao.converter.PageConverter;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* @author chenwenjian
@ -22,31 +46,188 @@ import org.springframework.stereotype.Service;
*/
@Slf4j
@Service
@RefreshScope
@RequiredArgsConstructor
public class ApplicationVersionServiceImpl extends ServiceImpl<ApplicationVersionDao, ApplicationVersion> implements ApplicationVersionService {
private final ApplicationVersionReadLogService applicationVersionReadLogService;
private final ProfileGateway profileGateway;
@Value("${versionRemindImg.app}")
private String appVersionRemindImage;
@Value("${versionRemindImg.cms}")
private String cmsVersionRemindImage;
/**
* 创建版本信息
*
* @param req {@link CreateApplicationVersionReq}
* @return 版本信息id
*/
@Override
public Long create(CreateApplicationVersionReq req) {
return null;
checkDuplicateVersion(req);
ApplicationVersion version = BeanUtil.copyProperties(req, ApplicationVersion.class);
save(version);
return version.getId();
}
/**
* 更新版本信息
*
* @param req {@link UpdateApplicationVersionReq}
*/
@Override
public void update(UpdateApplicationVersionReq req) {
LambdaUpdateWrapper<ApplicationVersion> lambdaUpdateWrapper = buildLambdaUpdateWrapper(req);
update(lambdaUpdateWrapper);
}
/**
* 删除版本信息记录
*
* @param id 版本记录id
* @param personId 操作人personId
*/
@Override
public void deleteById(Long id, Long personId) {
update(buildDeleteLambdaUpdateWrapper(id, personId));
}
/**
* 分页查询版本信息
*
* @param req {@link PageApplicationVersionReq}
* @return 按照版本记录倒排的记录列表
*/
@Override
public Page<PageApplicationVersionResp> page(PageApplicationVersionReq req) {
LambdaQueryWrapper<ApplicationVersion> lambdaQueryWrapper = buildPageLambdaQueryWrapper(req);
Page<ApplicationVersion> versionPage = page(new Page<>(req.getPageNumber(), req.getPageSize()), lambdaQueryWrapper);
if (Objects.isNull(versionPage) || versionPage.getTotal() == 0) {
return new Page<>();
}
List<Long> personIds = versionPage.getRecords().stream()
.map(ApplicationVersion::getUpdateBy)
.distinct()
.collect(Collectors.toList());
List<PersonProfileDto> profiles = profileGateway.getProfiles(personIds);
Map<Long, PersonProfileDto> personProfileDtoMap = profiles.stream().collect(Collectors.toMap(BasicDto::getId, Function.identity()));
return PageConverter.convert(versionPage, record -> BeanMapper.copyBean(record, PageApplicationVersionResp.class, (source, target) -> {
PersonProfileDto person = personProfileDtoMap.get(source.getUpdateBy());
target.setUpdateBy(Objects.isNull(person.getRealName())? "-" : person.getRealName());
}));
}
/**
* 获取版本更新提醒内容
*
* @param req {@link GetVersionUpdateRemindContentReq}
* @return 对应端的版本更新记录信息 {@link GetVersionUpdateRemindContentResp}
*/
@Transactional(rollbackFor = Exception.class)
@Override
public GetVersionUpdateRemindContentResp getVersionUpdateRemindContent(GetVersionUpdateRemindContentReq req) {
// 获取对应平台配置的版本信息
ApplicationVersion version = lambdaQuery()
.eq(ApplicationVersion::getIsDelete, 0)
.eq(Objects.nonNull(req.getPlatform()), ApplicationVersion::getPlatform, req.getPlatform())
.eq(Objects.nonNull(req.getOpSystem()), ApplicationVersion::getOpSystem, req.getOpSystem())
.eq(StringUtils.isNotBlank(req.getVersion()), ApplicationVersion::getVersion, req.getVersion())
.orderByDesc(ApplicationVersion::getVersion)
.orderByDesc(ApplicationVersion::getReleaseTime)
.last("limit 1")
.one();
if (Objects.isNull(version) || version.getRemind() == 0) {
return null;
}
// 校验该用户是否已经提示
ApplicationVersionReadLog versionReadLog = applicationVersionReadLogService.getByIdWithPersonId(req.getPersonId(),version.getId());
if (Objects.isNull(versionReadLog)) {
// 该用户未提示
applicationVersionReadLogService.create(CreateApplicationVersionReadLogReq.builder()
.personId(req.getPersonId())
.versionId(version.getId())
.version(version.getVersion())
.platform(version.getPlatform())
.opSystem(version.getOpSystem())
.build());
GetVersionUpdateRemindContentResp versionRemindContent = BeanUtil.copyProperties(version, GetVersionUpdateRemindContentResp.class);
versionRemindContent.setImageUrl(Objects.equals(PlatformTypeEnum.CMS.getName(), version.getPlatform().getName()) ? cmsVersionRemindImage : appVersionRemindImage);
return versionRemindContent;
}
return null;
}
@Override
public GetVersionUpdateRemindContentResp getVersionUpdateRemindContent(GetVersionUpdateRemindContentReq req) {
return null;
/**
* 校验版本号是否重复
* <p>
* 版本号+平台+操作系统不可重复
* </p>
*
* @param req {@link CreateApplicationVersionReq}
*/
private void checkDuplicateVersion(CreateApplicationVersionReq req) {
ApplicationVersion version = lambdaQuery()
.eq(ApplicationVersion::getVersion, req.getVersion())
.eq(ApplicationVersion::getPlatform, req.getPlatform())
.eq(ApplicationVersion::getOpSystem, req.getOpSystem())
.eq(ApplicationVersion::getIsDelete, 0)
.orderByDesc(ApplicationVersion::getReleaseTime)
.one();
if (Objects.nonNull(version)) {
throw new ServiceException("版本号重复");
}
}
/**
* 构建更新条件
*
* @param req {@link UpdateApplicationVersionReq}
* @return {@link LambdaUpdateWrapper}
*/
private LambdaUpdateWrapper<ApplicationVersion> buildLambdaUpdateWrapper(UpdateApplicationVersionReq req) {
return new LambdaUpdateWrapper<ApplicationVersion>()
.eq(ApplicationVersion::getIsDelete, 0)
.eq(ApplicationVersion::getId, req.getId())
.set(ApplicationVersion::getVersion, req.getVersion())
.set(ApplicationVersion::getReleaseTime, req.getReleaseTime())
.set(ApplicationVersion::getDescription, req.getDescription())
.set(ApplicationVersion::getJumpUrl, JSONUtil.toJsonStr(req.getJumpUrl()))
.set(ApplicationVersion::getRemind, req.getRemind());
}
/**
* 构建分页查询条件
*
* @param req {@link PageApplicationVersionReq}
* @return {@link LambdaQueryWrapper}
*/
private LambdaQueryWrapper<ApplicationVersion> buildPageLambdaQueryWrapper(PageApplicationVersionReq req) {
return new LambdaQueryWrapper<ApplicationVersion>()
.eq(ApplicationVersion::getIsDelete, 0)
.eq(Objects.nonNull(req.getPlatform()), ApplicationVersion::getPlatform, req.getPlatform())
.eq(Objects.nonNull(req.getOpSystem()), ApplicationVersion::getOpSystem, req.getOpSystem())
.eq(StringUtils.isNotBlank(req.getVersion()), ApplicationVersion::getVersion, req.getVersion())
.orderByDesc(ApplicationVersion::getVersion)
.orderByDesc(ApplicationVersion::getReleaseTime);
}
/**
* 构建删除版本信息的条件
*
* @param id 版本记录id
* @param personId 操作人personId
* @return 删除条件
*/
private LambdaUpdateWrapper<ApplicationVersion> buildDeleteLambdaUpdateWrapper(Long id, Long personId) {
return new LambdaUpdateWrapper<ApplicationVersion>()
.eq(ApplicationVersion::getId, id)
.set(ApplicationVersion::getCreateBy, personId)
.set(ApplicationVersion::getIsDelete, 1);
}
}

View File

@ -1,15 +1,22 @@
package cn.axzo.nanopart.server.service.impl;
import cn.axzo.nanopart.api.request.CreateBannerOperationLogReq;
import cn.axzo.nanopart.server.mapper.BannerOperationLogDao;
import cn.axzo.nanopart.api.request.PageBannerOperationLogReq;
import cn.axzo.nanopart.api.response.PageBannerOperationLogResp;
import cn.axzo.nanopart.server.domain.BannerOperationLog;
import cn.axzo.nanopart.server.mapper.BannerOperationLogDao;
import cn.axzo.nanopart.server.service.BannerOperationLogService;
import cn.axzo.pokonyan.dao.converter.PageConverter;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.Objects;
/**
* @author chenwenjian
* @version 1.0
@ -19,10 +26,42 @@ import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class BannerOperationLogServiceImpl extends ServiceImpl<BannerOperationLogDao, BannerOperationLog> implements BannerOperationLogService {
@Override
public Long create(CreateBannerOperationLogReq req) {
BannerOperationLog bannerOperationLog = BeanUtil.copyProperties(req, BannerOperationLog.class);
this.save(bannerOperationLog);
return bannerOperationLog.getId();
}
/**
* 分页查询
*
* @param req {@link PageBannerOperationLogReq}
* @return 按照时间倒序排序后的列表
*/
@Override
public Page<PageBannerOperationLogResp> page(PageBannerOperationLogReq req) {
LambdaQueryWrapper<BannerOperationLog> pageLambdaQueryWrapper = buildPageLambdaQueryWrapper(req);
Page<BannerOperationLog> logPage = page(new Page<>(req.getPageNumber(), req.getPageSize()), pageLambdaQueryWrapper);
if (Objects.isNull(logPage) || logPage.getTotal() == 0) {
return new Page<>();
}
return PageConverter.convert(logPage, record -> BeanUtil.copyProperties(record, PageBannerOperationLogResp.class));
}
/**
* 构建分页查询条件
*
* @param req {@link PageBannerOperationLogReq}
* @return {@link LambdaQueryWrapper}
*/
private LambdaQueryWrapper<BannerOperationLog> buildPageLambdaQueryWrapper(PageBannerOperationLogReq req) {
LambdaQueryWrapper<BannerOperationLog> lambdaQueryWrapper = new LambdaQueryWrapper<>();
return lambdaQueryWrapper
.eq(BannerOperationLog::getIsDelete, 0)
.eq(Objects.nonNull(req.getRecodeType()), BannerOperationLog::getRecodeType, req.getRecodeType())
.eq(Objects.nonNull(req.getRecodeId()), BannerOperationLog::getRecodeId, req.getRecodeId())
.between(Objects.nonNull(req.getStartTime()) && Objects.nonNull(req.getEndTime()), BannerOperationLog::getUpdateBy, req.getStartTime(), req.getEndTime());
}
}

View File

@ -1,6 +1,8 @@
package cn.axzo.nanopart.server.service.impl;
import cn.axzo.framework.domain.ServiceException;
import cn.axzo.nanopart.api.enums.DisplayTimeTypeEnum;
import cn.axzo.nanopart.api.enums.PlatformTypeEnum;
import cn.axzo.nanopart.api.enums.RecodeTypeEnum;
import cn.axzo.nanopart.api.request.CreateBannerOperationLogReq;
import cn.axzo.nanopart.api.request.CreateBannerReq;
@ -10,14 +12,17 @@ import cn.axzo.nanopart.api.request.UpdateBannerReq;
import cn.axzo.nanopart.api.request.UpdateStatusReq;
import cn.axzo.nanopart.api.response.DetailBannerResp;
import cn.axzo.nanopart.api.response.PageBannerResp;
import cn.axzo.nanopart.server.mapper.BannerDao;
import cn.axzo.nanopart.server.common.ApplicationVersionValidator;
import cn.axzo.nanopart.server.domain.Banner;
import cn.axzo.nanopart.server.mapper.BannerDao;
import cn.axzo.nanopart.server.service.BannerOperationLogService;
import cn.axzo.nanopart.server.service.BannerService;
import cn.axzo.pokonyan.dao.converter.PageConverter;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@ -27,6 +32,7 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.sql.Time;
import java.util.Objects;
/**
@ -39,7 +45,7 @@ import java.util.Objects;
@RequiredArgsConstructor
public class BannerServiceImpl extends ServiceImpl<BannerDao, Banner> implements BannerService {
private BannerOperationLogService bannerOperationLogService;
private final BannerOperationLogService bannerOperationLogService;
/**
* 分页查询banner
@ -49,10 +55,10 @@ public class BannerServiceImpl extends ServiceImpl<BannerDao, Banner> implements
*/
@Override
public Page<PageBannerResp> page(PageBannerReq req) {
LambdaQueryChainWrapper<Banner> pageLambdaQueryChain = buildPageLambdaQueryChain(req);
LambdaQueryWrapper<Banner> pageLambdaQueryWrapper = buildPageLambdaQueryWrapper(req);
Page<Banner> bannerPage = page(new Page<>(req.getPageNumber(), req.getPageSize()), pageLambdaQueryChain);
if (bannerPage.getTotal() == 0) {
Page<Banner> bannerPage = page(new Page<>(req.getPageNumber(), req.getPageSize()), pageLambdaQueryWrapper);
if (Objects.isNull(bannerPage) || bannerPage.getTotal() == 0) {
return new Page<>();
}
return PageConverter.convert(bannerPage, record -> BeanUtil.toBean(record, PageBannerResp.class));
@ -69,13 +75,16 @@ public class BannerServiceImpl extends ServiceImpl<BannerDao, Banner> implements
// 校验占位图宽高比例
req.getAspectRatio().checkAspectRatio();
// 展示时间段类型校验
checkDisplayTimeType(req);
Banner oldBanner = this.selectById(req.getId());
if (Objects.isNull(oldBanner)) {
return;
}
LambdaUpdateChainWrapper<Banner> updateLambdaQueryChain = buildUpdateLambdaQueryChain(req);
update(updateLambdaQueryChain);
LambdaUpdateWrapper<Banner> lambdaUpdateWrapper = buildUpdateLambdaQueryWrapper(req);
update(lambdaUpdateWrapper);
Banner newBanner = this.selectById(req.getId());
@ -146,6 +155,14 @@ public class BannerServiceImpl extends ServiceImpl<BannerDao, Banner> implements
// 对站点code进行校重
checkBannerCodeDuplicate(req.getCode());
// 展示时间段类型校验
checkDisplayTimeType(req);
if (PlatformTypeEnum.CM.getName().equals(req.getTerminal().getName()) || PlatformTypeEnum.CMP.getName().equals(req.getTerminal().getName())){
ApplicationVersionValidator.checkVersionSimple(req.getIosVersion());
ApplicationVersionValidator.checkVersionSimple(req.getAndroidVersion());
}
// 校验占位图宽高比例
req.getAspectRatio().checkAspectRatio();
@ -213,18 +230,56 @@ public class BannerServiceImpl extends ServiceImpl<BannerDao, Banner> implements
}
}
/**
* 校验展示时间段类型
* <p>
* 此处不抽取Create和Update共同类型所以这么写
* </p>
*
* @param obj {@link CreateBannerReq} {@link UpdateBannerReq}}
*/
private void checkDisplayTimeType(Object obj) {
if (obj instanceof CreateBannerReq) {
CreateBannerReq req = (CreateBannerReq) obj;
// 为自定义时间段
if (Objects.equals(req.getDisplayTimeType().getName(), DisplayTimeTypeEnum.CUSTOM.getName())) {
if (Objects.isNull(req.getStartTime()) || Objects.isNull(req.getEndTime())) {
throw new RuntimeException("请设置展示时间段");
}
return;
}
// 此处为防止选定展示时间段类型后又手动设置了起止时间
req.setStartTime(req.getDisplayTimeType().getStartTime());
req.setEndTime(req.getDisplayTimeType().getEndTime());
} else if (obj instanceof UpdateBannerReq) {
UpdateBannerReq req = (UpdateBannerReq) obj;
if (Objects.equals(req.getDisplayTimeType().getName(), DisplayTimeTypeEnum.CUSTOM.getName())) {
if (Objects.isNull(req.getStartTime()) || Objects.isNull(req.getEndTime())) {
throw new RuntimeException("请设置展示时间段");
}
return;
}
// 此处为防止选定展示时间段类型后又手动设置了起止时间
req.setStartTime(req.getDisplayTimeType().getStartTime());
req.setEndTime(req.getDisplayTimeType().getEndTime());
}
}
/**
* 构建分页查询条件
*
* @param req {@link PageBannerReq}
* @return {@link LambdaQueryChainWrapper}
* @return {@link LambdaQueryWrapper}
*/
private LambdaQueryChainWrapper<Banner> buildPageLambdaQueryChain(PageBannerReq req) {
return lambdaQuery()
private LambdaQueryWrapper<Banner> buildPageLambdaQueryWrapper(PageBannerReq req) {
LambdaQueryWrapper<Banner> lambdaQueryWrapper = new LambdaQueryWrapper<Banner>();
return lambdaQueryWrapper
.like(StringUtils.isNotEmpty(req.getName()), Banner::getName, req.getName())
.eq(Objects.nonNull(req.getTerminal()), Banner::getTerminal, req.getTerminal())
.eq(Objects.nonNull(req.getStatus()), Banner::getStatus, req.getStatus())
.eq(Banner::getIsDelete, 0)
.orderByDesc(Banner::getStatus)
.orderByDesc(Banner::getCreateAt)
.orderByAsc(Banner::getCode);
}
@ -234,17 +289,21 @@ public class BannerServiceImpl extends ServiceImpl<BannerDao, Banner> implements
* @param req {@link UpdateBannerReq}
* @return {@link LambdaUpdateChainWrapper}
*/
private LambdaUpdateChainWrapper<Banner> buildUpdateLambdaQueryChain(UpdateBannerReq req) {
return lambdaUpdate()
private LambdaUpdateWrapper<Banner> buildUpdateLambdaQueryWrapper(UpdateBannerReq req) {
LambdaUpdateWrapper<Banner> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
return lambdaUpdateWrapper
.eq(Banner::getId, req.getId())
.set(StringUtils.isNotBlank(req.getName()), Banner::getName, req.getName())
.set(Objects.nonNull(req.getStatus()), Banner::getStatus, req.getStatus())
.set(Objects.nonNull(req.getCarouselStatus()), Banner::getCarouselStatus, req.getCarouselStatus())
.set(Banner::getMaxCarouselLimit, req.getMaxCarouselLimit())
.set(Banner::getPlayDuration, req.getPlayDuration())
.set(Banner::getStartTime, req.getStartTime())
.set(Banner::getEndTime, req.getEndTime())
.set(Banner::getAspectRatio, req.getAspectRatio())
.set(Banner::getDisplayTimeType,req.getDisplayTimeType())
.set(Banner::getStartTime, new Time(req.getStartTime()))
.set(Banner::getEndTime, new Time(req.getEndTime()))
.set(Banner::getAspectRatio, JSONUtil.toJsonStr(req.getAspectRatio()))
.set(Banner::getIosVersion, req.getIosVersion())
.set(Banner::getAndroidVersion, req.getAndroidVersion())
.set(Banner::getUpdateBy, req.getUpdateBy());
}
}

View File

@ -0,0 +1,35 @@
package cn.axzo.nanopart.server.service.impl;
import cn.axzo.nanopart.api.request.CreateMaterialPutLogReq;
import cn.axzo.nanopart.server.domain.MaterialPutLog;
import cn.axzo.nanopart.server.mapper.MaterialPutLogDao;
import cn.axzo.nanopart.server.service.MaterialPutLogService;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @author chenwenjian
* @version 1.0
* @date 2024/4/10 18:41
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class MaterialPutLogServiceImpl extends ServiceImpl<MaterialPutLogDao, MaterialPutLog> implements MaterialPutLogService {
/**
* 创建
*
* @param req {@link CreateMaterialPutLogReq}
* @return {@link Long}
*/
@Override
public Long create(CreateMaterialPutLogReq req) {
MaterialPutLog materialPutLog = BeanUtil.copyProperties(req, MaterialPutLog.class);
save(materialPutLog);
return materialPutLog.getId();
}
}

View File

@ -11,6 +11,7 @@ import cn.axzo.nanopart.api.enums.MaterialDisplayFrequencyTypeEnum;
import cn.axzo.nanopart.api.enums.RecodeTypeEnum;
import cn.axzo.nanopart.api.enums.StatusEnum;
import cn.axzo.nanopart.api.request.CreateBannerOperationLogReq;
import cn.axzo.nanopart.api.request.CreateMaterialPutLogReq;
import cn.axzo.nanopart.api.request.CreateMaterialReq;
import cn.axzo.nanopart.api.request.DetailMaterialReq;
import cn.axzo.nanopart.api.request.ListMaterialByBannerCodeReq;
@ -27,27 +28,38 @@ import cn.axzo.nanopart.server.rpc.OrganizationalJobGateway;
import cn.axzo.nanopart.server.rpc.OrganizationalNodeUserGateway;
import cn.axzo.nanopart.server.service.BannerOperationLogService;
import cn.axzo.nanopart.server.service.BannerService;
import cn.axzo.nanopart.server.service.MaterialPutLogService;
import cn.axzo.nanopart.server.service.MaterialService;
import cn.axzo.pokonyan.config.redis.RedisClient;
import cn.axzo.pokonyan.dao.converter.PageConverter;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.time.LocalDateTime;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
@ -57,6 +69,7 @@ import java.util.stream.Collectors;
*/
@Slf4j
@Service
@RefreshScope
@RequiredArgsConstructor
public class MaterialServiceImpl extends ServiceImpl<MaterialDao, Material> implements MaterialService {
@ -64,13 +77,20 @@ public class MaterialServiceImpl extends ServiceImpl<MaterialDao, Material> impl
private final BannerOperationLogService bannerOperationLogService;
private final MaterialPutLogService materialPutLogService;
private final OrganizationalNodeUserGateway organizationalNodeUserGateway;
private final OrganizationalJobGateway organizationalJobGateway;
private final CooperateShipGateway cooperateShipGateway;
// private final
/**
* 素材投放频次缓存key有效期
* 单位默认为90天
*/
@Value("${materialDisplayFrequencyKeyTtl: 90}")
private Long materialDisplayFrequencyKeyTtl;
/**
* 根据广告位编码bannerCode查询素材
@ -81,15 +101,12 @@ public class MaterialServiceImpl extends ServiceImpl<MaterialDao, Material> impl
* @param req {@link ListMaterialByBannerCodeReq}
* @return 根据优先级priority升序创建时间createAt降序排序后的列表
*/
@Transactional(rollbackFor = Exception.class)
@Override
public List<MaterialResp> listMaterialByBannerCode(ListMaterialByBannerCodeReq req) {
// 获取广告位并校验
Banner banner = bannerService.selectByCode(req.getBannerCode());
if (Objects.isNull(banner)) {
throw new ServiceException("广告位不存在");
}
if (banner.getStatus() != StatusEnum.ONLINE) {
throw new ServiceException("广告位已停用");
public List<MaterialResp> listMaterialByBannerCode(ListMaterialByBannerCodeReq req, String traceId) {
// 获取广告位并校验(是否存在是否启用是否在有效期)
if (Objects.isNull(validateBanner(req.getBannerCode()))) {
return Collections.emptyList();
}
// 获取该广告位下已上架且在有效期内的所有素材
@ -97,52 +114,39 @@ public class MaterialServiceImpl extends ServiceImpl<MaterialDao, Material> impl
if (CollectionUtils.isEmpty(materialList)) {
return Collections.emptyList();
}
log.info("上架且有效广告位:{}", JSONUtil.toJsonStr(materialList));
// 获取当前登录用户加入的所有项目部单位及其在项目部或在单位下担任的岗位
JoinedWorkspaceOuJob personJoinedWorkspaceOuJob = getPersonJoinedWorkspaceOuJob(req.getPersonId());
if (Objects.isNull(personJoinedWorkspaceOuJob)) {
// 理论上不会走到这里因为登录用户必然加入了一个项目部或单位
throw new ServiceException("数据异常");
}
// 根据素材投放人群和投放规则频次进行过滤
// 根据素材投放规则进行过滤
List<Material> list = materialList.stream()
.filter(m -> {
m.getTargetUserType().isDeliverRequired(m.getWorkspaceIds(), m.getOuIds(), m.getJobCodes(), personJoinedWorkspaceOuJob);
// 频次过滤这个人
// RedisClient.KeyOps.hasKey();
return false;
// 投放人群过滤
return m.getTargetUserType()
.isDeliverRequired(m.getWorkspaceIds(), m.getOuIds(), m.getJobCodes(),
req.getWorkspaceId(), req.getOuId(),
personJoinedWorkspaceOuJob)
&&
// 投放频次过滤
filterByDisplayFrequency(req, m);
})
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(list)) {
return Collections.emptyList();
}
// 记录素材投放日志
CreateMaterialPutLogReq materialPutLogReq = new CreateMaterialPutLogReq();
materialPutLogReq.setRequestId(traceId)
.setPersonId(req.getPersonId())
.setBannerCode(req.getBannerCode())
.setMaterialIds(list.stream().map(Material::getId).collect(Collectors.toList()));
materialPutLogService.create(materialPutLogReq);
return BeanUtil.copyToList(list, MaterialResp.class);
}
/**
* 构建素材投放频次记录缓存key
*
* <p>
* 1.含义指定素材给指定人按照投放频次类型投放次数
* 2.组成namespace:bannerCode:materialId:personId:频次类型转换后的值
* 3.频次类型转换规则示例投放频次类型参考{@link MaterialDisplayFrequencyTypeEnum}
* 有效期内:VALIDITY_PERIOD -> 有效期
* 每天:EVERY_DAY -> 当天
* 每周:EVERY_WEEK -> 当周第一天
* 每月:EVERY_MONTH -> 当月第一天
* </p>
*
* @param material 素材信息
* @param personId 投放人Id
* @return key
*/
public static String buildMaterialDisplayFrequencyKey(Material material, Long personId) {
LocalDateTime now = LocalDateTime.now();
// return String.format("nanopart:%s:%s", materialId, bannerId);
return null;
}
/**
* 分页查询
*
@ -151,7 +155,7 @@ public class MaterialServiceImpl extends ServiceImpl<MaterialDao, Material> impl
*/
@Override
public Page<PageMaterialResp> page(PageMaterialReq req) {
LambdaQueryChainWrapper<Material> pageQueryLambdaWrapper = buildPageQueryLambdaWrapper(req);
LambdaQueryWrapper<Material> pageQueryLambdaWrapper = buildPageQueryLambdaWrapper(req);
Page<Material> materialPage = page(new Page<>(req.getPageNumber(), req.getPageSize()), pageQueryLambdaWrapper);
if (materialPage.getTotal() == 0) {
@ -203,7 +207,7 @@ public class MaterialServiceImpl extends ServiceImpl<MaterialDao, Material> impl
@Override
public void update(UpdateMaterialReq req) {
Material oldMaterial = this.getById(req.getId());
if (Objects.isNull(oldMaterial) || oldMaterial.getIsDelete() == 0) {
if (Objects.isNull(oldMaterial) || oldMaterial.getIsDelete() != 0) {
throw new ServiceException("素材不存在");
}
@ -242,7 +246,7 @@ public class MaterialServiceImpl extends ServiceImpl<MaterialDao, Material> impl
Material newMaterial = this.getById(req.getId());
// 记录操作日志
CreateBannerOperationLogReq updateLogReq = new CreateBannerOperationLogReq()
.setRecodeType(RecodeTypeEnum.BANNER)
.setRecodeType(RecodeTypeEnum.MATERIAL)
.setRecodeId(req.getId())
.setOperationType("updateStatus")
.setOldData((JSONObject) JSONObject.toJSON(oldMaterial))
@ -263,23 +267,93 @@ public class MaterialServiceImpl extends ServiceImpl<MaterialDao, Material> impl
if (Objects.isNull(req.getId()) || req.getId() == 0) {
return null;
}
return BeanUtil.copyProperties(getById(req.getId()), MaterialResp.class);
Material material = getById(req.getId());
if (Objects.isNull(material)) {
return null;
}
// 获取所属广告位
Banner banner = bannerService.selectByCode(material.getBannerCode());
if (Objects.isNull(banner)) {
log.warn("广告位不存在广告位code{}素材id{}", material.getBannerCode(), material.getId());
throw new ServiceException("数据异常");
}
MaterialResp materialResp = BeanUtil.copyProperties(material, MaterialResp.class);
materialResp.setTerminal(banner.getTerminal());
return materialResp;
}
/**
* 对于给定bannerCode校验其存在性和状态有效性
*
* @param bannerCode 广告位code
* @return 若存在且有效返回广告位对象否则否则返回null
*/
private Banner validateBanner(String bannerCode) {
if (StringUtils.isEmpty(bannerCode)) {
return null;
}
Banner banner = bannerService.selectByCode(bannerCode);
if (Objects.isNull(banner)) {
log.warn("广告位不存在广告位code{}", bannerCode);
return null;
}
if (banner.getStatus() != StatusEnum.ONLINE) {
log.warn("广告位已停用广告位code{}", bannerCode);
return null;
}
LocalTime now = LocalTime.now();
// 当前不在广告位配置的展示时间范围内
if (now.isBefore(banner.getStartTime().toLocalTime()) || now.isAfter(banner.getEndTime().toLocalTime())) {
log.warn("当前时间不在广告位配置的展示时间范围内广告位code{},当前时间:{},广告位开始时间:{},广告位结束时间:{}", bannerCode, now, banner.getStartTime(), banner.getEndTime());
return null;
}
return banner;
}
/**
* 根据素材投放频次规则进行过滤
*
* @param req {@link ListMaterialByBannerCodeReq}
* @param m {@link Material}
* @return true符合投放规则即为达到最大投放次数限制false不符合投放规则已到达最大投放次数限制
*/
private boolean filterByDisplayFrequency(ListMaterialByBannerCodeReq req, Material m) {
boolean displayFrequencyFilter;
String key = buildMaterialDisplayFrequencyKey(m, req.getPersonId());
if (RedisClient.KeyOps.hasKey(key)) {
int frequency = Integer.parseInt(RedisClient.StringOps.get(key));
log.info("{素材投放key{}value{}", key, frequency);
displayFrequencyFilter = MaterialDisplayFrequencyTypeEnum.NO_LIMIT.getCode().equals(m.getDisplayFrequencyType().getCode()) || frequency < m.getMaxDisplayFrequency();
if (displayFrequencyFilter) {
// 本次需要投放
RedisClient.StringOps.incrBy(key, 1L);
}
} else {
displayFrequencyFilter = true;
RedisClient.StringOps.set(key, String.valueOf(1));
// key失效时间有效期天数加上配置的有效期天数
long intervalDays = (m.getEndTime().getTime() - m.getStartTime().getTime()) / (1000 * 60 * 60 * 24);
RedisClient.KeyOps.expire(key, intervalDays + materialDisplayFrequencyKeyTtl, TimeUnit.DAYS);
}
return displayFrequencyFilter;
}
/**
* 构建分页查询条件
*
* @param req {@link PageMaterialReq}
* @return {@link LambdaQueryChainWrapper}
* @return {@link LambdaQueryWrapper}
*/
private LambdaQueryChainWrapper<Material> buildPageQueryLambdaWrapper(PageMaterialReq req) {
return lambdaQuery()
private LambdaQueryWrapper<Material> buildPageQueryLambdaWrapper(PageMaterialReq req) {
LambdaQueryWrapper<Material> lambdaQueryWrapper = new LambdaQueryWrapper<>();
return lambdaQueryWrapper
.eq(Material::getIsDelete, 0)
.eq(StringUtils.isNotEmpty(req.getBannerCode()), Material::getBannerCode, req.getBannerCode())
.like(StringUtils.isNotEmpty(req.getName()), Material::getName, req.getName())
.eq(Objects.nonNull(req.getStatus()), Material::getStatus, req.getStatus())
.le(Objects.nonNull(req.getStartTime()), Material::getStartTime, req.getStartTime())
.ge(Objects.nonNull(req.getEndTime()), Material::getEndTime, req.getEndTime())
.ge(Objects.nonNull(req.getStartTime()), Material::getStartTime, req.getStartTime())
.le(Objects.nonNull(req.getEndTime()), Material::getEndTime, req.getEndTime())
.orderByDesc(Material::getStatus)
.orderByAsc(Material::getPriority)
.orderByDesc(Material::getCreateAt);
@ -289,16 +363,17 @@ public class MaterialServiceImpl extends ServiceImpl<MaterialDao, Material> impl
* 构建通过BannerCode查询素材的wrapper
*
* @param req {@link ListMaterialByBannerCodeReq}
* @return {@link LambdaQueryChainWrapper}
* @return {@link LambdaQueryWrapper}
*/
private LambdaQueryChainWrapper<Material> buildListByBannerCodeQueryWrapper(ListMaterialByBannerCodeReq req) {
private LambdaQueryWrapper<Material> buildListByBannerCodeQueryWrapper(ListMaterialByBannerCodeReq req) {
Date now = new Date(System.currentTimeMillis());
return lambdaQuery()
LambdaQueryWrapper<Material> lambdaQueryWrapper = new LambdaQueryWrapper<>();
return lambdaQueryWrapper
.eq(Material::getIsDelete, 0)
.eq(Material::getBannerCode, req.getBannerCode())
.eq(Material::getStatus, StatusEnum.ONLINE)
.ge(Material::getStartTime, now)
.le(Material::getEndTime, now)
.le(Material::getStartTime, now)
.ge(Material::getEndTime, now)
.orderByAsc(Material::getPriority)
.orderByDesc(Material::getCreateAt);
}
@ -357,10 +432,22 @@ public class MaterialServiceImpl extends ServiceImpl<MaterialDao, Material> impl
// Map<ouId, List<topNodeId>>
Map<Long, List<Long>> ouIdToTopNodeIdMap = genericQuery.stream()
.filter(c -> c.getWorkspaceId() == 1)
.filter(c -> c.getWorkspaceType() == 1)
.collect(Collectors.groupingBy(CooperateShipResp::getOrganizationalUnitId,
Collectors.mapping(CooperateShipResp::getOrganizationalNodeId, Collectors.toList())));
// 单位加入的项目部Map<ouId,List<workspace>>
Map<Long, List<Long>> ouIdToWorkspaceMap = genericQuery.stream()
.filter(c -> c.getWorkspaceType() == 2)
.collect(Collectors.groupingBy(CooperateShipResp::getOrganizationalUnitId,
Collectors.mapping(CooperateShipResp::getWorkspaceId, Collectors.toList())));
// 项目部下的单位 Map<workspaceId, List<ouId>
Map<Long, List<Long>> workspaceToOuIdMap = genericQuery.stream()
.filter(c -> c.getWorkspaceType() == 2)
.collect(Collectors.groupingBy(CooperateShipResp::getWorkspaceId,
Collectors.mapping(CooperateShipResp::getOrganizationalUnitId, Collectors.toList())));
// Map<workspaceId, List<jobCode>
Map<Long, List<String>> workspaceToJobCodeMap = workspaceToTopNodeIdMap.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey,
@ -381,7 +468,49 @@ public class MaterialServiceImpl extends ServiceImpl<MaterialDao, Material> impl
.distinct()
.collect(Collectors.toList())));
return new JoinedWorkspaceOuJob(workspaceToJobCodeMap, ouIdToJobCodeMap);
return new JoinedWorkspaceOuJob(workspaceToJobCodeMap, ouIdToJobCodeMap,ouIdToWorkspaceMap,workspaceToOuIdMap);
}
/**
* 构建素材投放频次记录缓存key
*
* <p>
* 1.含义指定素材给指定人按照投放频次类型投放次数
* 2.组成namespace:bannerCode:materialId:personId:频次类型转换后的值
* 3.频次类型转换规则示例投放频次类型参考{@link MaterialDisplayFrequencyTypeEnum}
* 有效期内:VALIDITY_PERIOD -> 有效期
* 每天:EVERY_DAY -> 当天
* 每周:EVERY_WEEK -> 当周第一天
* 每月:EVERY_MONTH -> 当月第一天
* </p>
*
* @param material 素材信息
* @param personId 投放人Id
* @return key
*/
public static String buildMaterialDisplayFrequencyKey(Material material, Long personId) {
String prefix = String.format("nanopart:%s:%s:%s:", material.getBannerCode(), material.getId(), personId);
String datePattern = "yyyy_MM_dd";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(datePattern);
LocalDate now = LocalDate.now();
String suffix = "";
switch (material.getDisplayFrequencyType()) {
case NO_LIMIT:
suffix = String.join("_", MaterialDisplayFrequencyTypeEnum.NO_LIMIT.getCode());
break;
case VALIDITY_PERIOD:
suffix = String.join("_", "P", DateUtil.format(material.getStartTime(), datePattern), DateUtil.format(material.getEndTime(), datePattern));
break;
case EVERY_DAY:
suffix = String.join("_", "D", now.format(formatter));
break;
case EVERY_WEEK:
suffix = String.join("_", "W", now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)).format(formatter));
break;
case EVERY_MONTH:
suffix = String.join("_", "M", now.with(TemporalAdjusters.firstDayOfMonth()).format(formatter));
}
return prefix + suffix;
}
}

View File

@ -21,7 +21,7 @@ mybatis-plus:
logic-delete-value: id #逻辑已删除值(默认为 1)
logic-not-delete-value: 0 #逻辑未删除值(默认为 0)
logic-delete-field: isDelete #逻辑删除字段
type-enums-package: cn.axzo.nanopart.api.constant.enums,cn.axzo.nanopart.api.enums
type-enums-package: cn.axzo.nanopart.api.constant.enums;cn.axzo.nanopart.api.enums
logging:
level: