diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/notice/NoticeController.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/notice/NoticeController.java new file mode 100644 index 0000000..869de38 --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/notice/NoticeController.java @@ -0,0 +1,141 @@ +package com.fjrcloud.community.module.community.controller.admin.notice; + +import com.fjrcloud.community.framework.apilog.core.annotation.ApiAccessLog; +import com.fjrcloud.community.framework.common.pojo.CommonResult; +import com.fjrcloud.community.framework.common.pojo.PageParam; +import com.fjrcloud.community.framework.common.pojo.PageResult; +import com.fjrcloud.community.framework.common.util.object.BeanUtils; +import com.fjrcloud.community.framework.excel.core.util.ExcelUtils; +import com.fjrcloud.community.module.community.controller.admin.notice.vo.NoticePageReqVO; +import com.fjrcloud.community.module.community.controller.admin.notice.vo.NoticeRespVO; +import com.fjrcloud.community.module.community.controller.admin.notice.vo.NoticeSaveReqVO; +import com.fjrcloud.community.module.community.dal.dataobject.notice.NoticeDO; +import com.fjrcloud.community.module.community.dal.dataobject.notice.NoticeScopeDO; +import com.fjrcloud.community.module.community.dal.mysql.notice.NoticeScopeMapper; +import com.fjrcloud.community.module.community.service.notice.NoticeService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; + +import static com.fjrcloud.community.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static com.fjrcloud.community.framework.common.pojo.CommonResult.success; + +/** + * 管理后台 - 通知管理 + * + * @author fjrcloud + */ +@Tag(name = "管理后台 - 通知管理") +@RestController +@RequestMapping("/community/notice") +@Validated +public class NoticeController { + + @Resource + private NoticeService noticeService; + + @Resource + private NoticeScopeMapper noticeScopeMapper; + + @PostMapping("/create") + @Operation(summary = "创建通知") + @PreAuthorize("@ss.hasPermission('community:notice:create')") + public CommonResult createNotice(@Valid @RequestBody NoticeSaveReqVO createReqVO) { + return success(noticeService.createNotice(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新通知") + @PreAuthorize("@ss.hasPermission('community:notice:update')") + public CommonResult updateNotice(@Valid @RequestBody NoticeSaveReqVO updateReqVO) { + noticeService.updateNotice(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除通知") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('community:notice:delete')") + public CommonResult deleteNotice(@RequestParam("id") Long id) { + noticeService.deleteNotice(id); + return success(true); + } + + @DeleteMapping("/delete-list") + @Parameter(name = "ids", description = "编号", required = true) + @Operation(summary = "批量删除通知") + @PreAuthorize("@ss.hasPermission('community:notice:delete')") + public CommonResult deleteNoticeList(@RequestParam("ids") List ids) { + noticeService.deleteNoticeListByIds(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得通知") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('community:notice:query')") + public CommonResult getNotice(@RequestParam("id") Long id) { + NoticeDO notice = noticeService.getNotice(id); + NoticeRespVO respVO = BeanUtils.toBean(notice, NoticeRespVO.class); + + // 查询发布范围 + List scopeList = noticeScopeMapper.selectListByNoticeId(id); + if (scopeList != null && !scopeList.isEmpty()) { + respVO.setCommunityIds(scopeList.stream() + .map(NoticeScopeDO::getCommunityId) + .collect(Collectors.toList())); + } + + return success(respVO); + } + + @GetMapping("/page") + @Operation(summary = "获得通知分页") + @PreAuthorize("@ss.hasPermission('community:notice:query')") + public CommonResult> getNoticePage(@Valid NoticePageReqVO pageReqVO) { + PageResult pageResult = noticeService.getNoticePage(pageReqVO); + return success(BeanUtils.toBean(pageResult, NoticeRespVO.class)); + } + + @PutMapping("/publish") + @Operation(summary = "发布通知") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('community:notice:publish')") + public CommonResult publishNotice(@RequestParam("id") Long id) { + noticeService.publishNotice(id); + return success(true); + } + + @PutMapping("/revoke") + @Operation(summary = "撤回通知") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('community:notice:revoke')") + public CommonResult revokeNotice(@RequestParam("id") Long id) { + noticeService.revokeNotice(id); + return success(true); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出通知 Excel") + @PreAuthorize("@ss.hasPermission('community:notice:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportNoticeExcel(@Valid NoticePageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = noticeService.getNoticePage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "通知管理.xls", "数据", NoticeRespVO.class, + BeanUtils.toBean(list, NoticeRespVO.class)); + } + +} diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/notice/vo/NoticePageReqVO.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/notice/vo/NoticePageReqVO.java new file mode 100644 index 0000000..955e233 --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/notice/vo/NoticePageReqVO.java @@ -0,0 +1,34 @@ +package com.fjrcloud.community.module.community.controller.admin.notice.vo; + +import com.fjrcloud.community.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static com.fjrcloud.community.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +/** + * 管理后台 - 通知管理分页 Request VO + * + * @author fjrcloud + */ +@Schema(description = "管理后台 - 通知管理分页 Request VO") +@Data +public class NoticePageReqVO extends PageParam { + + @Schema(description = "公告标题", example = "春节通知") + private String title; + + @Schema(description = "状态(0-草稿,1-已发布,2-已过期,3-已撤回)", example = "1") + private Integer status; + + @Schema(description = "发布类型(1-立即发布,2-定时发布)", example = "1") + private Integer publishType; + + @Schema(description = "发布时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] publishTime; + +} diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/notice/vo/NoticeRespVO.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/notice/vo/NoticeRespVO.java new file mode 100644 index 0000000..5766c05 --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/notice/vo/NoticeRespVO.java @@ -0,0 +1,76 @@ +package com.fjrcloud.community.module.community.controller.admin.notice.vo; + +import cn.idev.excel.annotation.ExcelIgnoreUnannotated; +import cn.idev.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 管理后台 - 通知管理 Response VO + * + * @author fjrcloud + */ +@Schema(description = "管理后台 - 通知管理 Response VO") +@Data +@ExcelIgnoreUnannotated +public class NoticeRespVO { + + @Schema(description = "通知编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "公告标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "关于春节期间物业服务安排的通知") + @ExcelProperty("公告标题") + private String title; + + @Schema(description = "公告内容(富文本)", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("公告内容") + private String content; + + @Schema(description = "发布方", requiredMode = Schema.RequiredMode.REQUIRED, example = "物业管理处") + @ExcelProperty("发布方") + private String publisher; + + @Schema(description = "附件URL列表", example = "[\"https://xxx.com/file1.pdf\"]") + @ExcelProperty("附件") + private String attachments; + + @Schema(description = "发布类型(1-立即发布,2-定时发布)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("发布类型") + private Integer publishType; + + @Schema(description = "发布时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("发布时间") + private LocalDateTime publishTime; + + @Schema(description = "结束类型(1-长期有效,2-定时结束)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("结束类型") + private Integer endType; + + @Schema(description = "结束时间") + @ExcelProperty("结束时间") + private LocalDateTime endTime; + + @Schema(description = "是否消息推送", example = "true") + @ExcelProperty("消息推送") + private Boolean pushEnabled; + + @Schema(description = "状态(0-草稿,1-已发布,2-已过期,3-已撤回)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("状态") + private Integer status; + + @Schema(description = "浏览次数", example = "100") + @ExcelProperty("浏览次数") + private Integer viewCount; + + @Schema(description = "小区ID列表(发布范围)", example = "[1, 2, 3]") + private List communityIds; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/notice/vo/NoticeSaveReqVO.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/notice/vo/NoticeSaveReqVO.java new file mode 100644 index 0000000..8321877 --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/notice/vo/NoticeSaveReqVO.java @@ -0,0 +1,60 @@ +package com.fjrcloud.community.module.community.controller.admin.notice.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 管理后台 - 通知管理新增/修改 Request VO + * + * @author fjrcloud + */ +@Schema(description = "管理后台 - 通知管理新增/修改 Request VO") +@Data +public class NoticeSaveReqVO { + + @Schema(description = "通知编号", example = "1") + private Long id; + + @Schema(description = "公告标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "关于春节期间物业服务安排的通知") + @NotEmpty(message = "公告标题不能为空") + private String title; + + @Schema(description = "公告内容(富文本)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "公告内容不能为空") + private String content; + + @Schema(description = "发布方", requiredMode = Schema.RequiredMode.REQUIRED, example = "物业管理处") + @NotEmpty(message = "发布方不能为空") + private String publisher; + + @Schema(description = "附件URL列表(JSON数组)", example = "[\"https://xxx.com/file1.pdf\"]") + private String attachments; + + @Schema(description = "发布类型(1-立即发布,2-定时发布)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "发布类型不能为空") + private Integer publishType; + + @Schema(description = "发布时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "发布时间不能为空") + private LocalDateTime publishTime; + + @Schema(description = "结束类型(1-长期有效,2-定时结束)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "结束类型不能为空") + private Integer endType; + + @Schema(description = "结束时间") + private LocalDateTime endTime; + + @Schema(description = "是否消息推送", example = "true") + private Boolean pushEnabled; + + @Schema(description = "小区ID列表(发布范围)", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 2, 3]") + @NotNull(message = "发布范围不能为空") + private List communityIds; + +} diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/dataobject/notice/NoticeDO.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/dataobject/notice/NoticeDO.java new file mode 100644 index 0000000..be3aff7 --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/dataobject/notice/NoticeDO.java @@ -0,0 +1,87 @@ +package com.fjrcloud.community.module.community.dal.dataobject.notice; + +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fjrcloud.community.framework.mybatis.core.dataobject.BaseDO; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 通知管理 DO + * + * @author fjrcloud + */ +@TableName("comm_notice") +@KeySequence("comm_notice_seq") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class NoticeDO extends BaseDO { + + /** + * 通知编号 + */ + @TableId + private Long id; + + /** + * 公告标题 + */ + private String title; + + /** + * 公告内容(富文本) + */ + private String content; + + /** + * 发布方 + */ + private String publisher; + + /** + * 附件URL列表(JSON数组格式) + */ + private String attachments; + + /** + * 发布类型(1-立即发布,2-定时发布) + */ + private Integer publishType; + + /** + * 发布时间 + */ + private LocalDateTime publishTime; + + /** + * 结束类型(1-长期有效,2-定时结束) + */ + private Integer endType; + + /** + * 结束时间 + */ + private LocalDateTime endTime; + + /** + * 是否消息推送 + */ + private Boolean pushEnabled; + + /** + * 状态(0-草稿,1-已发布,2-已过期,3-已撤回) + */ + private Integer status; + + /** + * 浏览次数 + */ + private Integer viewCount; + +} diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/dataobject/notice/NoticeScopeDO.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/dataobject/notice/NoticeScopeDO.java new file mode 100644 index 0000000..fbe37eb --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/dataobject/notice/NoticeScopeDO.java @@ -0,0 +1,40 @@ +package com.fjrcloud.community.module.community.dal.dataobject.notice; + +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fjrcloud.community.framework.mybatis.core.dataobject.BaseDO; +import lombok.*; + +/** + * 通知小区关联 DO + * + * @author fjrcloud + */ +@TableName("comm_notice_scope") +@KeySequence("comm_notice_scope_seq") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class NoticeScopeDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + + /** + * 通知编号 + */ + private Long noticeId; + + /** + * 小区编号 + */ + private Long communityId; + +} diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/mysql/notice/NoticeMapper.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/mysql/notice/NoticeMapper.java new file mode 100644 index 0000000..3aaf05c --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/mysql/notice/NoticeMapper.java @@ -0,0 +1,33 @@ +package com.fjrcloud.community.module.community.dal.mysql.notice; + +import com.fjrcloud.community.framework.common.pojo.PageResult; +import com.fjrcloud.community.framework.mybatis.core.mapper.BaseMapperX; +import com.fjrcloud.community.framework.mybatis.core.query.LambdaQueryWrapperX; +import com.fjrcloud.community.module.community.controller.admin.notice.vo.NoticePageReqVO; +import com.fjrcloud.community.module.community.dal.dataobject.notice.NoticeDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 通知管理 Mapper + * + * @author fjrcloud + */ +@Mapper +public interface NoticeMapper extends BaseMapperX { + + /** + * 分页查询通知列表 + * + * @param reqVO 分页查询条件 + * @return 分页结果 + */ + default PageResult selectPage(NoticePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(NoticeDO::getTitle, reqVO.getTitle()) + .eqIfPresent(NoticeDO::getStatus, reqVO.getStatus()) + .eqIfPresent(NoticeDO::getPublishType, reqVO.getPublishType()) + .betweenIfPresent(NoticeDO::getPublishTime, reqVO.getPublishTime()) + .orderByDesc(NoticeDO::getId)); + } + +} diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/mysql/notice/NoticeScopeMapper.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/mysql/notice/NoticeScopeMapper.java new file mode 100644 index 0000000..eaedaa6 --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/mysql/notice/NoticeScopeMapper.java @@ -0,0 +1,55 @@ +package com.fjrcloud.community.module.community.dal.mysql.notice; + +import com.fjrcloud.community.framework.mybatis.core.mapper.BaseMapperX; +import com.fjrcloud.community.module.community.dal.dataobject.notice.NoticeScopeDO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 通知小区关联 Mapper + * + * @author fjrcloud + */ +@Mapper +public interface NoticeScopeMapper extends BaseMapperX { + + /** + * 根据通知ID查询小区关联列表 + * + * @param noticeId 通知ID + * @return 小区关联列表 + */ + default List selectListByNoticeId(Long noticeId) { + return selectList(NoticeScopeDO::getNoticeId, noticeId); + } + + /** + * 根据通知ID删除关联 + * + * @param noticeId 通知ID + * @return 删除数量 + */ + default int deleteByNoticeId(Long noticeId) { + return delete(NoticeScopeDO::getNoticeId, noticeId); + } + + /** + * 批量插入通知小区关联 + * + * @param noticeId 通知ID + * @param communityIds 小区ID列表 + * @return 插入数量 + */ + default int insertBatch(@Param("noticeId") Long noticeId, @Param("communityIds") List communityIds) { + List list = communityIds.stream() + .map(communityId -> NoticeScopeDO.builder() + .noticeId(noticeId) + .communityId(communityId) + .build()) + .collect(java.util.stream.Collectors.toList()); + return insertBatch(list); + } + +} diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/enums/ErrorCodeConstants.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/enums/ErrorCodeConstants.java index fe66234..facb31b 100644 --- a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/enums/ErrorCodeConstants.java +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/enums/ErrorCodeConstants.java @@ -33,5 +33,9 @@ public interface ErrorCodeConstants { ErrorCode BANNER_NOT_EXISTS = new ErrorCode(2_002_002_007, "banner不存在"); + ErrorCode NOTICE_NOT_EXISTS = new ErrorCode(2_004_000_000, "通知不存在"); + + ErrorCode NOTICE_NOT_DRAFT = new ErrorCode(2_004_000_003, "只有草稿状态的通知才能修改"); + ErrorCode MINI_APP_CONFIG_NOT_EXISTS = new ErrorCode(2_003_002_007, "小程序配置不存在"); } diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/enums/notice/EndTypeEnum.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/enums/notice/EndTypeEnum.java new file mode 100644 index 0000000..7e69b90 --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/enums/notice/EndTypeEnum.java @@ -0,0 +1,28 @@ +package com.fjrcloud.community.module.community.enums.notice; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 通知结束类型枚举 + * + * @author fjrcloud + */ +@Getter +@AllArgsConstructor +public enum EndTypeEnum { + + PERMANENT(1, "长期有效"), + SCHEDULED(2, "定时结束"); + + /** + * 类型值 + */ + private final Integer type; + + /** + * 类型描述 + */ + private final String desc; + +} diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/enums/notice/NoticeStatusEnum.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/enums/notice/NoticeStatusEnum.java new file mode 100644 index 0000000..1c01027 --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/enums/notice/NoticeStatusEnum.java @@ -0,0 +1,30 @@ +package com.fjrcloud.community.module.community.enums.notice; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 通知状态枚举 + * + * @author fjrcloud + */ +@Getter +@AllArgsConstructor +public enum NoticeStatusEnum { + + DRAFT(0, "草稿"), + PUBLISHED(1, "已发布"), + EXPIRED(2, "已过期"), + REVOKED(3, "已撤回"); + + /** + * 状态值 + */ + private final Integer status; + + /** + * 状态描述 + */ + private final String desc; + +} diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/enums/notice/PublishTypeEnum.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/enums/notice/PublishTypeEnum.java new file mode 100644 index 0000000..d866b1c --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/enums/notice/PublishTypeEnum.java @@ -0,0 +1,28 @@ +package com.fjrcloud.community.module.community.enums.notice; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 通知发布类型枚举 + * + * @author fjrcloud + */ +@Getter +@AllArgsConstructor +public enum PublishTypeEnum { + + IMMEDIATE(1, "立即发布"), + SCHEDULED(2, "定时发布"); + + /** + * 类型值 + */ + private final Integer type; + + /** + * 类型描述 + */ + private final String desc; + +} diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/job/NoticeExpireJob.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/job/NoticeExpireJob.java new file mode 100644 index 0000000..7e7d628 --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/job/NoticeExpireJob.java @@ -0,0 +1,31 @@ +package com.fjrcloud.community.module.community.job.notice; + +import cn.hutool.core.util.StrUtil; +import com.fjrcloud.community.framework.quartz.core.handler.JobHandler; +import com.fjrcloud.community.framework.tenant.core.job.TenantJob; +import com.fjrcloud.community.module.community.service.notice.NoticeService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 通知定时过期 Job + * + * 扫描 endTime 已到且状态为已发布的通知,自动标记为已过期 + * + * @author fjrcloud + */ +@Component +public class NoticeExpireJob implements JobHandler { + + @Resource + private NoticeService noticeService; + + @Override + @TenantJob + public String execute(String param) { + int count = noticeService.autoExpireNotices(); + return StrUtil.format("自动过期通知 {} 个", count); + } + +} diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/job/NoticePublishJob.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/job/NoticePublishJob.java new file mode 100644 index 0000000..7ab348d --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/job/NoticePublishJob.java @@ -0,0 +1,31 @@ +package com.fjrcloud.community.module.community.job; + +import cn.hutool.core.util.StrUtil; +import com.fjrcloud.community.framework.quartz.core.handler.JobHandler; +import com.fjrcloud.community.framework.tenant.core.job.TenantJob; +import com.fjrcloud.community.module.community.service.notice.NoticeService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 通知定时发布 Job + * + * 扫描 publishTime 已到且状态为草稿的通知,自动发布 + * + * @author fjrcloud + */ +@Component +public class NoticePublishJob implements JobHandler { + + @Resource + private NoticeService noticeService; + + @Override + @TenantJob + public String execute(String param) { + int count = noticeService.autoPublishNotices(); + return StrUtil.format("自动发布通知 {} 个", count); + } + +} diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/service/notice/NoticeService.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/service/notice/NoticeService.java new file mode 100644 index 0000000..3ea74ff --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/service/notice/NoticeService.java @@ -0,0 +1,91 @@ +package com.fjrcloud.community.module.community.service.notice; + +import com.fjrcloud.community.framework.common.pojo.PageResult; +import com.fjrcloud.community.module.community.controller.admin.notice.vo.NoticePageReqVO; +import com.fjrcloud.community.module.community.controller.admin.notice.vo.NoticeSaveReqVO; +import com.fjrcloud.community.module.community.dal.dataobject.notice.NoticeDO; + +import javax.validation.Valid; +import java.util.List; + +/** + * 通知管理 Service 接口 + * + * @author fjrcloud + */ +public interface NoticeService { + + /** + * 创建通知 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createNotice(@Valid NoticeSaveReqVO createReqVO); + + /** + * 更新通知 + * + * @param updateReqVO 更新信息 + */ + void updateNotice(@Valid NoticeSaveReqVO updateReqVO); + + /** + * 删除通知 + * + * @param id 编号 + */ + void deleteNotice(Long id); + + /** + * 批量删除通知 + * + * @param ids 编号列表 + */ + void deleteNoticeListByIds(List ids); + + /** + * 获得通知 + * + * @param id 编号 + * @return 通知 + */ + NoticeDO getNotice(Long id); + + /** + * 获得通知分页 + * + * @param pageReqVO 分页查询 + * @return 通知分页 + */ + PageResult getNoticePage(NoticePageReqVO pageReqVO); + + /** + * 发布通知 + * + * @param id 通知ID + */ + void publishNotice(Long id); + + /** + * 撤回通知 + * + * @param id 通知ID + */ + void revokeNotice(Long id); + + /** + * 自动发布到期的通知(定时任务调用) + * + * @return 发布数量 + */ + int autoPublishNotices(); + + /** + * 自动过期到期的通知(定时任务调用) + * + * @return 过期数量 + */ + int autoExpireNotices(); + +} diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/service/notice/NoticeServiceImpl.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/service/notice/NoticeServiceImpl.java new file mode 100644 index 0000000..8008019 --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/service/notice/NoticeServiceImpl.java @@ -0,0 +1,231 @@ +package com.fjrcloud.community.module.community.service.notice; + +import com.fjrcloud.community.framework.common.pojo.PageResult; +import com.fjrcloud.community.framework.common.util.object.BeanUtils; +import com.fjrcloud.community.module.community.controller.admin.notice.vo.NoticePageReqVO; +import com.fjrcloud.community.module.community.controller.admin.notice.vo.NoticeSaveReqVO; +import com.fjrcloud.community.module.community.dal.dataobject.notice.NoticeDO; +import com.fjrcloud.community.module.community.dal.mysql.notice.NoticeMapper; +import com.fjrcloud.community.module.community.dal.mysql.notice.NoticeScopeMapper; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.List; + +import static com.fjrcloud.community.framework.common.exception.util.ServiceExceptionUtil.exception; +import static com.fjrcloud.community.module.community.enums.ErrorCodeConstants.NOTICE_NOT_DRAFT; +import static com.fjrcloud.community.module.community.enums.ErrorCodeConstants.NOTICE_NOT_EXISTS; + +/** + * 通知管理 Service 实现类 + * + * @author fjrcloud + */ +@Service +@Validated +public class NoticeServiceImpl implements NoticeService { + + @Resource + private NoticeMapper noticeMapper; + + @Resource + private NoticeScopeMapper noticeScopeMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createNotice(NoticeSaveReqVO createReqVO) { + // 插入通知 + NoticeDO notice = BeanUtils.toBean(createReqVO, NoticeDO.class); + + // 根据发布类型设置状态:1-立即发布直接设为已发布,2-定时发布设为草稿 + if (createReqVO.getPublishType() == 1) { + notice.setStatus(1); // 已发布 + notice.setPublishTime(LocalDateTime.now()); + } else { + notice.setStatus(0); // 草稿 + } + notice.setViewCount(0); + noticeMapper.insert(notice); + + // 插入通知小区关联 + if (createReqVO.getCommunityIds() != null && !createReqVO.getCommunityIds().isEmpty()) { + noticeScopeMapper.insertBatch(notice.getId(), createReqVO.getCommunityIds()); + } + + return notice.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateNotice(NoticeSaveReqVO updateReqVO) { + // 校验存在 + NoticeDO oldNotice = validateNoticeExists(updateReqVO.getId()); + + // 如果原状态是已发布、已过期或已撤回,不允许修改 + if (oldNotice.getStatus() != 0) { + throw exception(NOTICE_NOT_DRAFT); + } + + // 更新通知 + NoticeDO updateObj = BeanUtils.toBean(updateReqVO, NoticeDO.class); + + // 根据发布类型设置状态:1-立即发布直接设为已发布,2-定时发布设为草稿 + if (updateReqVO.getPublishType() == 1) { + updateObj.setStatus(1); // 已发布 + updateObj.setPublishTime(LocalDateTime.now()); + } else { + updateObj.setStatus(0); // 草稿 + } + + noticeMapper.updateById(updateObj); + + // 更新通知小区关联:先删除旧的,再插入新的 + noticeScopeMapper.deleteByNoticeId(updateReqVO.getId()); + if (updateReqVO.getCommunityIds() != null && !updateReqVO.getCommunityIds().isEmpty()) { + noticeScopeMapper.insertBatch(updateReqVO.getId(), updateReqVO.getCommunityIds()); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteNotice(Long id) { + // 校验存在 + validateNoticeExists(id); + // 删除通知 + noticeMapper.deleteById(id); + // 删除通知小区关联 + noticeScopeMapper.deleteByNoticeId(id); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteNoticeListByIds(List ids) { + // 删除通知 + noticeMapper.deleteByIds(ids); + // 删除通知小区关联 + for (Long id : ids) { + noticeScopeMapper.deleteByNoticeId(id); + } + } + + @Override + public NoticeDO getNotice(Long id) { + return noticeMapper.selectById(id); + } + + @Override + public PageResult getNoticePage(NoticePageReqVO pageReqVO) { + return noticeMapper.selectPage(pageReqVO); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void publishNotice(Long id) { + // 校验存在 + NoticeDO notice = validateNoticeExists(id); + + // 校验状态 + if (notice.getStatus() != 0) { + throw exception(new com.fjrcloud.community.framework.common.exception.ErrorCode(2_004_000_001, "只有草稿状态的通知才能发布")); + } + + // 更新状态为已发布 + NoticeDO updateObj = new NoticeDO(); + updateObj.setId(id); + updateObj.setStatus(1); + updateObj.setPublishTime(LocalDateTime.now()); + noticeMapper.updateById(updateObj); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void revokeNotice(Long id) { + // 校验存在 + NoticeDO notice = validateNoticeExists(id); + + // 校验状态 + if (notice.getStatus() != 1) { + throw exception(new com.fjrcloud.community.framework.common.exception.ErrorCode(2_004_000_002, "只有已发布状态的通知才能撤回")); + } + + // 更新状态为已撤回 + NoticeDO updateObj = new NoticeDO(); + updateObj.setId(id); + updateObj.setStatus(3); + noticeMapper.updateById(updateObj); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int autoPublishNotices() { + // 查询需要发布的通知:草稿状态 + 发布时间已到 + LocalDateTime now = LocalDateTime.now(); + List notices = noticeMapper.selectList(new com.fjrcloud.community.framework.mybatis.core.query.LambdaQueryWrapperX() + .eq(NoticeDO::getStatus, 0) // 草稿状态 + .eq(NoticeDO::getPublishType, 2) // 定时发布 + .le(NoticeDO::getPublishTime, now) // 发布时间已到 + ); + + if (notices == null || notices.isEmpty()) { + return 0; + } + + // 批量更新状态为已发布 + int count = 0; + for (NoticeDO notice : notices) { + NoticeDO updateObj = new NoticeDO(); + updateObj.setId(notice.getId()); + updateObj.setStatus(1); // 已发布 + noticeMapper.updateById(updateObj); + count++; + } + + return count; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int autoExpireNotices() { + // 查询需要过期的通知:已发布状态 + 结束类型是定时结束 + 结束时间已到 + LocalDateTime now = LocalDateTime.now(); + List notices = noticeMapper.selectList(new com.fjrcloud.community.framework.mybatis.core.query.LambdaQueryWrapperX() + .eq(NoticeDO::getStatus, 1) // 已发布状态 + .eq(NoticeDO::getEndType, 2) // 定时结束 + .le(NoticeDO::getEndTime, now) // 结束时间已到 + ); + + if (notices == null || notices.isEmpty()) { + return 0; + } + + // 批量更新状态为已过期 + int count = 0; + for (NoticeDO notice : notices) { + NoticeDO updateObj = new NoticeDO(); + updateObj.setId(notice.getId()); + updateObj.setStatus(2); // 已过期 + noticeMapper.updateById(updateObj); + count++; + } + + return count; + } + + /** + * 校验通知是否存在 + * + * @param id 通知ID + * @return 通知对象 + */ + private NoticeDO validateNoticeExists(Long id) { + NoticeDO notice = noticeMapper.selectById(id); + if (notice == null) { + throw exception(NOTICE_NOT_EXISTS); + } + return notice; + } + +} diff --git a/fjrcloud-module-community/src/main/resources/mapper/notice/NoticeMapper.xml b/fjrcloud-module-community/src/main/resources/mapper/notice/NoticeMapper.xml new file mode 100644 index 0000000..5100381 --- /dev/null +++ b/fjrcloud-module-community/src/main/resources/mapper/notice/NoticeMapper.xml @@ -0,0 +1,12 @@ + + + + + + +