diff --git a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/ApplicationVersionApi.java b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/ApplicationVersionApi.java index e3e0dfd5..b2fb2369 100644 --- a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/ApplicationVersionApi.java +++ b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/ApplicationVersionApi.java @@ -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 { -// -// /** -// * 创建 -// *

-// * 版本号+平台+操作系统,不可重复 -// *

-// * -// * @param req {@link CreateApplicationVersionReq} -// * @return 版本记录id -// */ -// @PostMapping("/api/applicationVersion/create") -// ApiResult create(@RequestBody @Valid CreateApplicationVersionReq req); -// -// /** -// * 更新 -// * -// * @param req {@link UpdateApplicationVersionReq} -// * @return void -// */ -// @PostMapping("/api/applicationVersion/update") -// ApiResult update(@RequestBody @Valid UpdateApplicationVersionReq req); -// -// /** -// * 删除 -// * -// * @param id 版本记录id -// * @return void -// */ -// @GetMapping("/api/applicationVersion/delete") -// ApiResult deleteById(@RequestParam("id") Long id, @RequestParam("personId") Long personId); -// -// /** -// * 分页查询 -// * -// * @param req {@link PageApplicationVersionReq} -// * @return 按照版本号字典序倒排 -// */ -// @PostMapping("/api/applicationVersion/page") -// ApiPageResult page(@RequestBody @Valid PageApplicationVersionReq req); -// -// /** -// * 获取版本更新提醒内容 -// *

-// * 1. 获取最新配置的提示内容记录 -// * - 对于cms,直接返回最新配置(版本号最高)的一条记录()看是否配置了弹窗提示 -// * - 对于app,根据版本号和操作系统,看该版本号是否配置了弹窗提示 -// * 2. 检查当前用户是否已经提示 -// * - 若已提示则不再提示,直接返回null -// * - 若还没有提示,则返回该条提示内容记录 -// *

-// * -// * @param req {@link GetVersionUpdateRemindContentReq} -// * @return 版本更新提醒内容 -// */ -// @PostMapping("/api/applicationVersion/getVersionUpdateRemindContent") -// ApiResult 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 { + + /** + * 创建 + *

+ * 版本号+平台+操作系统,不可重复 + *

+ * + * @param req {@link CreateApplicationVersionReq} + * @return 版本记录id + */ + @PostMapping("/api/applicationVersion/create") + ApiResult create(@RequestBody @Valid CreateApplicationVersionReq req); + + /** + * 更新 + * + * @param req {@link UpdateApplicationVersionReq} + * @return void + */ + @PostMapping("/api/applicationVersion/update") + ApiResult update(@RequestBody @Valid UpdateApplicationVersionReq req); + + /** + * 删除 + * + * @param id 版本记录id + * @return void + */ + @GetMapping("/api/applicationVersion/delete") + ApiResult deleteById(@RequestParam("id") Long id, @RequestParam(value = "personId") Long personId); + + /** + * 分页查询 + * + * @param req {@link PageApplicationVersionReq} + * @return 按照版本号字典序倒排 + */ + @PostMapping("/api/applicationVersion/page") + ApiPageResult page(@RequestBody @Valid PageApplicationVersionReq req); + + /** + * 获取版本更新提醒内容 + *

+ * 1. 获取最新配置的提示内容记录 + * - 对于cms,直接返回最新配置(版本号最高)的一条记录()看是否配置了弹窗提示 + * - 对于app,根据版本号和操作系统,看该版本号是否配置了弹窗提示 + * 2. 检查当前用户是否已经提示 + * - 若已提示则不再提示,直接返回null + * - 若还没有提示,则返回该条提示内容记录并记录为已提示 + *

+ * + * @param req {@link GetVersionUpdateRemindContentReq} + * @return 版本更新提醒内容 + */ + @PostMapping("/api/applicationVersion/getVersionUpdateRemindContent") + ApiResult getVersionUpdateRemindContent(@RequestBody @Valid GetVersionUpdateRemindContentReq req); +} diff --git a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/BannerApi.java b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/BannerApi.java index 47ef264c..c30edfbf 100644 --- a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/BannerApi.java +++ b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/BannerApi.java @@ -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 page(@RequestBody @Valid PageBannerReq req); -// -// /** -// * 创建banner -// * -// * @param req {@link CreateBannerReq} -// * @return bannerId -// */ -// @PostMapping("/api/banner/create") -// ApiResult create(@RequestBody @Valid CreateBannerReq req); -// -// /** -// * 更新banner -// * -// * @param req {@link UpdateBannerReq} -// * @return void -// */ -// @PostMapping("/api/banner/update") -// ApiResult update(@RequestBody @Valid UpdateBannerReq req); -// -// /** -// * 更新banner状态 -// * -// * @param req {@link UpdateStatusReq} -// * @return void -// */ -// @PostMapping("/api/banner/updateStatus") -// ApiResult updateStatus(@RequestBody @Valid UpdateStatusReq req); -// -// /** -// * 详情 -// * -// * @param req 广告位唯一的id或code {@link DetailBannerReq} -// * @return {@link DetailBannerResp} -// */ -// @PostMapping("/api/banner/detail") -// ApiResult 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 page(@RequestBody @Valid PageBannerReq req); + + /** + * 创建banner + * + * @param req {@link CreateBannerReq} + * @return bannerId + */ + @PostMapping("/api/banner/create") + ApiResult create(@RequestBody @Valid CreateBannerReq req); + + /** + * 更新banner + * + * @param req {@link UpdateBannerReq} + * @return void + */ + @PostMapping("/api/banner/update") + ApiResult update(@RequestBody @Valid UpdateBannerReq req); + + /** + * 更新banner状态 + * + * @param req {@link UpdateStatusReq} + * @return void + */ + @PostMapping("/api/banner/updateStatus") + ApiResult updateStatus(@RequestBody @Valid UpdateStatusReq req); + + /** + * 详情 + * + * @param req 广告位唯一的id或code {@link DetailBannerReq} + * @return {@link DetailBannerResp} + */ + @PostMapping("/api/banner/detail") + ApiResult detail(@RequestBody @Valid DetailBannerReq req); +} diff --git a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/BannerOperationLogApi.java b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/BannerOperationLogApi.java index 4955eede..ca1cfa2c 100644 --- a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/BannerOperationLogApi.java +++ b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/BannerOperationLogApi.java @@ -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 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 page(@RequestBody @Valid PageBannerOperationLogReq req); +} diff --git a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/MaterialApi.java b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/MaterialApi.java index 603cf2ef..eb08ba74 100644 --- a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/MaterialApi.java +++ b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/MaterialApi.java @@ -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 page(@RequestBody @Valid PageMaterialReq req); - // - // /** - // * 创建 - // * - // * @param req {@link CreateMaterialReq} - // * @return 素材id - // */ - // @PostMapping("/api/material/create") - // ApiResult create(@RequestBody @Valid CreateMaterialReq req); - // - // /** - // * 更新 - // * - // * @param req {@link UpdateMaterialReq} - // * @return 无 - // */ - // @PostMapping("/api/material/update") - // ApiResult update(@RequestBody @Valid UpdateMaterialReq req); - // - // /** - // * 更新banner状态 - // * - // * @param req {@link UpdateStatusReq} - // * @return void - // */ - // @PostMapping("/api/material/updateStatus") - // ApiResult updateStatus(@RequestBody @Valid UpdateStatusReq req); - // - // /** - // * 详情 - // * - // * @param req {@link UpdateMaterialReq} - // * @return 素材详情 - // */ - // @PostMapping("/api/material/detail") - // ApiResult detail(@RequestBody @Valid DetailMaterialReq req); + /** + * 分页查询 + * + * @param req {@link PageMaterialReq}} + * @return 根据上下架状态(上架→下架)。优先级正序(数字由小到大)排列后素材列表 + */ + @PostMapping("/api/material/page") + ApiPageResult page(@RequestBody @Valid PageMaterialReq req); + + /** + * 创建 + * + * @param req {@link CreateMaterialReq} + * @return 素材id + */ + @PostMapping("/api/material/create") + ApiResult create(@RequestBody @Valid CreateMaterialReq req); + + /** + * 更新 + * + * @param req {@link UpdateMaterialReq} + * @return 无 + */ + @PostMapping("/api/material/update") + ApiResult update(@RequestBody @Valid UpdateMaterialReq req); + + /** + * 更新banner状态 + * + * @param req {@link UpdateStatusReq} + * @return 无 + */ + @PostMapping("/api/material/updateStatus") + ApiResult updateStatus(@RequestBody @Valid UpdateStatusReq req); + + /** + * 详情 + * + * @param req {@link UpdateMaterialReq} + * @return 素材详情 + */ + @PostMapping("/api/material/detail") + ApiResult detail(@RequestBody @Valid DetailMaterialReq req); /** * 根据广告位编码(bannerCode)查询素材 *

- * 对于cms和cmp需要传入当前登录人所在的workspaceId,ouId和所担任的jobCode - *

- *

* 1. 通过广告位code获取该广告位下的所有素材(默认查询上架状态且在有效期范围内的素材) - * 2. 根据广告位投放人群进行过滤 + * 2. 根据广告位投放人群进行过滤(对于cms/cmp需要根据当前登录人登录企业情况进行过滤) * 3. 根据广告位投放规则频次进行过滤 * 4. 将最终的素材根据优先级(priority)升序,创建时间(createAt)降序排序 *

@@ -80,5 +86,4 @@ public interface MaterialApi { */ @PostMapping("/api/material/listByBannerCode") ApiResult> listMaterialByBannerCode(@RequestBody @Valid ListMaterialByBannerCodeReq req); - } diff --git a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/constant/NanopartConstant.java b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/constant/NanopartConstant.java index 8cab11ce..633285d6 100644 --- a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/constant/NanopartConstant.java +++ b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/constant/NanopartConstant.java @@ -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+$"; } \ No newline at end of file diff --git a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/dto/AspectRatioDto.java b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/dto/AspectRatioDto.java index 4b194606..d321f84d 100644 --- a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/dto/AspectRatioDto.java +++ b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/dto/AspectRatioDto.java @@ -39,6 +39,9 @@ public class AspectRatioDto { if (this.getWidth() <= 0 || this.getWidth() > 100) { throw new ServiceException("请设置合适的占位图宽高比例"); } + }else { + this.setWidth(0); + this.setHeight(0); } } } \ No newline at end of file diff --git a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/dto/JoinedWorkspaceOuJob.java b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/dto/JoinedWorkspaceOuJob.java index 69b2b1c4..e5677c0b 100644 --- a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/dto/JoinedWorkspaceOuJob.java +++ b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/dto/JoinedWorkspaceOuJob.java @@ -16,6 +16,7 @@ import java.util.Map; @NoArgsConstructor @AllArgsConstructor public class JoinedWorkspaceOuJob { + /** * 加入的项目部及在该项目部下担任的所有岗位 */ @@ -26,4 +27,14 @@ public class JoinedWorkspaceOuJob { */ private Map> ouJobMap; + /** + * 加入的单位及在该单位加入的项目部 + */ + private Map> ouWorkspaceMap; + + /** + * 加入的项目部及在该项目部加入的单位 + */ + private Map> workspaceOuMap; + } \ No newline at end of file diff --git a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/enums/DisplayTimeTypeEnum.java b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/enums/DisplayTimeTypeEnum.java new file mode 100644 index 00000000..97fdd80c --- /dev/null +++ b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/enums/DisplayTimeTypeEnum.java @@ -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); + } +} diff --git a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/enums/LogOperationTypeEnum.java b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/enums/LogOperationTypeEnum.java new file mode 100644 index 00000000..28b65ad2 --- /dev/null +++ b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/enums/LogOperationTypeEnum.java @@ -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); + } +} diff --git a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/enums/MaterialDisplayFrequencyTypeEnum.java b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/enums/MaterialDisplayFrequencyTypeEnum.java index 01bbb829..861f4ad1 100644 --- a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/enums/MaterialDisplayFrequencyTypeEnum.java +++ b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/enums/MaterialDisplayFrequencyTypeEnum.java @@ -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", "每周"), diff --git a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/enums/MaterialTargetUserTypeEnum.java b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/enums/MaterialTargetUserTypeEnum.java index 38fa3299..1bf47878 100644 --- a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/enums/MaterialTargetUserTypeEnum.java +++ b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/enums/MaterialTargetUserTypeEnum.java @@ -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 workspaceIds, List ouIds, List jobCodes, JoinedWorkspaceOuJob workspaceOuJob) { + public boolean isDeliverRequired(List workspaceIds, List ouIds, List jobCodes, + Long loginWorkspaceId, Long loginOuid, + JoinedWorkspaceOuJob workspaceOuJob) { + log.info("投放全部用户"); return true; } }, PROJECT("PROJECT", "按照项目部") { @Override - public boolean isDeliverRequired(List workspaceIds, List ouIds, List jobCodes, JoinedWorkspaceOuJob workspaceOuJob) { - // 若workspaceIds和jobCodes都为空,则表示不限制,否则需要满足配置的workspaceIds和jobCodes与用户加入的workspaceJob的key,value均存在交集 + public boolean isDeliverRequired(List workspaceIds, List ouIds, List jobCodes, + Long loginWorkspaceId, Long loginOuid, + JoinedWorkspaceOuJob workspaceOuJob) { + Map> 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 workspaceIds, List ouIds, List jobCodes, JoinedWorkspaceOuJob workspaceOuJob) { - // 若workspaceIds和jobCodes都为空,则表示不限制,否则需要满足配置的workspaceIds和jobCodes与用户加入的workspaceJob的key,value均存在交集 + public boolean isDeliverRequired(List workspaceIds, List ouIds, List jobCodes, + Long loginWorkspaceId, Long loginOuid, + JoinedWorkspaceOuJob workspaceOuJob) { + Map> 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 workspaceIds, List ouIds, List jobCodes, JoinedWorkspaceOuJob workspaceOuJob); + public abstract boolean isDeliverRequired(List workspaceIds, List ouIds, List jobCodes, + Long loginWorkspaceId, Long loginOuid, + JoinedWorkspaceOuJob workspaceOuJob); public static MaterialTargetUserTypeEnum getByCode(String code) { if (StringUtils.isEmpty(code)) { diff --git a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/enums/OpSystemTypeEnum.java b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/enums/OpSystemTypeEnum.java index 004f6042..094aa5b7 100644 --- a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/enums/OpSystemTypeEnum.java +++ b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/enums/OpSystemTypeEnum.java @@ -17,9 +17,9 @@ import java.util.Arrays; @AllArgsConstructor public enum OpSystemTypeEnum { - ANDROID("Android", "安卓"), + ANDROID("ANDROID", "安卓"), - IOS("iOS", "苹果"), + IOS("IOS", "苹果"), PC("PC", "电脑"); diff --git a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/enums/RecodeTypeEnum.java b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/enums/RecodeTypeEnum.java index bd8ab20c..032d14b5 100644 --- a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/enums/RecodeTypeEnum.java +++ b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/enums/RecodeTypeEnum.java @@ -15,9 +15,9 @@ import java.util.Arrays; @AllArgsConstructor public enum RecodeTypeEnum { - BANNER("BANNER", "广告位操作类型"), + BANNER("BANNER", "广告"), - MATERIAL("MATERIAL", "素材操作类型"), + MATERIAL("MATERIAL", "素材"), ; private final String type; diff --git a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/CreateApplicationVersionReadLogReq.java b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/CreateApplicationVersionReadLogReq.java new file mode 100644 index 00000000..77b0ef56 --- /dev/null +++ b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/CreateApplicationVersionReadLogReq.java @@ -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; +} diff --git a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/CreateApplicationVersionReq.java b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/CreateApplicationVersionReq.java index d4f38a20..8c25823d 100644 --- a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/CreateApplicationVersionReq.java +++ b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/CreateApplicationVersionReq.java @@ -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 diff --git a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/CreateBannerReq.java b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/CreateBannerReq.java index 1942f586..cfb5944b 100644 --- a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/CreateBannerReq.java +++ b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/CreateBannerReq.java @@ -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 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-120】s */ - @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 diff --git a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/CreateMaterialPutLogReq.java b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/CreateMaterialPutLogReq.java new file mode 100644 index 00000000..448d924b --- /dev/null +++ b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/CreateMaterialPutLogReq.java @@ -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 materialIds; +} diff --git a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/CreateMaterialReq.java b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/CreateMaterialReq.java index 33d3bdc9..3ef1bfdd 100644 --- a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/CreateMaterialReq.java +++ b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/CreateMaterialReq.java @@ -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; + /** * 占位图,支持jpg、jpeg、png、gif,限定大小为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 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; /** diff --git a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/GetApplicationVersionReadLogReq.java b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/GetApplicationVersionReadLogReq.java new file mode 100644 index 00000000..e416be7d --- /dev/null +++ b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/GetApplicationVersionReadLogReq.java @@ -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; +} diff --git a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/ListMaterialByBannerCodeReq.java b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/ListMaterialByBannerCodeReq.java index 87103b14..ba4d5766 100644 --- a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/ListMaterialByBannerCodeReq.java +++ b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/ListMaterialByBannerCodeReq.java @@ -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 workspaceIds; + private Long workspaceId; /** - * 单位id,用于筛选相关运营素材是否配置给了该单位人员 + * 当前登录单位id,用于筛选相关运营素材是否配置给了该单位人员 */ - private List ouIds; + private Long ouId; /** * 岗位编码,搭配{@code workspaceIds}或{@code unitIds}使用 * 用于筛选相关运营素材是否配置给了指定项目部下指定岗位人员 * 或指定单位下指定岗位人员 */ - private List jobCodes; + private String jobCode; } diff --git a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/UpdateApplicationVersionReq.java b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/UpdateApplicationVersionReq.java index 7e2f51ab..d9d2eec3 100644 --- a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/UpdateApplicationVersionReq.java +++ b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/UpdateApplicationVersionReq.java @@ -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 diff --git a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/UpdateBannerReq.java b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/UpdateBannerReq.java index 959e4576..c608bc3b 100644 --- a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/UpdateBannerReq.java +++ b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/request/UpdateBannerReq.java @@ -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-120】s */ - @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; /** * 长宽比 diff --git a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/response/DetailBannerResp.java b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/response/DetailBannerResp.java index 3d89f62e..e358c351 100644 --- a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/response/DetailBannerResp.java +++ b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/response/DetailBannerResp.java @@ -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; } diff --git a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/response/GetVersionUpdateRemindContentResp.java b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/response/GetVersionUpdateRemindContentResp.java index aa013e33..8b08c237 100644 --- a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/response/GetVersionUpdateRemindContentResp.java +++ b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/response/GetVersionUpdateRemindContentResp.java @@ -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; } diff --git a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/response/MaterialResp.java b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/response/MaterialResp.java index cd5047db..7e026a24 100644 --- a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/response/MaterialResp.java +++ b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/response/MaterialResp.java @@ -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:安心筑CMS,CM,CMP:安心筑工人端APP,安心筑管理端APP + *

+ * 素材 + *

+ * {@link PlatformTypeEnum} + */ + private PlatformTypeEnum terminal; + + /** + * 创建时间 + */ + private Date createAt; + + /** + * 目标投放项目部或企业 + */ + private String targetWorkspaceOrUnit; + + /** + * 目标投放岗位 + */ + private String targetUserJobCode; + } diff --git a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/response/PageApplicationVersionResp.java b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/response/PageApplicationVersionResp.java index 5688270f..30380e15 100644 --- a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/response/PageApplicationVersionResp.java +++ b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/response/PageApplicationVersionResp.java @@ -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; } diff --git a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/response/PageBannerOperationLogResp.java b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/response/PageBannerOperationLogResp.java index a7d42bd2..79e1a00a 100644 --- a/banner/banner-api/src/main/java/cn/axzo/nanopart/api/response/PageBannerOperationLogResp.java +++ b/banner/banner-api/src/main/java/cn/axzo/nanopart/api/response/PageBannerOperationLogResp.java @@ -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; } diff --git a/banner/banner-server/pom.xml b/banner/banner-server/pom.xml index 64eb92b9..639ccf06 100644 --- a/banner/banner-server/pom.xml +++ b/banner/banner-server/pom.xml @@ -74,5 +74,10 @@ cn.axzo.maokai maokai-api + + + cn.axzo.basics + basics-profiles-api + diff --git a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/common/ApplicationVersionValidator.java b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/common/ApplicationVersionValidator.java new file mode 100644 index 00000000..e60ecd36 --- /dev/null +++ b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/common/ApplicationVersionValidator.java @@ -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("请输入正确的版本号"); + } + } + } +} diff --git a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/controller/ApplicationVersionController.java b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/controller/ApplicationVersionController.java index 1e2bd3ed..6dd0da2c 100644 --- a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/controller/ApplicationVersionController.java +++ b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/controller/ApplicationVersionController.java @@ -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 create(CreateApplicationVersionReq req) { -// return ApiResult.ok(applicationVersionService.create(req)); -// } -// -// @Override -// public ApiResult update(UpdateApplicationVersionReq req) { -// applicationVersionService.update(req); -// return ApiResult.ok(); -// } -// -// @Override -// public ApiResult deleteById(Long id, Long personId) { -// applicationVersionService.deleteById(id, personId); -// return ApiResult.ok(); -// } -// -// @Override -// public ApiPageResult page(PageApplicationVersionReq req) { -// Page pageData = applicationVersionService.page(req); -// return ApiPageResult.ok(pageData); -// } -// -// @Override -// public ApiResult 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 create(CreateApplicationVersionReq req) { + return ApiResult.ok(applicationVersionService.create(req)); + } + + @Override + public ApiResult update(UpdateApplicationVersionReq req) { + applicationVersionService.update(req); + return ApiResult.ok(); + } + + @Override + public ApiResult deleteById(Long id, Long personId) { + applicationVersionService.deleteById(id, personId); + return ApiResult.ok(); + } + + @Override + public ApiPageResult page(PageApplicationVersionReq req) { + Page pageData = applicationVersionService.page(req); + return ApiPageResult.ok(pageData); + } + + @Override + public ApiResult getVersionUpdateRemindContent(GetVersionUpdateRemindContentReq req) { + if (Objects.isNull(req.getPersonId()) || req.getPersonId() == 0) { + throw new ServiceException("personId不能为空"); + } + return ApiResult.ok(applicationVersionService.getVersionUpdateRemindContent(req)); + } +} diff --git a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/controller/BannerController.java b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/controller/BannerController.java index e93d61c5..cffed1c8 100644 --- a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/controller/BannerController.java +++ b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/controller/BannerController.java @@ -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 page(PageBannerReq req) { -// Page pageData = bannerService.page(req); -// return ApiPageResult.ok(pageData); -// } -// -// @Override -// public ApiResult create(CreateBannerReq req) { -// return ApiResult.ok(bannerService.create(req)); -// } -// -// @Override -// public ApiResult update(UpdateBannerReq req) { -// bannerService.update(req); -// return ApiResult.ok(); -// } -// -// @Override -// public ApiResult updateStatus(UpdateStatusReq req) { -// bannerService.updateStatus(req); -// return ApiResult.ok(); -// } -// -// @Override -// public ApiResult 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 page(PageBannerReq req) { + Page pageData = bannerService.page(req); + return ApiPageResult.ok(pageData); + } + + @Override + public ApiResult create(CreateBannerReq req) { + return ApiResult.ok(bannerService.create(req)); + } + + @Override + public ApiResult update(UpdateBannerReq req) { + bannerService.update(req); + return ApiResult.ok(); + } + + @Override + public ApiResult updateStatus(UpdateStatusReq req) { + bannerService.updateStatus(req); + return ApiResult.ok(); + } + + @Override + public ApiResult detail(DetailBannerReq req) { + return ApiResult.ok(bannerService.detail(req)); + } +} diff --git a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/controller/BannerOperationLogController.java b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/controller/BannerOperationLogController.java index cc1328da..44e511a9 100644 --- a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/controller/BannerOperationLogController.java +++ b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/controller/BannerOperationLogController.java @@ -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 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 page(PageBannerOperationLogReq req) { + Page pageData = bannerOperationLogService.page(req); + return ApiPageResult.ok(pageData); + } +} diff --git a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/controller/MaterialController.java b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/controller/MaterialController.java index b5a36755..07bda5ff 100644 --- a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/controller/MaterialController.java +++ b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/controller/MaterialController.java @@ -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 page(PageMaterialReq req) { - // Page pageData = materialService.page(req); - // return ApiPageResult.ok(pageData); - // } - // - // @Override - // public ApiResult create(CreateMaterialReq req) { - // return ApiResult.ok(materialService.create(req)); - // } - // - // @Override - // public ApiResult update(UpdateMaterialReq req) { - // materialService.update(req); - // return ApiResult.ok(); - // } - // - // @Override - // public ApiResult updateStatus(UpdateStatusReq req) { - // materialService.updateStatus(req); - // return ApiResult.ok(); - // } - // - // @Override - // public ApiResult detail(DetailMaterialReq req) { - // return ApiResult.ok(materialService.detail(req)); - // } + private final MaterialService materialService; + + private final HttpServletRequest request; + @Override + public ApiPageResult page(PageMaterialReq req) { + Page pageData = materialService.page(req); + return ApiPageResult.ok(pageData); + } + + @Override + public ApiResult create(CreateMaterialReq req) { + return ApiResult.ok(materialService.create(req)); + } + + @Override + public ApiResult update(UpdateMaterialReq req) { + materialService.update(req); + return ApiResult.ok(); + } + + @Override + public ApiResult updateStatus(UpdateStatusReq req) { + materialService.updateStatus(req); + return ApiResult.ok(); + } + + @Override + public ApiResult detail(DetailMaterialReq req) { + return ApiResult.ok(materialService.detail(req)); + } + + /** + * 根据广告位编码(bannerCode)查询素材 + *

+ * 1. 通过广告位code获取该广告位下的所有素材(默认查询上架状态且在有效期范围内的素材) + * 2. 根据广告位投放人群进行过滤(对于cms/cmp需要根据当前登录人登录企业情况进行过滤) + * 3. 根据广告位投放规则频次进行过滤 + * 4. 将最终的素材根据优先级(priority)升序,创建时间(createAt)降序排序 + *

+ * + * @param req {@link ListMaterialByBannerCodeReq} + * @return 根据优先级(priority)升序,创建时间(createAt)降序排序后的列表 + */ @Override public ApiResult> 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)); } } diff --git a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/domain/ApplicationVersion.java b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/domain/ApplicationVersion.java index 18232ccb..eefe4e14 100644 --- a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/domain/ApplicationVersion.java +++ b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/domain/ApplicationVersion.java @@ -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 { /** * 跳转地址 - * 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 diff --git a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/domain/ApplicationVersionReadLog.java b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/domain/ApplicationVersionReadLog.java new file mode 100644 index 00000000..80e4b66b --- /dev/null +++ b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/domain/ApplicationVersionReadLog.java @@ -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 { + + /** + * 阅读人 + */ + @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; + +} diff --git a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/domain/Banner.java b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/domain/Banner.java index f92bb340..90c67baa 100644 --- a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/domain/Banner.java +++ b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/domain/Banner.java @@ -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 { @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 diff --git a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/domain/Material.java b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/domain/Material.java index 801c60d4..54b40a3c 100644 --- a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/domain/Material.java +++ b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/domain/Material.java @@ -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 { 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 { /** * 跳转地址 - * 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 diff --git a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/domain/MaterialPutLog.java b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/domain/MaterialPutLog.java new file mode 100644 index 00000000..8b228394 --- /dev/null +++ b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/domain/MaterialPutLog.java @@ -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 { + + /** + * 请求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 materialIds; +} diff --git a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/mapper/ApplicationVersionReadLogDao.java b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/mapper/ApplicationVersionReadLogDao.java new file mode 100644 index 00000000..da87e7fc --- /dev/null +++ b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/mapper/ApplicationVersionReadLogDao.java @@ -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 { +} diff --git a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/mapper/MaterialPutLogDao.java b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/mapper/MaterialPutLogDao.java new file mode 100644 index 00000000..0e28378d --- /dev/null +++ b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/mapper/MaterialPutLogDao.java @@ -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 { +} diff --git a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/rpc/ProfileGateway.java b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/rpc/ProfileGateway.java new file mode 100644 index 00000000..6843625a --- /dev/null +++ b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/rpc/ProfileGateway.java @@ -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 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 getProfiles(List personIds) { + if (CollectionUtil.isEmpty(personIds)) { + return Collections.emptyList(); + } + CommonResponse> personProfiles = userProfileServiceApi.getPersonProfiles(personIds); + if (Objects.nonNull(personProfiles) && personProfiles.getCode() == 200) { + return personProfiles.getData(); + } + return Collections.emptyList(); + } +} diff --git a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/ApplicationVersionReadLogService.java b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/ApplicationVersionReadLogService.java new file mode 100644 index 00000000..1ec38e73 --- /dev/null +++ b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/ApplicationVersionReadLogService.java @@ -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); +} diff --git a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/ApplicationVersionService.java b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/ApplicationVersionService.java index 169dd283..4118d7f4 100644 --- a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/ApplicationVersionService.java +++ b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/ApplicationVersionService.java @@ -23,4 +23,5 @@ public interface ApplicationVersionService { Page page(PageApplicationVersionReq req); GetVersionUpdateRemindContentResp getVersionUpdateRemindContent(GetVersionUpdateRemindContentReq req); + } diff --git a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/BannerOperationLogService.java b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/BannerOperationLogService.java index 0bb491c2..b08f6af9 100644 --- a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/BannerOperationLogService.java +++ b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/BannerOperationLogService.java @@ -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 page(PageBannerOperationLogReq req); } diff --git a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/MaterialPutLogService.java b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/MaterialPutLogService.java new file mode 100644 index 00000000..5dd70ab0 --- /dev/null +++ b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/MaterialPutLogService.java @@ -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); +} diff --git a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/MaterialService.java b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/MaterialService.java index 49b812de..4a993d32 100644 --- a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/MaterialService.java +++ b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/MaterialService.java @@ -28,7 +28,7 @@ public interface MaterialService { * @param req {@link ListMaterialByBannerCodeReq} * @return 根据优先级(priority)升序,创建时间(createAt)降序排序后的列表 */ - List listMaterialByBannerCode(ListMaterialByBannerCodeReq req); + List listMaterialByBannerCode(ListMaterialByBannerCodeReq req,String traceId); Page page(PageMaterialReq req); diff --git a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/impl/ApplicationVersionReadLogServiceImpl.java b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/impl/ApplicationVersionReadLogServiceImpl.java new file mode 100644 index 00000000..2ee6f45c --- /dev/null +++ b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/impl/ApplicationVersionReadLogServiceImpl.java @@ -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 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(); + } +} diff --git a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/impl/ApplicationVersionServiceImpl.java b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/impl/ApplicationVersionServiceImpl.java index 078c6802..e18ba6d5 100644 --- a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/impl/ApplicationVersionServiceImpl.java +++ b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/impl/ApplicationVersionServiceImpl.java @@ -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 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 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 page(PageApplicationVersionReq req) { + LambdaQueryWrapper lambdaQueryWrapper = buildPageLambdaQueryWrapper(req); + Page versionPage = page(new Page<>(req.getPageNumber(), req.getPageSize()), lambdaQueryWrapper); + if (Objects.isNull(versionPage) || versionPage.getTotal() == 0) { + return new Page<>(); + } + + List personIds = versionPage.getRecords().stream() + .map(ApplicationVersion::getUpdateBy) + .distinct() + .collect(Collectors.toList()); + + List profiles = profileGateway.getProfiles(personIds); + Map 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; + /** + * 校验版本号是否重复 + *

+ * 版本号+平台+操作系统,不可重复 + *

+ * + * @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 buildLambdaUpdateWrapper(UpdateApplicationVersionReq req) { + return new LambdaUpdateWrapper() + .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 buildPageLambdaQueryWrapper(PageApplicationVersionReq req) { + return new LambdaQueryWrapper() + .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 buildDeleteLambdaUpdateWrapper(Long id, Long personId) { + return new LambdaUpdateWrapper() + .eq(ApplicationVersion::getId, id) + .set(ApplicationVersion::getCreateBy, personId) + .set(ApplicationVersion::getIsDelete, 1); } } diff --git a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/impl/BannerOperationLogServiceImpl.java b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/impl/BannerOperationLogServiceImpl.java index 4c16b8a9..cddcad92 100644 --- a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/impl/BannerOperationLogServiceImpl.java +++ b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/impl/BannerOperationLogServiceImpl.java @@ -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 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 page(PageBannerOperationLogReq req) { + LambdaQueryWrapper pageLambdaQueryWrapper = buildPageLambdaQueryWrapper(req); + Page 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 buildPageLambdaQueryWrapper(PageBannerOperationLogReq req) { + LambdaQueryWrapper 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()); + } } diff --git a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/impl/BannerServiceImpl.java b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/impl/BannerServiceImpl.java index 371b1112..2b0b8312 100644 --- a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/impl/BannerServiceImpl.java +++ b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/impl/BannerServiceImpl.java @@ -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 implements BannerService { - private BannerOperationLogService bannerOperationLogService; + private final BannerOperationLogService bannerOperationLogService; /** * 分页查询banner @@ -49,10 +55,10 @@ public class BannerServiceImpl extends ServiceImpl implements */ @Override public Page page(PageBannerReq req) { - LambdaQueryChainWrapper pageLambdaQueryChain = buildPageLambdaQueryChain(req); + LambdaQueryWrapper pageLambdaQueryWrapper = buildPageLambdaQueryWrapper(req); - Page bannerPage = page(new Page<>(req.getPageNumber(), req.getPageSize()), pageLambdaQueryChain); - if (bannerPage.getTotal() == 0) { + Page 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 implements // 校验占位图宽高比例 req.getAspectRatio().checkAspectRatio(); + // 展示时间段类型校验 + checkDisplayTimeType(req); + Banner oldBanner = this.selectById(req.getId()); if (Objects.isNull(oldBanner)) { return; } - LambdaUpdateChainWrapper updateLambdaQueryChain = buildUpdateLambdaQueryChain(req); - update(updateLambdaQueryChain); + LambdaUpdateWrapper lambdaUpdateWrapper = buildUpdateLambdaQueryWrapper(req); + update(lambdaUpdateWrapper); Banner newBanner = this.selectById(req.getId()); @@ -146,6 +155,14 @@ public class BannerServiceImpl extends ServiceImpl 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 implements } } + /** + * 校验展示时间段类型 + *

+ * 此处不抽取Create和Update共同类型,所以这么写 + *

+ * + * @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 buildPageLambdaQueryChain(PageBannerReq req) { - return lambdaQuery() + private LambdaQueryWrapper buildPageLambdaQueryWrapper(PageBannerReq req) { + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper(); + 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 implements * @param req {@link UpdateBannerReq} * @return {@link LambdaUpdateChainWrapper} */ - private LambdaUpdateChainWrapper buildUpdateLambdaQueryChain(UpdateBannerReq req) { - return lambdaUpdate() + private LambdaUpdateWrapper buildUpdateLambdaQueryWrapper(UpdateBannerReq req) { + LambdaUpdateWrapper 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()); } } diff --git a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/impl/MaterialPutLogServiceImpl.java b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/impl/MaterialPutLogServiceImpl.java new file mode 100644 index 00000000..1700f916 --- /dev/null +++ b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/impl/MaterialPutLogServiceImpl.java @@ -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 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(); + } +} diff --git a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/impl/MaterialServiceImpl.java b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/impl/MaterialServiceImpl.java index f6d2430b..2cd53482 100644 --- a/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/impl/MaterialServiceImpl.java +++ b/banner/banner-server/src/main/java/cn/axzo/nanopart/server/service/impl/MaterialServiceImpl.java @@ -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 implements MaterialService { @@ -64,13 +77,20 @@ public class MaterialServiceImpl extends ServiceImpl 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 impl * @param req {@link ListMaterialByBannerCodeReq} * @return 根据优先级(priority)升序,创建时间(createAt)降序排序后的列表 */ + @Transactional(rollbackFor = Exception.class) @Override - public List 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 listMaterialByBannerCode(ListMaterialByBannerCodeReq req, String traceId) { + // 获取广告位并校验(是否存在,是否启用,是否在有效期) + if (Objects.isNull(validateBanner(req.getBannerCode()))) { + return Collections.emptyList(); } // 获取该广告位下已上架且在有效期内的所有素材 @@ -97,52 +114,39 @@ public class MaterialServiceImpl extends ServiceImpl 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 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 - * - *

- * 1.含义:指定素材给指定人按照投放频次类型投放次数 - * 2.组成:namespace:bannerCode:materialId:personId:频次类型转换后的值 - * 3.频次类型转换规则示例:投放频次类型参考{@link MaterialDisplayFrequencyTypeEnum} - * 有效期内:VALIDITY_PERIOD -> 有效期 - * 每天:EVERY_DAY -> 当天 - * 每周:EVERY_WEEK -> 当周第一天 - * 每月:EVERY_MONTH -> 当月第一天 - *

- * - * @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 impl */ @Override public Page page(PageMaterialReq req) { - LambdaQueryChainWrapper pageQueryLambdaWrapper = buildPageQueryLambdaWrapper(req); + LambdaQueryWrapper pageQueryLambdaWrapper = buildPageQueryLambdaWrapper(req); Page materialPage = page(new Page<>(req.getPageNumber(), req.getPageSize()), pageQueryLambdaWrapper); if (materialPage.getTotal() == 0) { @@ -203,7 +207,7 @@ public class MaterialServiceImpl extends ServiceImpl 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 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 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 buildPageQueryLambdaWrapper(PageMaterialReq req) { - return lambdaQuery() + private LambdaQueryWrapper buildPageQueryLambdaWrapper(PageMaterialReq req) { + LambdaQueryWrapper 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 impl * 构建通过BannerCode查询素材的wrapper * * @param req {@link ListMaterialByBannerCodeReq} - * @return {@link LambdaQueryChainWrapper} + * @return {@link LambdaQueryWrapper} */ - private LambdaQueryChainWrapper buildListByBannerCodeQueryWrapper(ListMaterialByBannerCodeReq req) { + private LambdaQueryWrapper buildListByBannerCodeQueryWrapper(ListMaterialByBannerCodeReq req) { Date now = new Date(System.currentTimeMillis()); - return lambdaQuery() + LambdaQueryWrapper 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 impl // Map> Map> 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> + Map> ouIdToWorkspaceMap = genericQuery.stream() + .filter(c -> c.getWorkspaceType() == 2) + .collect(Collectors.groupingBy(CooperateShipResp::getOrganizationalUnitId, + Collectors.mapping(CooperateShipResp::getWorkspaceId, Collectors.toList()))); + + // 项目部下的单位 Map + Map> workspaceToOuIdMap = genericQuery.stream() + .filter(c -> c.getWorkspaceType() == 2) + .collect(Collectors.groupingBy(CooperateShipResp::getWorkspaceId, + Collectors.mapping(CooperateShipResp::getOrganizationalUnitId, Collectors.toList()))); + // Map Map> workspaceToJobCodeMap = workspaceToTopNodeIdMap.entrySet().stream() .collect(Collectors.toMap(Map.Entry::getKey, @@ -381,7 +468,49 @@ public class MaterialServiceImpl extends ServiceImpl impl .distinct() .collect(Collectors.toList()))); - return new JoinedWorkspaceOuJob(workspaceToJobCodeMap, ouIdToJobCodeMap); + return new JoinedWorkspaceOuJob(workspaceToJobCodeMap, ouIdToJobCodeMap,ouIdToWorkspaceMap,workspaceToOuIdMap); + } + + /** + * 构建素材投放频次记录缓存key + * + *

+ * 1.含义:指定素材给指定人按照投放频次类型投放次数 + * 2.组成:namespace:bannerCode:materialId:personId:频次类型转换后的值 + * 3.频次类型转换规则示例:投放频次类型参考{@link MaterialDisplayFrequencyTypeEnum} + * 有效期内:VALIDITY_PERIOD -> 有效期 + * 每天:EVERY_DAY -> 当天 + * 每周:EVERY_WEEK -> 当周第一天 + * 每月:EVERY_MONTH -> 当月第一天 + *

+ * + * @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; } } diff --git a/nanopart-server/src/main/resources/application.yml b/nanopart-server/src/main/resources/application.yml index 1fd01c81..644e549c 100644 --- a/nanopart-server/src/main/resources/application.yml +++ b/nanopart-server/src/main/resources/application.yml @@ -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: