diff --git a/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/constant/FirstAidConstants.java b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/constant/FirstAidConstants.java index b4f5a25..17f548b 100644 --- a/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/constant/FirstAidConstants.java +++ b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/constant/FirstAidConstants.java @@ -32,6 +32,7 @@ public interface FirstAidConstants { /** 已驳回 */ Integer AUDIT_STATUS_REJECTED = 12; + // ========== 发布状态 ========== /** 草稿 */ Integer STATUS_DRAFT = 0; diff --git a/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/dto/IdDTO.java b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/dto/IdDTO.java new file mode 100644 index 0000000..d6a8132 --- /dev/null +++ b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/dto/IdDTO.java @@ -0,0 +1,16 @@ +package com.renkang.emergency.dto; + +import lombok.Data; + +/** + * 通用ID入参DTO + * 用于单参数POST操作接口(删除/审核/上下架/收藏/回滚等) + * + * @Author: jeecg-boot + * @Date: 2026-06-24 + */ +@Data +public class IdDTO { + + private String id; +} diff --git a/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/dto/PushBatchSendDTO.java b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/dto/PushBatchSendDTO.java new file mode 100644 index 0000000..cf04bae --- /dev/null +++ b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/dto/PushBatchSendDTO.java @@ -0,0 +1,24 @@ +package com.renkang.emergency.dto; + +import lombok.Data; + +import java.util.List; + +/** + * 批量推送入参DTO + * + * @Author: jeecg-boot + * @Date: 2026-06-24 + */ +@Data +public class PushBatchSendDTO { + + /** 工单ID(必填) */ + private String orderId; + + /** 资源ID列表(方式一:指定ID) */ + private List resourceIds; + + /** 筛选条件(方式二:按条件批量推送),与 resourceIds 二选一 */ + private PushFilterDTO filterParams; +} diff --git a/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/dto/PushFilterDTO.java b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/dto/PushFilterDTO.java new file mode 100644 index 0000000..fe8dee4 --- /dev/null +++ b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/dto/PushFilterDTO.java @@ -0,0 +1,19 @@ +package com.renkang.emergency.dto; + +import lombok.Data; + +/** + * 推送资源筛选条件DTO + * + * @Author: jeecg-boot + * @Date: 2026-06-24 + */ +@Data +public class PushFilterDTO { + + private String keyword; + + private String categoryId; + + private String contentType; +} diff --git a/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/dto/RejectDTO.java b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/dto/RejectDTO.java new file mode 100644 index 0000000..60d50f7 --- /dev/null +++ b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/dto/RejectDTO.java @@ -0,0 +1,17 @@ +package com.renkang.emergency.dto; + +import lombok.Data; + +/** + * 审核驳回入参DTO + * + * @Author: jeecg-boot + * @Date: 2026-06-24 + */ +@Data +public class RejectDTO { + + private String id; + + private String reason; +} diff --git a/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/entity/FirstAidPushRecord.java b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/entity/FirstAidPushRecord.java new file mode 100644 index 0000000..fa37a47 --- /dev/null +++ b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/entity/FirstAidPushRecord.java @@ -0,0 +1,58 @@ +package com.renkang.emergency.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serializable; +import java.util.Date; + +/** + * @Description: 急救宣教推送记录 + * @Author: jeecg-boot + * @Date: 2026-06-24 + */ +@Data +@TableName("QH_EME_FIRST_AID_PUSH_RECORD") +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@Schema(title = "first_aid_push_record对象", description = "急救宣教推送记录") +public class FirstAidPushRecord implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.ASSIGN_ID) + @Schema(title = "id") + private String id; + + @Schema(title = "资源ID") + private String resourceId; + + @Schema(title = "资源标题") + private String resourceTitle; + + @Schema(title = "关联应急工单ID") + private String orderId; + + @Schema(title = "推送目标用户ID") + private String targetUserId; + + @Schema(title = "推送人") + private String pushBy; + + @Schema(title = "推送人ID") + private String pushById; + + @Schema(title = "推送时间") + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date pushTime; + + @Schema(title = "租户ID") + private String tenantId; +} diff --git a/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/entity/FirstAidResource.java b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/entity/FirstAidResource.java index 9d03420..1da5eb4 100644 --- a/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/entity/FirstAidResource.java +++ b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/entity/FirstAidResource.java @@ -92,17 +92,23 @@ public class FirstAidResource implements Serializable { /** 审核状态(null=无审核,10=待审核,11=已通过,12=已驳回) */ @Excel(name = "审核状态", width = 15, dicCode = "first_aid_audit_status") @Schema(title = "审核状态(null=无审核,10=待审核,11=已通过,12=已驳回)") + @TableField(updateStrategy = FieldStrategy.IGNORED) private Integer auditStatus; /** 驳回原因 */ @Excel(name = "驳回原因", width = 30) @Schema(title = "驳回原因") + @TableField(updateStrategy = FieldStrategy.IGNORED) private String auditRejectReason; /** 审核人 */ @Schema(title = "审核人") private String auditBy; + /** 审核人ID */ + @Schema(title = "审核人ID") + private String auditById; + /** 审核时间 */ @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") @@ -174,4 +180,9 @@ public class FirstAidResource implements Serializable { @TableField(exist = false) @Schema(title = "复合状态(0=草稿,1=已发布,2=已下架,10=待审核,11=已通过,12=已驳回)") private Integer combinedStatus; + + /** 当前工单下是否已推送(非持久字段) */ + @TableField(exist = false) + @Schema(title = "当前工单下是否已推送") + private Boolean pushed; } diff --git a/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/entity/FirstAidResourceAudit.java b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/entity/FirstAidResourceAudit.java new file mode 100644 index 0000000..a06274b --- /dev/null +++ b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/entity/FirstAidResourceAudit.java @@ -0,0 +1,72 @@ +package com.renkang.emergency.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serializable; +import java.util.Date; + +/** + * @Description: 急救宣教资源审核记录 + * @Author: jeecg-boot + * @Date: 2026-06-24 + * @Version: V1.0 + */ +@Data +@TableName("QH_EME_FIRST_AID_RESOURCE_AUDIT") +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@Schema(title = "first_aid_resource_audit对象", description = "急救宣教资源审核记录") +public class FirstAidResourceAudit implements Serializable { + private static final long serialVersionUID = 1L; + + /** id */ + @TableId(type = IdType.ASSIGN_ID) + @Schema(title = "id") + private String id; + + /** 资源ID */ + @Schema(title = "资源ID") + private String resourceId; + + /** 审核状态(10=待审核, 11=已通过, 12=已驳回) */ + @Schema(title = "审核状态") + private Integer auditStatus; + + /** 驳回原因 */ + @Schema(title = "驳回原因") + private String auditRejectReason; + + /** 审核人 */ + @Schema(title = "审核人") + private String auditBy; + + /** 审核人ID */ + @Schema(title = "审核人ID") + private String auditById; + + /** 审核时间 */ + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(title = "审核时间") + private Date auditTime; + + /** 创建时间 */ + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(title = "创建时间") + private Date createTime; + + /** 资源标题(非持久字段,查询时填充) */ + @TableField(exist = false) + @Schema(title = "资源标题") + private String resourceTitle; +} diff --git a/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/entity/FirstAidResourceVersion.java b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/entity/FirstAidResourceVersion.java index 8c5304a..595feea 100644 --- a/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/entity/FirstAidResourceVersion.java +++ b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/entity/FirstAidResourceVersion.java @@ -58,4 +58,8 @@ public class FirstAidResourceVersion implements Serializable { @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") @Schema(title = "创建时间") private java.util.Date createTime; + + /** 是否当前版本(true=当前版本, false=历史快照) */ + @Schema(title = "是否当前版本") + private Boolean isCurrent; } diff --git a/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/service/IFirstAidPushService.java b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/service/IFirstAidPushService.java new file mode 100644 index 0000000..2114106 --- /dev/null +++ b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/service/IFirstAidPushService.java @@ -0,0 +1,30 @@ +package com.renkang.emergency.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.renkang.emergency.dto.PushBatchSendDTO; +import com.renkang.emergency.dto.PushFilterDTO; +import com.renkang.emergency.entity.FirstAidResource; + +/** + * @Description: 急救宣教推送Service + * @Author: jeecg-boot + * @Date: 2026-06-24 + */ +public interface IFirstAidPushService { + + /** + * 查询可推送资源列表(已发布+已审核),并标记当前工单下是否已推送 + */ + IPage queryResourceList(String orderId, PushFilterDTO filter, Page page); + + /** + * 推送单条资源 + */ + void send(String resourceId, String orderId); + + /** + * 批量推送 + */ + int batchSend(PushBatchSendDTO dto); +} diff --git a/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/vo/FirstAidResourceExportVO.java b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/vo/FirstAidResourceExportVO.java new file mode 100644 index 0000000..14b600d --- /dev/null +++ b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/vo/FirstAidResourceExportVO.java @@ -0,0 +1,39 @@ +package com.renkang.emergency.vo; + +import lombok.Data; +import org.jeecgframework.poi.excel.annotation.Excel; + +import java.util.Date; + +/** + * @Description: 急救宣教资源-导出VO + * @Author: jeecg-boot + * @Date: 2026-06-24 + */ +@Data +public class FirstAidResourceExportVO { + + @Excel(name = "标题", width = 30) + private String title; + + @Excel(name = "摘要", width = 30) + private String summary; + + @Excel(name = "分类", width = 15) + private String categoryName; + + @Excel(name = "类型", width = 15, dicCode = "first_aid_content_type") + private String contentType; + + @Excel(name = "标签", width = 30) + private String tagNames; + + @Excel(name = "状态", width = 15) + private String statusText; + + @Excel(name = "阅读/收藏", width = 15) + private String viewFavorite; + + @Excel(name = "创建时间", width = 20, format = "yyyy-MM-dd HH:mm:ss") + private Date createTime; +} diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidPushController.java b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidPushController.java new file mode 100644 index 0000000..eeedf20 --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidPushController.java @@ -0,0 +1,99 @@ +package com.renkang.emergency.controller; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.renkang.emergency.dto.PushBatchSendDTO; +import com.renkang.emergency.dto.PushFilterDTO; +import com.renkang.emergency.entity.FirstAidResource; +import com.renkang.emergency.service.IFirstAidPushService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.jeecg.common.api.vo.Result; +import org.jeecg.common.aspect.annotation.AutoLog; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +/** + * @Description: 急救宣教资源-推送管理 + * @Author: jeecg-boot + * @Date: 2026-06-24 + */ +@Tag(name = "急救宣教资源-推送管理") +@RestController +@RequestMapping("/emergency/firstAid/push") +@Slf4j +public class FirstAidPushController { + + @Autowired + private IFirstAidPushService pushService; + + /** + * 可推送资源列表(已发布+已审核通过,含当前工单推送状态) + */ + @Operation(summary = "可推送资源列表", description = "查询已发布且审核通过、当前有效的资源,标记当前工单下是否已推送") + @GetMapping(value = "/resourceList") + public Result> resourceList( + @RequestParam(name = "orderId", required = false) String orderId, + @RequestParam(name = "keyword", required = false) String keyword, + @RequestParam(name = "categoryId", required = false) String categoryId, + @RequestParam(name = "contentType", required = false) String contentType, + @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(name = "pageSize", defaultValue = "20") Integer pageSize) { + + PushFilterDTO filter = new PushFilterDTO(); + filter.setKeyword(keyword); + filter.setCategoryId(categoryId); + filter.setContentType(contentType); + + Page page = new Page<>(pageNo, pageSize); + IPage result = pushService.queryResourceList(orderId, filter, page); + return Result.OK(result); + } + + /** + * 推送单条资源 + */ + @AutoLog(value = "急救宣教资源-推送单条") + @Operation(summary = "推送单条资源", description = "将指定资源推送给工单关联的求助者") + @PostMapping(value = "/send") + public Result send(@RequestBody Map params) { + String resourceId = params.get("resourceId"); + String orderId = params.get("orderId"); + if (resourceId == null || resourceId.isEmpty()) { + return Result.error("资源ID不能为空"); + } + if (orderId == null || orderId.isEmpty()) { + return Result.error("工单ID不能为空"); + } + try { + pushService.send(resourceId, orderId); + } catch (RuntimeException e) { + return Result.error(e.getMessage()); + } + return Result.OK("推送成功"); + } + + /** + * 一键推送(批量) + */ + @AutoLog(value = "急救宣教资源-批量推送") + @Operation(summary = "一键推送", description = "批量推送资源,支持指定ID列表或按筛选条件全量推送") + @PostMapping(value = "/batchSend") + public Result> batchSend(@RequestBody PushBatchSendDTO dto) { + if (dto.getOrderId() == null || dto.getOrderId().isEmpty()) { + return Result.error("工单ID不能为空"); + } + try { + int count = pushService.batchSend(dto); + Map result = new HashMap<>(); + result.put("count", count); + return Result.OK("已推送 " + count + " 条", result); + } catch (RuntimeException e) { + return Result.error(e.getMessage()); + } + } +} diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceAuditController.java b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceAuditController.java index 2ac48f4..18e74ff 100644 --- a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceAuditController.java +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceAuditController.java @@ -1,10 +1,15 @@ package com.renkang.emergency.controller; +import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.renkang.emergency.constant.FirstAidConstants; +import com.renkang.emergency.dto.IdDTO; +import com.renkang.emergency.dto.RejectDTO; import com.renkang.emergency.entity.FirstAidResource; +import com.renkang.emergency.entity.FirstAidResourceAudit; +import com.renkang.emergency.service.IFirstAidResourceAuditService; import com.renkang.emergency.service.IFirstAidResourceService; import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.Operation; @@ -14,6 +19,10 @@ import org.jeecg.common.aspect.annotation.AutoLog; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + /** * @Description: 急救宣教资源-审核管理 * @Author: jeecg-boot @@ -29,6 +38,9 @@ public class FirstAidResourceAuditController { @Autowired private IFirstAidResourceService resourceService; + @Autowired + private IFirstAidResourceAuditService auditService; + /** * 待审核列表(支持标题/分类/内容类型筛选) */ @@ -75,9 +87,9 @@ public class FirstAidResourceAuditController { //@RequiresPermissions("emergency:firstAidAudit:approve") @Operation(summary = "审核通过") @PostMapping(value = "/approve") - public Result approve(@RequestParam(name = "id", required = true) String id) { + public Result approve(@RequestBody IdDTO dto) { try { - resourceService.approve(id); + resourceService.approve(dto.getId()); } catch (RuntimeException e) { return Result.error(e.getMessage()); } @@ -91,13 +103,12 @@ public class FirstAidResourceAuditController { //@RequiresPermissions("emergency:firstAidAudit:reject") @Operation(summary = "审核驳回") @PostMapping(value = "/reject") - public Result reject(@RequestParam(name = "id", required = true) String id, - @RequestParam(name = "reason", required = true) String reason) { - if (StrUtil.isBlank(reason)) { + public Result reject(@RequestBody RejectDTO dto) { + if (StrUtil.isBlank(dto.getReason())) { return Result.error("驳回原因不能为空"); } try { - resourceService.reject(id, reason); + resourceService.reject(dto.getId(), dto.getReason()); } catch (RuntimeException e) { return Result.error(e.getMessage()); } @@ -105,20 +116,29 @@ public class FirstAidResourceAuditController { } /** - * 审核记录列表(合并待审核/已通过/已驳回的全部审核操作日志) + * 审核记录列表(从审计表查询,支持按审核动作和日期范围筛选) */ - @Operation(summary = "审核记录列表", description = "查询所有已审核的资源记录,支持按操作类型和日期范围筛选") + @Operation(summary = "审核记录列表", description = "查询审核记录,支持按审核状态和日期范围筛选") @GetMapping(value = "/records") - public Result> records(FirstAidResource entity, - @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, - @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, - @RequestParam(name = "startDate", required = false) String startDate, - @RequestParam(name = "endDate", required = false) String endDate) { - Page page = new Page<>(pageNo, pageSize); - // 不传auditStatus时默认查所有已审核的(>=10),传了则按指定类型查 - if (entity.getAuditStatus() == null) { - entity.setAuditStatus(10); // 查所有 >=10 的已审核记录: 10=待审核, 11=已通过, 12=已驳回 + public Result> records( + @RequestParam(name = "resourceTitle", required = false) String resourceTitle, + @RequestParam(name = "auditStatus", required = false) Integer auditStatus, + @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, + @RequestParam(name = "startDate", required = false) String startDate, + @RequestParam(name = "endDate", required = false) String endDate) { + Page page = new Page<>(pageNo, pageSize); + IPage result = auditService.queryAuditRecords(page, resourceTitle, auditStatus, startDate, endDate); + // 批量填充资源标题 + if (CollectionUtil.isNotEmpty(result.getRecords())) { + List resourceIds = result.getRecords().stream() + .map(FirstAidResourceAudit::getResourceId) + .distinct() + .collect(Collectors.toList()); + Map titleMap = resourceService.listByIds(resourceIds).stream() + .collect(Collectors.toMap(FirstAidResource::getId, FirstAidResource::getTitle, (a, b) -> a)); + result.getRecords().forEach(audit -> audit.setResourceTitle(titleMap.get(audit.getResourceId()))); } - return Result.OK(resourceService.queryAuditRecords(entity, page, startDate, endDate)); + return Result.OK(result); } } diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceCategoryController.java b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceCategoryController.java index 9d8cd18..c514227 100644 --- a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceCategoryController.java +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceCategoryController.java @@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.renkang.emergency.constant.FirstAidConstants; +import com.renkang.emergency.dto.IdDTO; import com.renkang.emergency.entity.FirstAidResourceCategory; import com.renkang.emergency.service.IFirstAidResourceCategoryService; import io.swagger.v3.oas.annotations.tags.Tag; @@ -76,6 +77,11 @@ public class FirstAidResourceCategoryController extends JeecgController() + .eq("name", entity.getName()) + .eq("type", FirstAidConstants.TYPE_CATEGORY)) > 0) { + return Result.error("分类名称已存在"); + } categoryService.save(entity); return Result.OK("添加成功!"); } @@ -87,6 +93,12 @@ public class FirstAidResourceCategoryController extends JeecgController edit(@RequestBody FirstAidResourceCategory entity) { FirstAidResourceCategory old = categoryService.getById(entity.getId()); if (old == null) return Result.error("数据不存在"); + if (categoryService.count(new QueryWrapper() + .eq("name", entity.getName()) + .eq("type", FirstAidConstants.TYPE_CATEGORY) + .ne("id", entity.getId())) > 0) { + return Result.error("分类名称已存在"); + } entity.setType(old.getType()); categoryService.updateById(entity); return Result.OK("编辑成功!"); @@ -96,9 +108,9 @@ public class FirstAidResourceCategoryController extends JeecgController delete(@RequestParam(name = "id") String id) { + public Result delete(@RequestBody IdDTO dto) { try { - categoryService.deleteWithCheck(id); + categoryService.deleteWithCheck(dto.getId()); } catch (RuntimeException e) { return Result.error(e.getMessage()); } diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceController.java b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceController.java index 25c948b..516e1e0 100644 --- a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceController.java +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceController.java @@ -1,23 +1,33 @@ package com.renkang.emergency.controller; import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.renkang.emergency.dto.IdDTO; import com.renkang.emergency.entity.FirstAidResource; import com.renkang.emergency.service.IFirstAidResourceService; +import com.renkang.emergency.vo.FirstAidResourceExportVO; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; +import org.apache.shiro.SecurityUtils; import org.jeecg.common.api.vo.Result; import org.jeecg.common.aspect.annotation.AutoLog; import org.jeecg.common.system.base.controller.JeecgController; +import org.jeecg.common.system.query.QueryGenerator; +import org.jeecg.common.system.vo.LoginUser; import org.jeecg.global.GlobalUtils; +import org.jeecgframework.poi.excel.def.NormalExcelConstants; +import org.jeecgframework.poi.excel.entity.ExportParams; +import org.jeecgframework.poi.excel.view.JeecgEntityExcelView; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.util.Arrays; import java.util.List; @Tag(name = "急救宣教资源管理") @@ -31,10 +41,25 @@ public class FirstAidResourceController extends JeecgController> queryPageList(FirstAidResource entity, - @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, - @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, - HttpServletRequest req) { + public Result> queryPageList( + @RequestParam(name = "title", required = false) String title, + @RequestParam(name = "categoryId", required = false) String categoryId, + @RequestParam(name = "contentType", required = false) String contentType, + @RequestParam(name = "combinedStatus", required = false) Integer combinedStatus, + @RequestParam(name = "auditStatus", required = false) Integer auditStatus, + @RequestParam(name = "status", required = false) Integer status, + @RequestParam(name = "tags", required = false) String tags, + @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, + HttpServletRequest req) { + FirstAidResource entity = new FirstAidResource(); + entity.setTitle(title); + entity.setCategoryId(categoryId); + entity.setContentType(contentType); + entity.setCombinedStatus(combinedStatus); + entity.setAuditStatus(auditStatus); + entity.setStatus(status); + entity.setTags(tags); Page page = new Page<>(pageNo, pageSize); String userId = GlobalUtils.getLoginUser().getId(); return Result.OK(resourceService.queryPageList(entity, page, userId)); @@ -65,8 +90,8 @@ public class FirstAidResourceController extends JeecgController delete(@RequestParam(name = "id") String id) { - resourceService.removeById(id); + public Result delete(@RequestBody IdDTO dto) { + resourceService.removeById(dto.getId()); return Result.OK("删除成功!"); } @@ -97,9 +122,9 @@ public class FirstAidResourceController extends JeecgController submitForReview(@RequestParam(name = "id") String id) { + public Result submitForReview(@RequestBody IdDTO dto) { try { - resourceService.submitForReview(id); + resourceService.submitForReview(dto.getId()); } catch (RuntimeException e) { return Result.error(e.getMessage()); } @@ -109,9 +134,9 @@ public class FirstAidResourceController extends JeecgController takeDown(@RequestParam(name = "id") String id) { + public Result takeDown(@RequestBody IdDTO dto) { try { - resourceService.takeDown(id); + resourceService.takeDown(dto.getId()); } catch (RuntimeException e) { return Result.error(e.getMessage()); } @@ -121,9 +146,9 @@ public class FirstAidResourceController extends JeecgController publish(@RequestParam(name = "id") String id) { + public Result publish(@RequestBody IdDTO dto) { try { - resourceService.publish(id); + resourceService.publish(dto.getId()); } catch (RuntimeException e) { return Result.error(e.getMessage()); } @@ -141,18 +166,18 @@ public class FirstAidResourceController extends JeecgController incrementView(@RequestParam(name = "id") String id) { + public Result incrementView(@RequestBody IdDTO dto) { String userId = GlobalUtils.getLoginUser().getId(); - boolean firstRead = resourceService.incrementViewCount(id, userId); + boolean firstRead = resourceService.incrementViewCount(dto.getId(), userId); return firstRead ? Result.OK("阅读记录成功") : Result.OK("已阅读过"); } @Operation(summary = "急救宣教资源-复制资源") @AutoLog(value = "急救宣教资源-复制") @PostMapping(value = "/copy") - public Result copy(@RequestParam(name = "id") String id) { + public Result copy(@RequestBody IdDTO dto) { try { - return Result.OK("复制成功,已保存为草稿", resourceService.copyResource(id)); + return Result.OK("复制成功,已保存为草稿", resourceService.copyResource(dto.getId())); } catch (RuntimeException e) { return Result.error(e.getMessage()); } @@ -161,7 +186,25 @@ public class FirstAidResourceController extends JeecgController queryWrapper = QueryGenerator.initQueryWrapper(entity, request.getParameterMap()); + LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal(); + + String selections = request.getParameter("selections"); + if (StrUtil.isNotBlank(selections)) { + queryWrapper.in("id", Arrays.asList(selections.split(","))); + } + + queryWrapper.orderByDesc("create_time"); + List list = resourceService.list(queryWrapper); + List exportList = resourceService.convertToExportVO(list); + + ModelAndView mv = new ModelAndView(new JeecgEntityExcelView()); + mv.addObject(NormalExcelConstants.FILE_NAME, "急救宣教资源"); + ExportParams exportParams = new ExportParams("急救宣教资源报表", "导出人:" + sysUser.getRealname(), "急救宣教资源"); + mv.addObject(NormalExcelConstants.PARAMS, exportParams); + mv.addObject(NormalExcelConstants.CLASS, FirstAidResourceExportVO.class); + mv.addObject(NormalExcelConstants.DATA_LIST, exportList); + return mv; } @Operation(summary = "急救宣教资源-导入excel") diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceFavoriteController.java b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceFavoriteController.java index 0369d7a..0a258f3 100644 --- a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceFavoriteController.java +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceFavoriteController.java @@ -3,6 +3,7 @@ package com.renkang.emergency.controller; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.renkang.emergency.dto.IdDTO; import com.renkang.emergency.entity.FirstAidResource; import com.renkang.emergency.service.IFirstAidResourceUserActionService; import io.swagger.v3.oas.annotations.Operation; @@ -38,12 +39,12 @@ public class FirstAidResourceFavoriteController { @AutoLog(value = "急救宣教资源-切换收藏") @Operation(summary = "切换收藏状态", description = "已收藏则取消,未收藏则收藏") @PostMapping(value = "/toggle") - public Result> toggle(@RequestParam(name = "resourceId", required = true) String resourceId) { - if (StrUtil.isBlank(resourceId)) { + public Result> toggle(@RequestBody IdDTO dto) { + if (StrUtil.isBlank(dto.getId())) { return Result.error("资源ID不能为空"); } String userId = GlobalUtils.getLoginUser().getId(); - boolean favorited = userActionService.toggleFavorite(resourceId, userId); + boolean favorited = userActionService.toggleFavorite(dto.getId(), userId); Map result = new HashMap<>(); result.put("favorited", favorited); diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceTagController.java b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceTagController.java index 767a5e3..f97db5c 100644 --- a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceTagController.java +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceTagController.java @@ -1,9 +1,11 @@ package com.renkang.emergency.controller; +import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.renkang.emergency.constant.FirstAidConstants; +import com.renkang.emergency.dto.IdDTO; import com.renkang.emergency.entity.FirstAidResourceCategory; import com.renkang.emergency.service.IFirstAidResourceCategoryService; import io.swagger.v3.oas.annotations.tags.Tag; @@ -42,10 +44,11 @@ public class FirstAidResourceTagController extends JeecgController> listAll() { - return Result.OK(categoryService.listTags()); + public Result> listAll( + @RequestParam(name = "parentId", required = false) String parentId) { + return Result.OK(categoryService.listTags(parentId)); } @Operation(summary = "急救宣教资源标签-添加") @@ -56,6 +59,23 @@ public class FirstAidResourceTagController extends JeecgController checkWrapper = new QueryWrapper() + .eq("name", entity.getName()) + .eq("type", FirstAidConstants.TYPE_TAG); + if (StrUtil.isNotBlank(entity.getParentId())) { + checkWrapper.eq("parent_id", entity.getParentId()); + } + if (categoryService.count(checkWrapper) > 0) { + return Result.error("标签名称已存在"); + } categoryService.save(entity); return Result.OK("添加成功!"); } @@ -68,6 +88,24 @@ public class FirstAidResourceTagController extends JeecgController checkWrapper = new QueryWrapper() + .eq("name", entity.getName()) + .eq("type", FirstAidConstants.TYPE_TAG) + .ne("id", entity.getId()); + if (StrUtil.isNotBlank(entity.getParentId())) { + checkWrapper.eq("parent_id", entity.getParentId()); + } + if (categoryService.count(checkWrapper) > 0) { + return Result.error("标签名称已存在"); + } entity.setType(old.getType()); categoryService.updateById(entity); return Result.OK("编辑成功!"); @@ -77,9 +115,9 @@ public class FirstAidResourceTagController extends JeecgController delete(@RequestParam(name = "id") String id) { + public Result delete(@RequestBody IdDTO dto) { try { - categoryService.deleteWithCheck(id); + categoryService.deleteWithCheck(dto.getId()); } catch (RuntimeException e) { return Result.error(e.getMessage()); } @@ -105,7 +143,13 @@ public class FirstAidResourceTagController extends JeecgController queryById(@RequestParam(name = "id") String id) { FirstAidResourceCategory entity = categoryService.getById(id); - return entity == null ? Result.error("未找到对应数据") : Result.OK(entity); + if (entity == null) return Result.error("未找到对应数据"); + // 填充所属分类名称 + if (StrUtil.isNotBlank(entity.getParentId())) { + FirstAidResourceCategory parent = categoryService.getById(entity.getParentId()); + if (parent != null) entity.setParentName(parent.getName()); + } + return Result.OK(entity); } @Operation(summary = "急救宣教资源标签-导出excel") diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceVersionController.java b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceVersionController.java index 59fa3b7..e135949 100644 --- a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceVersionController.java +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceVersionController.java @@ -1,5 +1,6 @@ package com.renkang.emergency.controller; +import com.renkang.emergency.dto.IdDTO; import com.renkang.emergency.entity.FirstAidResourceVersion; import com.renkang.emergency.service.IFirstAidResourceVersionService; import io.swagger.v3.oas.annotations.tags.Tag; @@ -46,9 +47,9 @@ public class FirstAidResourceVersionController { //@RequiresPermissions("emergency:firstAidResource:edit") @Operation(summary = "回滚到指定版本", description = "将指定版本的内容恢复到资源表") @PostMapping(value = "/rollback") - public Result rollback(@RequestParam(name = "versionId", required = true) String versionId) { + public Result rollback(@RequestBody IdDTO dto) { try { - versionService.rollback(versionId); + versionService.rollback(dto.getId()); } catch (RuntimeException e) { return Result.error(e.getMessage()); } diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/FirstAidPushRecordMapper.java b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/FirstAidPushRecordMapper.java new file mode 100644 index 0000000..6216cb8 --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/FirstAidPushRecordMapper.java @@ -0,0 +1,12 @@ +package com.renkang.emergency.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.renkang.emergency.entity.FirstAidPushRecord; + +/** + * @Description: 急救宣教推送记录Mapper + * @Author: jeecg-boot + * @Date: 2026-06-24 + */ +public interface FirstAidPushRecordMapper extends BaseMapper { +} diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/FirstAidResourceAuditMapper.java b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/FirstAidResourceAuditMapper.java new file mode 100644 index 0000000..a1e9cc4 --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/FirstAidResourceAuditMapper.java @@ -0,0 +1,14 @@ +package com.renkang.emergency.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.renkang.emergency.entity.FirstAidResourceAudit; +import org.apache.ibatis.annotations.Mapper; + +/** + * @Description: 急救宣教资源审核记录 + * @Author: jeecg-boot + * @Date: 2026-06-24 + */ +@Mapper +public interface FirstAidResourceAuditMapper extends BaseMapper { +} diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/FirstAidResourceCategoryMapper.java b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/FirstAidResourceCategoryMapper.java index 9027003..e90048a 100644 --- a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/FirstAidResourceCategoryMapper.java +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/FirstAidResourceCategoryMapper.java @@ -41,6 +41,16 @@ public interface FirstAidResourceCategoryMapper extends BaseMapper selectByType(@Param("type") Integer type); + /** + * 按类型+父分类查询标签列表 + */ + @Select("") + List selectByTypeAndParent(@Param("type") Integer type, @Param("parentId") String parentId); + /** * 按父分类ID查询子分类列表(树形结构用) */ diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/xml/FirstAidResourceAuditMapper.xml b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/xml/FirstAidResourceAuditMapper.xml new file mode 100644 index 0000000..f6372ca --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/xml/FirstAidResourceAuditMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/IFirstAidResourceAuditService.java b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/IFirstAidResourceAuditService.java new file mode 100644 index 0000000..5a28b71 --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/IFirstAidResourceAuditService.java @@ -0,0 +1,28 @@ +package com.renkang.emergency.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.renkang.emergency.entity.FirstAidResourceAudit; + +/** + * @Description: 急救宣教资源审核记录 + * @Author: jeecg-boot + * @Date: 2026-06-24 + */ +public interface IFirstAidResourceAuditService extends IService { + + /** + * 保存审核记录 + */ + void saveAudit(String resourceId, Integer auditStatus, String rejectReason); + + /** + * 查询审核记录分页 + */ + IPage queryAuditRecords(Page page, + String resourceTitle, + Integer auditStatus, + String startDate, + String endDate); +} diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/IFirstAidResourceCategoryService.java b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/IFirstAidResourceCategoryService.java index a6ae0a3..485602f 100644 --- a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/IFirstAidResourceCategoryService.java +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/IFirstAidResourceCategoryService.java @@ -29,9 +29,9 @@ public interface IFirstAidResourceCategoryService extends IService listChildrenByParentId(String parentId); /** - * 查询所有有效标签列表 + * 查询所有有效标签列表(可按分类筛选) */ - List listTags(); + List listTags(String parentId); /** * 删除前校验(分类下有子分类/资源则拒绝;标签有资源引用则拒绝) diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/IFirstAidResourceService.java b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/IFirstAidResourceService.java index 74da04d..314a8d5 100644 --- a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/IFirstAidResourceService.java +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/IFirstAidResourceService.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import com.renkang.emergency.entity.FirstAidResource; +import com.renkang.emergency.vo.FirstAidResourceExportVO; import java.util.List; @@ -44,10 +45,10 @@ public interface IFirstAidResourceService extends IService { IPage queryPageList(FirstAidResource resource, Page page, String userId); - /** 审核记录分页列表(支持时间范围筛选) */ - IPage queryAuditRecords(FirstAidResource resource, Page page, String startDate, String endDate); - boolean incrementViewCount(String id, String userId); FirstAidResource getDetail(String id, String userId); + + /** 批量转换实体为导出VO(含分类、标签翻译) */ + List convertToExportVO(List resources); } diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/IFirstAidResourceVersionService.java b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/IFirstAidResourceVersionService.java index d2af997..2a760b4 100644 --- a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/IFirstAidResourceVersionService.java +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/IFirstAidResourceVersionService.java @@ -15,14 +15,20 @@ public interface IFirstAidResourceVersionService extends IService listVersions(String resourceId); + /** + * 清除指定资源所有版本的当前标记(内容已变更,不再匹配任何版本) + */ + void clearCurrent(String resourceId); + /** * 回滚到指定版本(将版本内容恢复到资源表) */ diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/impl/FirstAidPushServiceImpl.java b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/impl/FirstAidPushServiceImpl.java new file mode 100644 index 0000000..79d2c30 --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/impl/FirstAidPushServiceImpl.java @@ -0,0 +1,202 @@ +package com.renkang.emergency.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.renkang.emergency.constant.FirstAidConstants; +import com.renkang.emergency.dto.PushBatchSendDTO; +import com.renkang.emergency.dto.PushFilterDTO; +import com.renkang.emergency.entity.FirstAidPushRecord; +import com.renkang.emergency.entity.FirstAidResource; +import com.renkang.emergency.entity.FirstAidResourceCategory; +import com.renkang.emergency.entity.Order; +import com.renkang.emergency.mapper.FirstAidPushRecordMapper; +import com.renkang.emergency.mapper.FirstAidResourceMapper; +import com.renkang.emergency.mapper.FirstAidResourceCategoryMapper; +import com.renkang.emergency.mapper.OrderMapper; +import com.renkang.emergency.service.IFirstAidPushService; +import lombok.extern.slf4j.Slf4j; +import org.jeecg.common.constant.CommonConstant; +import org.jeecg.global.GlobalUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @Description: 急救宣教推送Service实现 + * @Author: jeecg-boot + * @Date: 2026-06-24 + */ +@Slf4j +@Service +public class FirstAidPushServiceImpl implements IFirstAidPushService { + + @Autowired + private FirstAidResourceMapper resourceMapper; + + @Autowired + private FirstAidPushRecordMapper pushRecordMapper; + + @Autowired + private FirstAidResourceCategoryMapper categoryMapper; + + @Autowired + private OrderMapper orderMapper; + + @Lazy + @Autowired + private FirstAidPushServiceImpl self; + + @Override + public IPage queryResourceList(String orderId, PushFilterDTO filter, Page page) { + LambdaQueryWrapper wrapper = buildFilterWrapper(filter); + wrapper.orderByDesc(FirstAidResource::getCreateTime); + + IPage result = resourceMapper.selectPage(page, wrapper); + + // 查询当前工单已推送的资源ID集合 + Set pushedIds = getPushedResourceIds(orderId); + + // 填充推送状态 + 分类名称 + for (FirstAidResource resource : result.getRecords()) { + resource.setPushed(pushedIds.contains(resource.getId())); + if (StrUtil.isNotBlank(resource.getCategoryId())) { + FirstAidResourceCategory category = categoryMapper.selectById(resource.getCategoryId()); + if (category != null) { + resource.setCategoryName(category.getName()); + } + } + } + + return result; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void send(String resourceId, String orderId) { + // 1. 校验资源 + FirstAidResource resource = resourceMapper.selectById(resourceId); + if (resource == null) { + throw new RuntimeException("资源不存在"); + } + if (!FirstAidConstants.STATUS_PUBLISHED.equals(resource.getStatus()) + || !FirstAidConstants.AUDIT_STATUS_APPROVED.equals(resource.getAuditStatus())) { + throw new RuntimeException("仅已发布且审核通过的资源可推送"); + } + + // 2. 查重 + LambdaQueryWrapper existWrapper = new LambdaQueryWrapper<>(); + existWrapper.eq(FirstAidPushRecord::getOrderId, orderId) + .eq(FirstAidPushRecord::getResourceId, resourceId); + if (pushRecordMapper.selectCount(existWrapper) > 0) { + throw new RuntimeException("该资源已推送,请勿重复操作"); + } + + // 3. 获取推送目标 + String targetUserId = null; + if (StrUtil.isNotBlank(orderId)) { + Order order = orderMapper.selectById(orderId); + if (order != null) { + targetUserId = order.getSalvageUserId(); + } + } + + // 4. 保存推送记录 + FirstAidPushRecord record = new FirstAidPushRecord(); + record.setResourceId(resourceId); + record.setResourceTitle(resource.getTitle()); + record.setOrderId(orderId); + record.setTargetUserId(targetUserId); + record.setPushBy(GlobalUtils.getLoginUser().getRealname()); + record.setPushById(GlobalUtils.getLoginUser().getId()); + record.setPushTime(new Date()); + pushRecordMapper.insert(record); + + // 5. 推送通知(预留,当前记录日志) + log.info("急救宣教推送: resourceId={}, title={}, orderId={}, targetUserId={}, pushById={}, pushByName={}", + resourceId, resource.getTitle(), orderId, targetUserId, + GlobalUtils.getLoginUser().getId(), GlobalUtils.getLoginUser().getRealname()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int batchSend(PushBatchSendDTO dto) { + List resourceIds = dto.getResourceIds(); + + // 方式二:按筛选条件查询 + if (CollectionUtil.isEmpty(resourceIds) && dto.getFilterParams() != null) { + LambdaQueryWrapper wrapper = buildFilterWrapper(dto.getFilterParams()); + List resources = resourceMapper.selectList(wrapper); + resourceIds = resources.stream().map(FirstAidResource::getId).collect(Collectors.toList()); + } + + if (CollectionUtil.isEmpty(resourceIds)) { + throw new RuntimeException("无可推送的资源"); + } + + int successCount = 0; + List errors = new ArrayList<>(); + + for (String resourceId : resourceIds) { + try { + // 通过 self 代理调用,确保每条 send 拥有独立事务 + self.send(resourceId, dto.getOrderId()); + successCount++; + } catch (RuntimeException e) { + errors.add(resourceId + ":" + e.getMessage()); + } + } + + if (!errors.isEmpty()) { + log.warn("批量推送部分失败: {}/{} 条, 失败原因: {}", + successCount, resourceIds.size(), String.join("; ", errors)); + } + + return successCount; + } + + private Set getPushedResourceIds(String orderId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(FirstAidPushRecord::getOrderId, orderId) + .select(FirstAidPushRecord::getResourceId); + List records = pushRecordMapper.selectList(wrapper); + if (CollectionUtil.isEmpty(records)) { + return Collections.emptySet(); + } + return records.stream().map(FirstAidPushRecord::getResourceId).collect(Collectors.toSet()); + } + + private LambdaQueryWrapper buildFilterWrapper(PushFilterDTO filter) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(FirstAidResource::getStatus, FirstAidConstants.STATUS_PUBLISHED) + .eq(FirstAidResource::getAuditStatus, FirstAidConstants.AUDIT_STATUS_APPROVED) + .eq(FirstAidResource::getDelFlag, CommonConstant.DEL_FLAG_0); + + // 仅返回当前有效资源:已生效(null视为立即生效) 且 未过期(null视为永不过期) + Date now = new Date(); + wrapper.and(w -> w.isNull(FirstAidResource::getEffectiveTime) + .or().le(FirstAidResource::getEffectiveTime, now)); + wrapper.and(w -> w.isNull(FirstAidResource::getExpiryTime) + .or().ge(FirstAidResource::getExpiryTime, now)); + + if (filter != null) { + if (StrUtil.isNotBlank(filter.getKeyword())) { + wrapper.and(w -> w.like(FirstAidResource::getTitle, filter.getKeyword()) + .or().like(FirstAidResource::getContent, filter.getKeyword())); + } + if (StrUtil.isNotBlank(filter.getCategoryId())) { + wrapper.eq(FirstAidResource::getCategoryId, filter.getCategoryId()); + } + if (StrUtil.isNotBlank(filter.getContentType())) { + wrapper.eq(FirstAidResource::getContentType, filter.getContentType()); + } + } + return wrapper; + } +} diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/impl/FirstAidResourceAuditServiceImpl.java b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/impl/FirstAidResourceAuditServiceImpl.java new file mode 100644 index 0000000..63593e1 --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/impl/FirstAidResourceAuditServiceImpl.java @@ -0,0 +1,82 @@ +package com.renkang.emergency.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.renkang.emergency.entity.FirstAidResource; +import com.renkang.emergency.entity.FirstAidResourceAudit; +import com.renkang.emergency.mapper.FirstAidResourceAuditMapper; +import com.renkang.emergency.mapper.FirstAidResourceMapper; +import com.renkang.emergency.service.IFirstAidResourceAuditService; +import org.jeecg.common.constant.CommonConstant; +import org.jeecg.global.GlobalUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @Description: 急救宣教资源审核记录 + * @Author: jeecg-boot + * @Date: 2026-06-24 + */ +@Service +public class FirstAidResourceAuditServiceImpl extends ServiceImpl implements IFirstAidResourceAuditService { + + @Autowired + private FirstAidResourceMapper resourceMapper; + + @Override + public void saveAudit(String resourceId, Integer auditStatus, String rejectReason) { + FirstAidResourceAudit audit = new FirstAidResourceAudit(); + audit.setResourceId(resourceId); + audit.setAuditStatus(auditStatus); + audit.setAuditRejectReason(rejectReason); + audit.setAuditBy(GlobalUtils.getLoginUser().getRealname()); + audit.setAuditById(GlobalUtils.getLoginUser().getId()); + audit.setAuditTime(new Date()); + save(audit); + } + + @Override + public IPage queryAuditRecords(Page page, + String resourceTitle, + Integer auditStatus, + String startDate, + String endDate) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + + // 按资源标题筛选:先查匹配的资源ID,再过滤审计记录 + if (StrUtil.isNotBlank(resourceTitle)) { + LambdaQueryWrapper resourceWrapper = new LambdaQueryWrapper<>(); + resourceWrapper.like(FirstAidResource::getTitle, resourceTitle); + resourceWrapper.select(FirstAidResource::getId); + List matchedIds = resourceMapper.selectList(resourceWrapper).stream() + .map(FirstAidResource::getId) + .collect(Collectors.toList()); + if (CollectionUtil.isEmpty(matchedIds)) { + return page; + } + queryWrapper.in(FirstAidResourceAudit::getResourceId, matchedIds); + } + + if (auditStatus != null) { + queryWrapper.eq(FirstAidResourceAudit::getAuditStatus, auditStatus); + } + if (StrUtil.isNotBlank(startDate)) { + queryWrapper.ge(FirstAidResourceAudit::getAuditTime, startDate + " 00:00:00"); + } + if (StrUtil.isNotBlank(endDate)) { + queryWrapper.le(FirstAidResourceAudit::getAuditTime, endDate + " 23:59:59"); + } + + queryWrapper.orderByDesc(FirstAidResourceAudit::getAuditTime); + return page(page, queryWrapper); + } +} diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/impl/FirstAidResourceCategoryServiceImpl.java b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/impl/FirstAidResourceCategoryServiceImpl.java index 4d3a324..5144520 100644 --- a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/impl/FirstAidResourceCategoryServiceImpl.java +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/impl/FirstAidResourceCategoryServiceImpl.java @@ -48,8 +48,8 @@ public class FirstAidResourceCategoryServiceImpl extends ServiceImpl listTags() { - List list = categoryMapper.selectByType(FirstAidConstants.TYPE_TAG); + public List listTags(String parentId) { + List list = categoryMapper.selectByTypeAndParent(FirstAidConstants.TYPE_TAG, parentId); for (FirstAidResourceCategory tag : list) { Integer count = categoryMapper.countResourcesByTagId(tag.getId()); tag.setResourceCount(count != null ? count : 0); diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/impl/FirstAidResourceServiceImpl.java b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/impl/FirstAidResourceServiceImpl.java index 15624e7..44c1d16 100644 --- a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/impl/FirstAidResourceServiceImpl.java +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/impl/FirstAidResourceServiceImpl.java @@ -12,8 +12,10 @@ import com.renkang.emergency.entity.FirstAidResourceCategory; import com.renkang.emergency.mapper.FirstAidResourceCategoryMapper; import com.renkang.emergency.mapper.FirstAidResourceMapper; import com.renkang.emergency.service.IFirstAidResourceService; +import com.renkang.emergency.service.IFirstAidResourceAuditService; import com.renkang.emergency.service.IFirstAidResourceUserActionService; import com.renkang.emergency.service.IFirstAidResourceVersionService; +import com.renkang.emergency.vo.FirstAidResourceExportVO; import org.jeecg.common.constant.CommonConstant; import org.jeecg.global.GlobalUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -47,6 +49,9 @@ public class FirstAidResourceServiceImpl extends ServiceImpl ids) { Date now = new Date(); String auditBy = GlobalUtils.getLoginUser().getRealname(); + String auditById = GlobalUtils.getLoginUser().getId(); for (String id : ids) { FirstAidResource resource = getById(id); if (resource != null) { resource.setStatus(FirstAidConstants.STATUS_PUBLISHED); resource.setAuditStatus(FirstAidConstants.AUDIT_STATUS_APPROVED); resource.setAuditBy(auditBy); + resource.setAuditById(auditById); resource.setAuditTime(now); resource.setAuditRejectReason(null); updateById(resource); @@ -202,10 +223,9 @@ public class FirstAidResourceServiceImpl extends ServiceImpl queryPageList(FirstAidResource resource, Page page, String userId) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - // 标题 + 正文 模糊搜索 + // 标题模糊搜索 if (StrUtil.isNotBlank(resource.getTitle())) { - queryWrapper.and(w -> w.like(FirstAidResource::getTitle, resource.getTitle()) - .or().like(FirstAidResource::getContent, resource.getTitle())); + queryWrapper.like(FirstAidResource::getTitle, resource.getTitle()); } if (StrUtil.isNotBlank(resource.getCategoryId())) { queryWrapper.eq(FirstAidResource::getCategoryId, resource.getCategoryId()); @@ -213,19 +233,21 @@ public class FirstAidResourceServiceImpl extends ServiceImpl queryAuditRecords(FirstAidResource resource, Page page, String startDate, String endDate) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - - // 标题 + 正文 模糊搜索 - if (StrUtil.isNotBlank(resource.getTitle())) { - queryWrapper.and(w -> w.like(FirstAidResource::getTitle, resource.getTitle()) - .or().like(FirstAidResource::getContent, resource.getTitle())); - } - if (StrUtil.isNotBlank(resource.getCategoryId())) { - queryWrapper.eq(FirstAidResource::getCategoryId, resource.getCategoryId()); - } - if (StrUtil.isNotBlank(resource.getContentType())) { - queryWrapper.eq(FirstAidResource::getContentType, resource.getContentType()); - } - - // 审核状态筛选:auditStatus=10 时查询所有已审核(>=10),否则精确匹配 - if (resource.getAuditStatus() != null) { - if (resource.getAuditStatus() == 10) { - queryWrapper.ge(FirstAidResource::getAuditStatus, 10); - } else { - queryWrapper.eq(FirstAidResource::getAuditStatus, resource.getAuditStatus()); - } - } - - // 审核时间范围筛选 - if (StrUtil.isNotBlank(startDate)) { - queryWrapper.ge(FirstAidResource::getAuditTime, startDate + " 00:00:00"); - } - if (StrUtil.isNotBlank(endDate)) { - queryWrapper.le(FirstAidResource::getAuditTime, endDate + " 23:59:59"); - } - - queryWrapper.eq(FirstAidResource::getDelFlag, CommonConstant.DEL_FLAG_0); - queryWrapper.orderByDesc(FirstAidResource::getAuditTime); - - IPage result = page(page, queryWrapper); - fillResourceExtras(result.getRecords(), null); - return result; - } - @Override @Transactional(rollbackFor = Exception.class) public boolean incrementViewCount(String id, String userId) { @@ -301,6 +282,24 @@ public class FirstAidResourceServiceImpl extends ServiceImpl convertToExportVO(List resources) { + fillResourceExtras(resources, null); + return resources.stream().map(r -> { + FirstAidResourceExportVO vo = new FirstAidResourceExportVO(); + vo.setTitle(r.getTitle()); + vo.setSummary(r.getSummary()); + vo.setCategoryName(r.getCategoryName()); + vo.setContentType(r.getContentType()); + vo.setTagNames(r.getTagNameList() != null && !r.getTagNameList().isEmpty() + ? String.join("、", r.getTagNameList()) : ""); + vo.setStatusText(toStatusText(r.getAuditStatus(), r.getStatus())); + vo.setViewFavorite(r.getViewCount() + "/" + r.getFavoriteCount()); + vo.setCreateTime(r.getCreateTime()); + return vo; + }).collect(Collectors.toList()); + } + private void fillResourceExtras(List resources, String userId) { if (CollectionUtil.isEmpty(resources)) { return; @@ -335,4 +334,34 @@ public class FirstAidResourceServiceImpl extends ServiceImpl clearWrapper = new LambdaUpdateWrapper<>(); + clearWrapper.eq(FirstAidResourceVersion::getResourceId, resourceId); + clearWrapper.eq(FirstAidResourceVersion::getIsCurrent, true); + clearWrapper.set(FirstAidResourceVersion::getIsCurrent, false); + update(clearWrapper); + } + Integer maxNo = versionMapper.selectMaxVersionNo(resourceId); int nextVersion = (maxNo == null) ? 1 : maxNo + 1; @@ -40,9 +50,19 @@ public class FirstAidResourceVersionServiceImpl extends ServiceImpl clearWrapper = new LambdaUpdateWrapper<>(); + clearWrapper.eq(FirstAidResourceVersion::getResourceId, resourceId); + clearWrapper.eq(FirstAidResourceVersion::getIsCurrent, true); + clearWrapper.set(FirstAidResourceVersion::getIsCurrent, false); + update(clearWrapper); + } + @Override public List listVersions(String resourceId) { return versionMapper.selectByResourceId(resourceId); @@ -61,9 +81,6 @@ public class FirstAidResourceVersionServiceImpl extends ServiceImpl