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 new file mode 100644 index 0000000..b4f5a25 --- /dev/null +++ b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/constant/FirstAidConstants.java @@ -0,0 +1,54 @@ +package com.renkang.emergency.constant; + +/** + * 急救宣教资源常量 + * + * @author jeecg-boot + * @date 2026-06-22 + */ +public interface FirstAidConstants { + + // ========== 分类/标签类型 ========== + /** 分类 */ + Integer TYPE_CATEGORY = 1; + /** 标签 */ + Integer TYPE_TAG = 2; + + // ========== 内容类型 ========== + /** 图文 */ + String CONTENT_TYPE_IMAGE_TEXT = "IMAGE_TEXT"; + /** 视频 */ + String CONTENT_TYPE_VIDEO = "VIDEO"; + /** 音频 */ + String CONTENT_TYPE_AUDIO = "AUDIO"; + /** PDF */ + String CONTENT_TYPE_PDF = "PDF"; + + // ========== 审核状态(值域 10+,与发布状态 0-9 错开) ========== + /** 待审核 */ + Integer AUDIT_STATUS_PENDING = 10; + /** 已通过 */ + Integer AUDIT_STATUS_APPROVED = 11; + /** 已驳回 */ + Integer AUDIT_STATUS_REJECTED = 12; + + // ========== 发布状态 ========== + /** 草稿 */ + Integer STATUS_DRAFT = 0; + /** 已发布 */ + Integer STATUS_PUBLISHED = 1; + /** 已下架 */ + Integer STATUS_DOWN = 2; + + // ========== 用户行为类型 ========== + /** 阅读 */ + Integer ACTION_TYPE_READ = 1; + /** 收藏 */ + Integer ACTION_TYPE_FAVORITE = 2; + + // ========== 通用状态 ========== + /** 正常 */ + Integer NORMAL = 1; + /** 冻结 */ + Integer FROZEN = 2; +} 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 new file mode 100644 index 0000000..9d03420 --- /dev/null +++ b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/entity/FirstAidResource.java @@ -0,0 +1,177 @@ +package com.renkang.emergency.entity; + +import java.io.Serializable; +import java.util.List; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.springframework.format.annotation.DateTimeFormat; +import org.jeecgframework.poi.excel.annotation.Excel; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + * @Description: 急救宣教资源 + * @Author: jeecg-boot + * @Date: 2026-06-22 + * @Version: V1.0 + */ +@Data +@TableName("QH_EME_FIRST_AID_RESOURCE") +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@Schema(title = "first_aid_resource对象", description = "急救宣教资源") +public class FirstAidResource implements Serializable { + private static final long serialVersionUID = 1L; + + /** id */ + @TableId(type = IdType.ASSIGN_ID) + @Schema(title = "id") + private String id; + + /** 标题 */ + @Excel(name = "标题", width = 30) + @Schema(title = "标题") + private String title; + + /** 摘要/简介 */ + @Excel(name = "摘要", width = 30) + @Schema(title = "摘要/简介") + private String summary; + + /** 内容类型(IMAGE_TEXT=图文/VIDEO=视频/AUDIO=音频/PDF) */ + @Excel(name = "内容类型", width = 15, dicCode = "first_aid_content_type") + @Schema(title = "内容类型") + private String contentType; + + /** 所属分类ID */ + @Excel(name = "所属分类ID", width = 15) + @Schema(title = "所属分类ID") + private String categoryId; + + /** 适用场景 */ + @Excel(name = "适用场景", width = 30) + @Schema(title = "适用场景") + private String applicableScenario; + + /** 标签ID列表(逗号分隔) */ + @Excel(name = "标签", width = 30) + @Schema(title = "标签ID列表(逗号分隔)") + private String tags; + + /** 正文内容(富文本HTML) */ + @Schema(title = "正文内容(富文本HTML)") + private String content; + + /** 封面图URL */ + @Excel(name = "封面图", width = 30) + @Schema(title = "封面图URL") + private String coverImage; + + /** 附件URL列表(JSON数组) */ + @Excel(name = "附件", width = 30) + @Schema(title = "附件URL列表(JSON数组)") + private String fileUrl; + + /** 生效时间 */ + @Excel(name = "生效时间", width = 20) + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(title = "生效时间") + private java.util.Date effectiveTime; + + /** 失效时间 */ + @Excel(name = "失效时间", width = 20) + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(title = "失效时间") + private java.util.Date expiryTime; + + /** 审核状态(null=无审核,10=待审核,11=已通过,12=已驳回) */ + @Excel(name = "审核状态", width = 15, dicCode = "first_aid_audit_status") + @Schema(title = "审核状态(null=无审核,10=待审核,11=已通过,12=已驳回)") + private Integer auditStatus; + + /** 驳回原因 */ + @Excel(name = "驳回原因", width = 30) + @Schema(title = "驳回原因") + private String auditRejectReason; + + /** 审核人 */ + @Schema(title = "审核人") + private String auditBy; + + /** 审核时间 */ + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(title = "审核时间") + private java.util.Date auditTime; + + /** 浏览次数 */ + @Excel(name = "浏览次数", width = 15) + @Schema(title = "浏览次数") + private Integer viewCount; + + /** 收藏次数 */ + @Excel(name = "收藏次数", width = 15) + @Schema(title = "收藏次数") + private Integer favoriteCount; + + /** 发布状态(0=草稿,1=已发布,2=已下架) */ + @Excel(name = "状态", width = 15, dicCode = "first_aid_resource_status") + @Schema(title = "发布状态(0=草稿,1=已发布,2=已下架)") + private Integer status; + + /** 删除标记(0=正常,1=已删除) */ + @Excel(name = "删除标记", width = 15) + @Schema(title = "删除标记(0=正常,1=已删除)") + @TableLogic + private Integer delFlag; + + /** 创建人 */ + @Schema(title = "创建人") + private String createBy; + + /** 创建时间 */ + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(title = "创建时间") + private java.util.Date createTime; + + /** 更新人 */ + @Schema(title = "更新人") + private String updateBy; + + /** 更新时间 */ + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(title = "更新时间") + private java.util.Date updateTime; + + /** 备注 */ + @Excel(name = "备注", width = 30) + @Schema(title = "备注") + private String memo; + + /** 所属分类名称(非持久字段) */ + @TableField(exist = false) + @Schema(title = "所属分类名称") + private String categoryName; + + /** 标签名称列表(非持久字段) */ + @TableField(exist = false) + @Schema(title = "标签名称列表") + private List tagNameList; + + /** 当前用户是否已收藏(非持久字段) */ + @TableField(exist = false) + @Schema(title = "当前用户是否已收藏") + private Boolean isFavorited; + + /** 复合状态(非持久字段,前端统一筛选:0-9查status,10+查auditStatus) */ + @TableField(exist = false) + @Schema(title = "复合状态(0=草稿,1=已发布,2=已下架,10=待审核,11=已通过,12=已驳回)") + private Integer combinedStatus; +} diff --git a/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/entity/FirstAidResourceCategory.java b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/entity/FirstAidResourceCategory.java new file mode 100644 index 0000000..9366847 --- /dev/null +++ b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/entity/FirstAidResourceCategory.java @@ -0,0 +1,103 @@ +package com.renkang.emergency.entity; + +import java.io.Serializable; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.springframework.format.annotation.DateTimeFormat; +import org.jeecgframework.poi.excel.annotation.Excel; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + * @Description: 急救宣教资源分类/标签 + * @Author: jeecg-boot + * @Date: 2026-06-22 + * @Version: V1.0 + */ +@Data +@TableName("QH_EME_FIRST_AID_RESOURCE_CATEGORY") +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@Schema(title = "first_aid_resource_category对象", description = "急救宣教资源分类/标签") +public class FirstAidResourceCategory implements Serializable { + private static final long serialVersionUID = 1L; + + /** id */ + @TableId(type = IdType.ASSIGN_ID) + @Schema(title = "id") + private String id; + + /** 名称 */ + @Excel(name = "名称", width = 20) + @Schema(title = "名称") + private String name; + + /** 类型(1=分类,2=标签) */ + @Excel(name = "类型", width = 15, dicCode = "first_aid_category_type") + @Schema(title = "类型(1=分类,2=标签)") + private Integer type; + + /** 父分类ID(分类树形结构,type=1时可用) */ + @Excel(name = "父分类ID", width = 15) + @Schema(title = "父分类ID") + private String parentId; + + /** 描述 */ + @Excel(name = "描述", width = 30) + @Schema(title = "描述") + private String description; + + /** 排序号 */ + @Excel(name = "排序号", width = 15) + @Schema(title = "排序号") + private Integer sortNo; + + /** 状态(1=正常,2=冻结) */ + @Excel(name = "状态", width = 15, dicCode = "status") + @Schema(title = "状态(1=正常,2=冻结)") + private Integer status; + + /** 删除标记(0=正常,1=已删除) */ + @Excel(name = "删除标记", width = 15) + @Schema(title = "删除标记(0=正常,1=已删除)") + @TableLogic + private Integer delFlag; + + /** 创建人 */ + @Schema(title = "创建人") + private String createBy; + + /** 创建时间 */ + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(title = "创建时间") + private java.util.Date createTime; + + /** 更新人 */ + @Schema(title = "更新人") + private String updateBy; + + /** 更新时间 */ + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(title = "更新时间") + private java.util.Date updateTime; + + /** 备注 */ + @Excel(name = "备注", width = 30) + @Schema(title = "备注") + private String memo; + + /** 所属分类/父级名称(非持久字段) */ + @TableField(exist = false) + @Schema(title = "所属分类/父级名称") + private String parentName; + + /** 关联资源数量(非持久字段) */ + @TableField(exist = false) + @Schema(title = "关联资源数量") + private Integer resourceCount; +} diff --git a/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/entity/FirstAidResourceUserAction.java b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/entity/FirstAidResourceUserAction.java new file mode 100644 index 0000000..85fc6d4 --- /dev/null +++ b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/entity/FirstAidResourceUserAction.java @@ -0,0 +1,49 @@ +package com.renkang.emergency.entity; + +import java.io.Serializable; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.springframework.format.annotation.DateTimeFormat; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + * @Description: 用户行为记录(阅读/收藏) + * @Author: jeecg-boot + * @Date: 2026-06-22 + * @Version: V1.0 + */ +@Data +@TableName("QH_EME_FIRST_AID_RESOURCE_USER_ACTION") +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@Schema(title = "first_aid_resource_user_action对象", description = "用户行为记录(阅读/收藏)") +public class FirstAidResourceUserAction 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; + + /** 用户ID */ + @Schema(title = "用户ID") + private String userId; + + /** 行为类型(1=阅读,2=收藏) */ + @Schema(title = "行为类型(1=阅读,2=收藏)") + private Integer type; + + /** 创建时间 */ + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(title = "创建时间") + private java.util.Date createTime; +} 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 new file mode 100644 index 0000000..8c5304a --- /dev/null +++ b/health-emergency/health-emergency-api/src/main/java/com/renkang/emergency/entity/FirstAidResourceVersion.java @@ -0,0 +1,61 @@ +package com.renkang.emergency.entity; + +import java.io.Serializable; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.springframework.format.annotation.DateTimeFormat; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + * @Description: 资源版本历史 + * @Author: jeecg-boot + * @Date: 2026-06-22 + * @Version: V1.0 + */ +@Data +@TableName("QH_EME_FIRST_AID_RESOURCE_VERSION") +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@Schema(title = "first_aid_resource_version对象", description = "资源版本历史") +public class FirstAidResourceVersion 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; + + /** 版本号 */ + @Schema(title = "版本号") + private Integer versionNo; + + /** 版本时的标题 */ + @Schema(title = "标题") + private String title; + + /** 版本时的正文内容 */ + @Schema(title = "正文内容") + private String content; + + /** 变更描述 */ + @Schema(title = "变更描述") + private String changeDescription; + + /** 创建人 */ + @Schema(title = "创建人") + private String createBy; + + /** 创建时间 */ + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(title = "创建时间") + private java.util.Date createTime; +} 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 new file mode 100644 index 0000000..2ac48f4 --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceAuditController.java @@ -0,0 +1,124 @@ +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.constant.FirstAidConstants; +import com.renkang.emergency.entity.FirstAidResource; +import com.renkang.emergency.service.IFirstAidResourceService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +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.*; + +/** + * @Description: 急救宣教资源-审核管理 + * @Author: jeecg-boot + * @Date: 2026-06-22 + * @Version: V1.0 + */ +@Tag(name = "急救宣教资源-审核管理") +@RestController +@RequestMapping("/emergency/firstAid/audit") +@Slf4j +public class FirstAidResourceAuditController { + + @Autowired + private IFirstAidResourceService resourceService; + + /** + * 待审核列表(支持标题/分类/内容类型筛选) + */ + @Operation(summary = "待审核列表") + @GetMapping(value = "/pending") + public Result> pending(FirstAidResource entity, + @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) { + Page page = new Page<>(pageNo, pageSize); + entity.setAuditStatus(FirstAidConstants.AUDIT_STATUS_PENDING); + return Result.OK(resourceService.queryPageList(entity, page, null)); + } + + /** + * 已通过列表(支持标题/分类/内容类型筛选) + */ + @Operation(summary = "已通过列表") + @GetMapping(value = "/passed") + public Result> passed(FirstAidResource entity, + @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) { + Page page = new Page<>(pageNo, pageSize); + entity.setAuditStatus(FirstAidConstants.AUDIT_STATUS_APPROVED); + return Result.OK(resourceService.queryPageList(entity, page, null)); + } + + /** + * 已驳回列表(支持标题/分类/内容类型筛选) + */ + @Operation(summary = "已驳回列表") + @GetMapping(value = "/rejected") + public Result> rejected(FirstAidResource entity, + @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) { + Page page = new Page<>(pageNo, pageSize); + entity.setAuditStatus(FirstAidConstants.AUDIT_STATUS_REJECTED); + return Result.OK(resourceService.queryPageList(entity, page, null)); + } + + /** + * 审核通过 + */ + @AutoLog(value = "急救宣教资源-审核通过") + //@RequiresPermissions("emergency:firstAidAudit:approve") + @Operation(summary = "审核通过") + @PostMapping(value = "/approve") + public Result approve(@RequestParam(name = "id", required = true) String id) { + try { + resourceService.approve(id); + } catch (RuntimeException e) { + return Result.error(e.getMessage()); + } + return Result.OK("审核通过"); + } + + /** + * 审核驳回 + */ + @AutoLog(value = "急救宣教资源-审核驳回") + //@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)) { + return Result.error("驳回原因不能为空"); + } + try { + resourceService.reject(id, reason); + } catch (RuntimeException e) { + return Result.error(e.getMessage()); + } + return Result.OK("已驳回"); + } + + /** + * 审核记录列表(合并待审核/已通过/已驳回的全部审核操作日志) + */ + @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=已驳回 + } + return Result.OK(resourceService.queryAuditRecords(entity, page, startDate, endDate)); + } +} 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 new file mode 100644 index 0000000..9d8cd18 --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceCategoryController.java @@ -0,0 +1,148 @@ +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.entity.FirstAidResourceCategory; +import com.renkang.emergency.service.IFirstAidResourceCategoryService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import lombok.extern.slf4j.Slf4j; +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.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.List; + +@Tag(name = "急救宣教资源-分类管理") +@RestController +@RequestMapping("/emergency/firstAid/category") +@Slf4j +public class FirstAidResourceCategoryController extends JeecgController { + + @Autowired + private IFirstAidResourceCategoryService categoryService; + + @Operation(summary = "急救宣教资源分类-分页列表查询") + @GetMapping(value = "/list") + public Result> queryPageList(FirstAidResourceCategory entity, + @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, + HttpServletRequest req) { + entity.setType(FirstAidConstants.TYPE_CATEGORY); + QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(entity, req.getParameterMap()); + Page page = new Page<>(pageNo, pageSize); + IPage pageList = categoryService.page(page, queryWrapper); + for (FirstAidResourceCategory record : pageList.getRecords()) { + if (StrUtil.isNotBlank(record.getParentId())) { + FirstAidResourceCategory parent = categoryService.getById(record.getParentId()); + if (parent != null) record.setParentName(parent.getName()); + } + } + return Result.OK(pageList); + } + + @Operation(summary = "急救宣教资源分类-全部列表") + @GetMapping(value = "/listAll") + public Result> listAll() { + return Result.OK(categoryService.listCategories()); + } + + @Operation(summary = "急救宣教资源分类-根分类列表") + @GetMapping(value = "/listRoot") + public Result> listRoot() { + return Result.OK(categoryService.listRootCategories()); + } + + @Operation(summary = "急救宣教资源分类-子分类列表") + @GetMapping(value = "/listChildren") + public Result> listChildren(@RequestParam(name = "parentId") String parentId) { + return Result.OK(categoryService.listChildrenByParentId(parentId)); + } + + @Operation(summary = "急救宣教资源分类-添加") + @AutoLog(value = "急救宣教资源分类-添加") + //@RequiresPermissions("emergency:firstAidCategory:add") + @PostMapping(value = "/add") + public Result add(@RequestBody FirstAidResourceCategory entity) { + entity.setType(FirstAidConstants.TYPE_CATEGORY); + if (entity.getSortNo() == null) entity.setSortNo(0); + if (entity.getStatus() == null) entity.setStatus(FirstAidConstants.NORMAL); + categoryService.save(entity); + return Result.OK("添加成功!"); + } + + @Operation(summary = "急救宣教资源分类-编辑") + @AutoLog(value = "急救宣教资源分类-编辑") + //@RequiresPermissions("emergency:firstAidCategory:edit") + @PostMapping(value = "/edit") + public Result edit(@RequestBody FirstAidResourceCategory entity) { + FirstAidResourceCategory old = categoryService.getById(entity.getId()); + if (old == null) return Result.error("数据不存在"); + entity.setType(old.getType()); + categoryService.updateById(entity); + return Result.OK("编辑成功!"); + } + + @Operation(summary = "急救宣教资源分类-删除") + @AutoLog(value = "急救宣教资源分类-删除") + //@RequiresPermissions("emergency:firstAidCategory:delete") + @PostMapping(value = "/delete") + public Result delete(@RequestParam(name = "id") String id) { + try { + categoryService.deleteWithCheck(id); + } catch (RuntimeException e) { + return Result.error(e.getMessage()); + } + return Result.OK("删除成功!"); + } + + @Operation(summary = "急救宣教资源分类-批量删除") + @AutoLog(value = "急救宣教资源分类-批量删除") + //@RequiresPermissions("emergency:firstAidCategory:deleteBatch") + @PostMapping(value = "/deleteBatch") + public Result deleteBatch(@RequestBody List ids) { + for (String id : ids) { + try { + categoryService.deleteWithCheck(id); + } catch (RuntimeException e) { + return Result.error("ID[" + id + "]:" + e.getMessage()); + } + } + return Result.OK("批量删除成功!"); + } + + @Operation(summary = "急救宣教资源分类-通过id查询") + @GetMapping(value = "/queryById") + public Result queryById(@RequestParam(name = "id") String id) { + FirstAidResourceCategory entity = categoryService.getById(id); + 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") + //@RequiresPermissions("emergency:firstAidCategory:exportXls") + @GetMapping(value = "/exportXls") + public ModelAndView exportXls(HttpServletRequest request, FirstAidResourceCategory entity) { + return super.exportXls(request, entity, FirstAidResourceCategory.class, "急救宣教资源分类"); + } + + @Operation(summary = "急救宣教资源分类-导入excel") + //@RequiresPermissions("emergency:firstAidCategory:importExcel") + @PostMapping(value = "/importExcel") + public Result importExcel(HttpServletRequest request, HttpServletResponse response) { + return super.importExcel(request, response, FirstAidResourceCategory.class); + } +} 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 new file mode 100644 index 0000000..25c948b --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceController.java @@ -0,0 +1,172 @@ +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.entity.FirstAidResource; +import com.renkang.emergency.service.IFirstAidResourceService; +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.jeecg.common.system.base.controller.JeecgController; +import org.jeecg.global.GlobalUtils; +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.List; + +@Tag(name = "急救宣教资源管理") +@RestController +@RequestMapping("/emergency/firstAid/resource") +@Slf4j +public class FirstAidResourceController extends JeecgController { + + @Autowired + private IFirstAidResourceService resourceService; + + @Operation(summary = "急救宣教资源-分页列表查询") + @GetMapping(value = "/list") + public Result> queryPageList(FirstAidResource entity, + @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, + HttpServletRequest req) { + Page page = new Page<>(pageNo, pageSize); + String userId = GlobalUtils.getLoginUser().getId(); + return Result.OK(resourceService.queryPageList(entity, page, userId)); + } + + @Operation(summary = "急救宣教资源-添加") + @AutoLog(value = "急救宣教资源-添加") + @PostMapping(value = "/add") + public Result add(@RequestBody FirstAidResource entity) { + if (StrUtil.isBlank(entity.getTitle())) { + return Result.error("标题不能为空"); + } + resourceService.saveResource(entity); + return Result.OK("添加成功!"); + } + + @Operation(summary = "急救宣教资源-编辑") + @AutoLog(value = "急救宣教资源-编辑") + @PostMapping(value = "/edit") + public Result edit(@RequestBody FirstAidResource entity) { + if (resourceService.getById(entity.getId()) == null) { + return Result.error("数据不存在"); + } + resourceService.updateResource(entity); + return Result.OK("编辑成功!"); + } + + @Operation(summary = "急救宣教资源-删除") + @AutoLog(value = "急救宣教资源-删除") + @PostMapping(value = "/delete") + public Result delete(@RequestParam(name = "id") String id) { + resourceService.removeById(id); + return Result.OK("删除成功!"); + } + + @Operation(summary = "急救宣教资源-批量删除") + @AutoLog(value = "急救宣教资源-批量删除") + @PostMapping(value = "/deleteBatch") + public Result deleteBatch(@RequestBody List ids) { + resourceService.removeByIds(ids); + return Result.OK("批量删除成功!"); + } + + @Operation(summary = "急救宣教资源-批量发布") + @AutoLog(value = "急救宣教资源-批量发布") + @PostMapping(value = "/batchPublish") + public Result batchPublish(@RequestBody List ids) { + resourceService.batchPublish(ids); + return Result.OK("批量发布成功!"); + } + + @Operation(summary = "急救宣教资源-批量下架") + @AutoLog(value = "急救宣教资源-批量下架") + @PostMapping(value = "/batchTakeDown") + public Result batchTakeDown(@RequestBody List ids) { + resourceService.batchTakeDown(ids); + return Result.OK("批量下架成功!"); + } + + @Operation(summary = "急救宣教资源-提交审核") + @AutoLog(value = "急救宣教资源-提交审核") + @PostMapping(value = "/submitForReview") + public Result submitForReview(@RequestParam(name = "id") String id) { + try { + resourceService.submitForReview(id); + } catch (RuntimeException e) { + return Result.error(e.getMessage()); + } + return Result.OK("已提交审核"); + } + + @Operation(summary = "急救宣教资源-下架") + @AutoLog(value = "急救宣教资源-下架") + @PostMapping(value = "/takeDown") + public Result takeDown(@RequestParam(name = "id") String id) { + try { + resourceService.takeDown(id); + } catch (RuntimeException e) { + return Result.error(e.getMessage()); + } + return Result.OK("已下架"); + } + + @Operation(summary = "急救宣教资源-上架") + @AutoLog(value = "急救宣教资源-上架") + @PostMapping(value = "/publish") + public Result publish(@RequestParam(name = "id") String id) { + try { + resourceService.publish(id); + } catch (RuntimeException e) { + return Result.error(e.getMessage()); + } + return Result.OK("已上架"); + } + + @Operation(summary = "急救宣教资源-通过id查询详情") + @GetMapping(value = "/queryById") + public Result queryById(@RequestParam(name = "id") String id) { + String userId = GlobalUtils.getLoginUser().getId(); + FirstAidResource entity = resourceService.getDetail(id, userId); + return entity == null ? Result.error("未找到对应数据") : Result.OK(entity); + } + + @Operation(summary = "急救宣教资源-记录阅读") + @AutoLog(value = "急救宣教资源-记录阅读") + @PostMapping(value = "/incrementView") + public Result incrementView(@RequestParam(name = "id") String id) { + String userId = GlobalUtils.getLoginUser().getId(); + boolean firstRead = resourceService.incrementViewCount(id, userId); + return firstRead ? Result.OK("阅读记录成功") : Result.OK("已阅读过"); + } + + @Operation(summary = "急救宣教资源-复制资源") + @AutoLog(value = "急救宣教资源-复制") + @PostMapping(value = "/copy") + public Result copy(@RequestParam(name = "id") String id) { + try { + return Result.OK("复制成功,已保存为草稿", resourceService.copyResource(id)); + } catch (RuntimeException e) { + return Result.error(e.getMessage()); + } + } + + @Operation(summary = "急救宣教资源-导出excel") + @GetMapping(value = "/exportXls") + public ModelAndView exportXls(HttpServletRequest request, FirstAidResource entity) { + return super.exportXls(request, entity, FirstAidResource.class, "急救宣教资源"); + } + + @Operation(summary = "急救宣教资源-导入excel") + @PostMapping(value = "/importExcel") + public Result importExcel(HttpServletRequest request, HttpServletResponse response) { + return super.importExcel(request, response, FirstAidResource.class); + } +} 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 new file mode 100644 index 0000000..0369d7a --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceFavoriteController.java @@ -0,0 +1,82 @@ +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.entity.FirstAidResource; +import com.renkang.emergency.service.IFirstAidResourceUserActionService; +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.jeecg.global.GlobalUtils; +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-22 + * @Version: V1.0 + */ +@Tag(name = "急救宣教资源-收藏管理") +@RestController +@RequestMapping("/emergency/firstAid/favorite") +@Slf4j +public class FirstAidResourceFavoriteController { + + @Autowired + private IFirstAidResourceUserActionService userActionService; + + /** + * 切换收藏状态(收藏/取消收藏) + */ + @AutoLog(value = "急救宣教资源-切换收藏") + @Operation(summary = "切换收藏状态", description = "已收藏则取消,未收藏则收藏") + @PostMapping(value = "/toggle") + public Result> toggle(@RequestParam(name = "resourceId", required = true) String resourceId) { + if (StrUtil.isBlank(resourceId)) { + return Result.error("资源ID不能为空"); + } + String userId = GlobalUtils.getLoginUser().getId(); + boolean favorited = userActionService.toggleFavorite(resourceId, userId); + + Map result = new HashMap<>(); + result.put("favorited", favorited); + return Result.OK(favorited ? "收藏成功" : "已取消收藏", result); + } + + /** + * 判断是否已收藏 + */ + @Operation(summary = "判断收藏状态", description = "查询当前用户是否已收藏该资源") + @GetMapping(value = "/isFavorited") + public Result> isFavorited(@RequestParam(name = "resourceId", required = true) String resourceId) { + if (StrUtil.isBlank(resourceId)) { + return Result.error("资源ID不能为空"); + } + String userId = GlobalUtils.getLoginUser().getId(); + boolean favorited = userActionService.isFavorited(resourceId, userId); + + Map result = new HashMap<>(); + result.put("favorited", favorited); + return Result.OK(result); + } + + /** + * 我的收藏列表 + */ + @Operation(summary = "我的收藏列表", description = "查询当前用户的收藏资源列表") + @GetMapping(value = "/myList") + public Result> myList(@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) { + String userId = GlobalUtils.getLoginUser().getId(); + Page page = new Page<>(pageNo, pageSize); + IPage pageList = userActionService.getMyFavoritePage(page, userId); + return Result.OK(pageList); + } +} 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 new file mode 100644 index 0000000..767a5e3 --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceTagController.java @@ -0,0 +1,124 @@ +package com.renkang.emergency.controller; + +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.entity.FirstAidResourceCategory; +import com.renkang.emergency.service.IFirstAidResourceCategoryService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import lombok.extern.slf4j.Slf4j; +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.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.List; + +@Tag(name = "急救宣教资源-标签管理") +@RestController +@RequestMapping("/emergency/firstAid/tag") +@Slf4j +public class FirstAidResourceTagController extends JeecgController { + + @Autowired + private IFirstAidResourceCategoryService categoryService; + + @Operation(summary = "急救宣教资源标签-分页列表查询") + @GetMapping(value = "/list") + public Result> queryPageList(FirstAidResourceCategory entity, + @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, + HttpServletRequest req) { + entity.setType(FirstAidConstants.TYPE_TAG); + QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(entity, req.getParameterMap()); + Page page = new Page<>(pageNo, pageSize); + return Result.OK(categoryService.page(page, queryWrapper)); + } + + @Operation(summary = "急救宣教资源标签-全部列表") + @GetMapping(value = "/listAll") + public Result> listAll() { + return Result.OK(categoryService.listTags()); + } + + @Operation(summary = "急救宣教资源标签-添加") + @AutoLog(value = "急救宣教资源标签-添加") + //@RequiresPermissions("emergency:firstAidTag:add") + @PostMapping(value = "/add") + public Result add(@RequestBody FirstAidResourceCategory entity) { + entity.setType(FirstAidConstants.TYPE_TAG); + if (entity.getSortNo() == null) entity.setSortNo(0); + if (entity.getStatus() == null) entity.setStatus(FirstAidConstants.NORMAL); + categoryService.save(entity); + return Result.OK("添加成功!"); + } + + @Operation(summary = "急救宣教资源标签-编辑") + @AutoLog(value = "急救宣教资源标签-编辑") + //@RequiresPermissions("emergency:firstAidTag:edit") + @PostMapping(value = "/edit") + public Result edit(@RequestBody FirstAidResourceCategory entity) { + FirstAidResourceCategory old = categoryService.getById(entity.getId()); + if (old == null) return Result.error("数据不存在"); + if (!FirstAidConstants.TYPE_TAG.equals(old.getType())) return Result.error("该记录不是标签"); + entity.setType(old.getType()); + categoryService.updateById(entity); + return Result.OK("编辑成功!"); + } + + @Operation(summary = "急救宣教资源标签-删除") + @AutoLog(value = "急救宣教资源标签-删除") + //@RequiresPermissions("emergency:firstAidTag:delete") + @PostMapping(value = "/delete") + public Result delete(@RequestParam(name = "id") String id) { + try { + categoryService.deleteWithCheck(id); + } catch (RuntimeException e) { + return Result.error(e.getMessage()); + } + return Result.OK("删除成功!"); + } + + @Operation(summary = "急救宣教资源标签-批量删除") + @AutoLog(value = "急救宣教资源标签-批量删除") + //@RequiresPermissions("emergency:firstAidTag:deleteBatch") + @PostMapping(value = "/deleteBatch") + public Result deleteBatch(@RequestBody List ids) { + for (String id : ids) { + try { + categoryService.deleteWithCheck(id); + } catch (RuntimeException e) { + return Result.error("ID[" + id + "]:" + e.getMessage()); + } + } + return Result.OK("批量删除成功!"); + } + + @Operation(summary = "急救宣教资源标签-通过id查询") + @GetMapping(value = "/queryById") + public Result queryById(@RequestParam(name = "id") String id) { + FirstAidResourceCategory entity = categoryService.getById(id); + return entity == null ? Result.error("未找到对应数据") : Result.OK(entity); + } + + @Operation(summary = "急救宣教资源标签-导出excel") + //@RequiresPermissions("emergency:firstAidTag:exportXls") + @GetMapping(value = "/exportXls") + public ModelAndView exportXls(HttpServletRequest request, FirstAidResourceCategory entity) { + return super.exportXls(request, entity, FirstAidResourceCategory.class, "急救宣教资源标签"); + } + + @Operation(summary = "急救宣教资源标签-导入excel") + //@RequiresPermissions("emergency:firstAidTag:importExcel") + @PostMapping(value = "/importExcel") + public Result importExcel(HttpServletRequest request, HttpServletResponse response) { + return super.importExcel(request, response, FirstAidResourceCategory.class); + } +} 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 new file mode 100644 index 0000000..59fa3b7 --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/controller/FirstAidResourceVersionController.java @@ -0,0 +1,78 @@ +package com.renkang.emergency.controller; + +import com.renkang.emergency.entity.FirstAidResourceVersion; +import com.renkang.emergency.service.IFirstAidResourceVersionService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +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.List; +import java.util.Map; + +/** + * @Description: 急救宣教资源-版本管理 + * @Author: jeecg-boot + * @Date: 2026-06-22 + * @Version: V1.0 + */ +@Tag(name = "急救宣教资源-版本管理") +@RestController +@RequestMapping("/emergency/firstAid/version") +@Slf4j +public class FirstAidResourceVersionController { + + @Autowired + private IFirstAidResourceVersionService versionService; + + /** + * 查询某资源的版本历史 + */ + @Operation(summary = "版本历史列表", description = "查询某资源的所有版本号,按版本倒序") + @GetMapping(value = "/list") + public Result> list(@RequestParam(name = "resourceId", required = true) String resourceId) { + List list = versionService.listVersions(resourceId); + return Result.OK(list); + } + + /** + * 回滚到指定版本 + */ + @AutoLog(value = "急救宣教资源-版本回滚") + //@RequiresPermissions("emergency:firstAidResource:edit") + @Operation(summary = "回滚到指定版本", description = "将指定版本的内容恢复到资源表") + @PostMapping(value = "/rollback") + public Result rollback(@RequestParam(name = "versionId", required = true) String versionId) { + try { + versionService.rollback(versionId); + } catch (RuntimeException e) { + return Result.error(e.getMessage()); + } + return Result.OK("回滚成功"); + } + + /** + * 版本差异对比 + */ + @Operation(summary = "版本差异对比", description = "对比两个版本的标题和内容差异") + @GetMapping(value = "/diff") + public Result> diff(@RequestParam(name = "versionId1", required = true) String versionId1, + @RequestParam(name = "versionId2", required = true) String versionId2) { + FirstAidResourceVersion v1 = versionService.getById(versionId1); + FirstAidResourceVersion v2 = versionService.getById(versionId2); + if (v1 == null || v2 == null) { + return Result.error("版本记录不存在"); + } + if (!v1.getResourceId().equals(v2.getResourceId())) { + return Result.error("两个版本不属于同一资源,无法对比"); + } + Map result = new HashMap<>(); + result.put("version1", v1); + result.put("version2", v2); + return Result.OK(result); + } +} 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 new file mode 100644 index 0000000..9027003 --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/FirstAidResourceCategoryMapper.java @@ -0,0 +1,55 @@ +package com.renkang.emergency.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.renkang.emergency.entity.FirstAidResourceCategory; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + * @Description: 急救宣教资源分类/标签 + * @Author: jeecg-boot + * @Date: 2026-06-22 + * @Version: V1.0 + */ +@Mapper +public interface FirstAidResourceCategoryMapper extends BaseMapper { + + /** + * 查询某分类下的子分类数量(级联删除校验用) + */ + @Select("SELECT COUNT(*) FROM QH_EME_FIRST_AID_RESOURCE_CATEGORY WHERE PARENT_ID = #{parentId} AND TYPE = 1 AND DEL_FLAG = 0") + Integer countChildrenByParentId(@Param("parentId") String parentId); + + /** + * 查询某分类下的资源数量(级联删除校验用) + */ + @Select("SELECT COUNT(*) FROM QH_EME_FIRST_AID_RESOURCE WHERE CATEGORY_ID = #{categoryId} AND DEL_FLAG = 0") + Integer countResourcesByCategoryId(@Param("categoryId") String categoryId); + + /** + * 查询引用某标签的资源数量(标签删除校验用) + */ + @Select("SELECT COUNT(*) FROM QH_EME_FIRST_AID_RESOURCE WHERE DEL_FLAG = 0 AND TAGS LIKE CONCAT('%', #{tagId}, '%')") + Integer countResourcesByTagId(@Param("tagId") String tagId); + + /** + * 按类型查询分类/标签列表 + */ + @Select("SELECT * FROM QH_EME_FIRST_AID_RESOURCE_CATEGORY WHERE TYPE = #{type} AND STATUS = 1 AND DEL_FLAG = 0 ORDER BY SORT_NO ASC, CREATE_TIME DESC") + List selectByType(@Param("type") Integer type); + + /** + * 按父分类ID查询子分类列表(树形结构用) + */ + @Select("SELECT * FROM QH_EME_FIRST_AID_RESOURCE_CATEGORY WHERE PARENT_ID = #{parentId} AND TYPE = 1 AND STATUS = 1 AND DEL_FLAG = 0 ORDER BY SORT_NO ASC") + List selectChildrenByParentId(@Param("parentId") String parentId); + + /** + * 查询所有根分类(PARENT_ID IS NULL) + */ + @Select("SELECT * FROM QH_EME_FIRST_AID_RESOURCE_CATEGORY WHERE TYPE = 1 AND PARENT_ID IS NULL AND STATUS = 1 AND DEL_FLAG = 0 ORDER BY SORT_NO ASC") + List selectRootCategories(); +} diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/FirstAidResourceMapper.java b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/FirstAidResourceMapper.java new file mode 100644 index 0000000..307071a --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/FirstAidResourceMapper.java @@ -0,0 +1,42 @@ +package com.renkang.emergency.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.renkang.emergency.entity.FirstAidResource; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.Update; + +/** + * @Description: 急救宣教资源 + * @Author: jeecg-boot + * @Date: 2026-06-22 + * @Version: V1.0 + */ +@Mapper +public interface FirstAidResourceMapper extends BaseMapper { + + /** + * 查询某分类下的资源数量(级联删除校验用) + */ + @Select("SELECT COUNT(*) FROM QH_EME_FIRST_AID_RESOURCE WHERE CATEGORY_ID = #{categoryId} AND DEL_FLAG = 0") + Integer countByCategoryId(@Param("categoryId") String categoryId); + + /** + * 浏览计数+1 + */ + @Update("UPDATE QH_EME_FIRST_AID_RESOURCE SET VIEW_COUNT = VIEW_COUNT + 1 WHERE ID = #{id}") + void incrementViewCount(@Param("id") String id); + + /** + * 收藏计数+1 + */ + @Update("UPDATE QH_EME_FIRST_AID_RESOURCE SET FAVORITE_COUNT = FAVORITE_COUNT + 1 WHERE ID = #{id}") + void incrementFavoriteCount(@Param("id") String id); + + /** + * 收藏计数-1 + */ + @Update("UPDATE QH_EME_FIRST_AID_RESOURCE SET FAVORITE_COUNT = FAVORITE_COUNT - 1 WHERE ID = #{id} AND FAVORITE_COUNT > 0") + void decrementFavoriteCount(@Param("id") String id); +} diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/FirstAidResourceUserActionMapper.java b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/FirstAidResourceUserActionMapper.java new file mode 100644 index 0000000..3a0c5a3 --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/FirstAidResourceUserActionMapper.java @@ -0,0 +1,45 @@ +package com.renkang.emergency.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.renkang.emergency.entity.FirstAidResource; +import com.renkang.emergency.entity.FirstAidResourceUserAction; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + * @Description: 用户行为记录 + * @Author: jeecg-boot + * @Date: 2026-06-22 + * @Version: V1.0 + */ +@Mapper +public interface FirstAidResourceUserActionMapper extends BaseMapper { + + /** + * 查询用户对一批资源的收藏状态 + */ + @Select("") + List selectFavoritedResourceIds(@Param("userId") String userId, + @Param("resourceIds") List resourceIds); + + /** + * 查询用户的收藏资源列表(分页) + */ + @Select("SELECT R.* FROM QH_EME_FIRST_AID_RESOURCE R " + + "INNER JOIN QH_EME_FIRST_AID_RESOURCE_USER_ACTION A ON R.ID = A.RESOURCE_ID " + + "WHERE A.USER_ID = #{userId} AND A.TYPE = 2 AND R.DEL_FLAG = 0 " + + "ORDER BY A.CREATE_TIME DESC") + IPage selectFavoritePage(Page page, @Param("userId") String userId); +} diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/FirstAidResourceVersionMapper.java b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/FirstAidResourceVersionMapper.java new file mode 100644 index 0000000..1e74488 --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/FirstAidResourceVersionMapper.java @@ -0,0 +1,31 @@ +package com.renkang.emergency.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.renkang.emergency.entity.FirstAidResourceVersion; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + * @Description: 资源版本历史 + * @Author: jeecg-boot + * @Date: 2026-06-22 + * @Version: V1.0 + */ +@Mapper +public interface FirstAidResourceVersionMapper extends BaseMapper { + + /** + * 查询某资源的最高版本号 + */ + @Select("SELECT MAX(VERSION_NO) FROM QH_EME_FIRST_AID_RESOURCE_VERSION WHERE RESOURCE_ID = #{resourceId}") + Integer selectMaxVersionNo(@Param("resourceId") String resourceId); + + /** + * 查询某资源的所有版本历史(按版本号倒序) + */ + @Select("SELECT * FROM QH_EME_FIRST_AID_RESOURCE_VERSION WHERE RESOURCE_ID = #{resourceId} ORDER BY VERSION_NO DESC") + List selectByResourceId(@Param("resourceId") String resourceId); +} diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/xml/FirstAidResourceCategoryMapper.xml b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/xml/FirstAidResourceCategoryMapper.xml new file mode 100644 index 0000000..192e7a7 --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/xml/FirstAidResourceCategoryMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/xml/FirstAidResourceMapper.xml b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/xml/FirstAidResourceMapper.xml new file mode 100644 index 0000000..0925aba --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/xml/FirstAidResourceMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/xml/FirstAidResourceUserActionMapper.xml b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/xml/FirstAidResourceUserActionMapper.xml new file mode 100644 index 0000000..40c971d --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/xml/FirstAidResourceUserActionMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/xml/FirstAidResourceVersionMapper.xml b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/xml/FirstAidResourceVersionMapper.xml new file mode 100644 index 0000000..95743fc --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/mapper/xml/FirstAidResourceVersionMapper.xml @@ -0,0 +1,5 @@ + + + + + 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 new file mode 100644 index 0000000..a6ae0a3 --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/IFirstAidResourceCategoryService.java @@ -0,0 +1,40 @@ +package com.renkang.emergency.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.renkang.emergency.entity.FirstAidResourceCategory; + +import java.util.List; + +/** + * @Description: 急救宣教资源分类/标签 + * @Author: jeecg-boot + * @Date: 2026-06-22 + * @Version: V1.0 + */ +public interface IFirstAidResourceCategoryService extends IService { + + /** + * 查询所有有效分类(根分类+子分类) + */ + List listCategories(); + + /** + * 查询根分类列表(树形结构顶层) + */ + List listRootCategories(); + + /** + * 按父分类ID查询子分类 + */ + List listChildrenByParentId(String parentId); + + /** + * 查询所有有效标签列表 + */ + List listTags(); + + /** + * 删除前校验(分类下有子分类/资源则拒绝;标签有资源引用则拒绝) + */ + void deleteWithCheck(String id); +} 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 new file mode 100644 index 0000000..74da04d --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/IFirstAidResourceService.java @@ -0,0 +1,53 @@ +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.FirstAidResource; + +import java.util.List; + +/** + * @Description: 急救宣教资源 + * @Author: jeecg-boot + * @Date: 2026-06-22 + * @Version: V1.0 + */ +public interface IFirstAidResourceService extends IService { + + void saveResource(FirstAidResource resource); + + void updateResource(FirstAidResource resource); + + FirstAidResource copyResource(String id); + + /** 提交审核 */ + void submitForReview(String id); + + /** 下架 */ + void takeDown(String id); + + /** 上架(发布) */ + void publish(String id); + + /** 审核通过 */ + void approve(String id); + + /** 审核驳回 */ + void reject(String id, String rejectReason); + + /** 批量发布 */ + void batchPublish(List ids); + + /** 批量下架 */ + void batchTakeDown(List ids); + + 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); +} diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/IFirstAidResourceUserActionService.java b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/IFirstAidResourceUserActionService.java new file mode 100644 index 0000000..819fc09 --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/IFirstAidResourceUserActionService.java @@ -0,0 +1,49 @@ +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.FirstAidResource; +import com.renkang.emergency.entity.FirstAidResourceUserAction; + +import java.util.List; + +/** + * @Description: 用户行为记录(阅读/收藏) + * @Author: jeecg-boot + * @Date: 2026-06-22 + * @Version: V1.0 + */ +public interface IFirstAidResourceUserActionService extends IService { + + /** + * 记录阅读行为(去重,已读则忽略) + * + * @return true=首次阅读(已计数), false=已读过(忽略) + */ + boolean recordRead(String resourceId, String userId); + + /** + * 切换收藏状态(收藏/取消收藏) + * + * @return true=已收藏, false=已取消 + */ + boolean toggleFavorite(String resourceId, String userId); + + /** + * 判断用户是否已收藏某资源 + */ + boolean isFavorited(String resourceId, String userId); + + /** + * 批量查询用户对一批资源的收藏状态 + * + * @return 已收藏的资源ID集合 + */ + List getFavoritedResourceIds(String userId, List resourceIds); + + /** + * 我的收藏分页列表 + */ + IPage getMyFavoritePage(Page page, String userId); +} 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 new file mode 100644 index 0000000..d2af997 --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/IFirstAidResourceVersionService.java @@ -0,0 +1,30 @@ +package com.renkang.emergency.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.renkang.emergency.entity.FirstAidResourceVersion; + +import java.util.List; + +/** + * @Description: 资源版本历史 + * @Author: jeecg-boot + * @Date: 2026-06-22 + * @Version: V1.0 + */ +public interface IFirstAidResourceVersionService extends IService { + + /** + * 保存版本快照 + */ + void saveVersion(String resourceId, String title, String content, String changeDescription); + + /** + * 查询某资源的所有版本 + */ + List listVersions(String resourceId); + + /** + * 回滚到指定版本(将版本内容恢复到资源表) + */ + void rollback(String versionId); +} 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 new file mode 100644 index 0000000..4d3a324 --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/impl/FirstAidResourceCategoryServiceImpl.java @@ -0,0 +1,98 @@ +package com.renkang.emergency.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.renkang.emergency.constant.FirstAidConstants; +import com.renkang.emergency.entity.FirstAidResourceCategory; +import com.renkang.emergency.mapper.FirstAidResourceCategoryMapper; +import com.renkang.emergency.mapper.FirstAidResourceMapper; +import com.renkang.emergency.service.IFirstAidResourceCategoryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @Description: 急救宣教资源分类/标签 + * @Author: jeecg-boot + * @Date: 2026-06-22 + * @Version: V1.0 + */ +@Service +public class FirstAidResourceCategoryServiceImpl extends ServiceImpl implements IFirstAidResourceCategoryService { + + @Autowired + private FirstAidResourceCategoryMapper categoryMapper; + + @Autowired + private FirstAidResourceMapper resourceMapper; + + @Override + public List listCategories() { + List list = categoryMapper.selectByType(FirstAidConstants.TYPE_CATEGORY); + fillResourceCounts(list); + return list; + } + + @Override + public List listRootCategories() { + List list = categoryMapper.selectRootCategories(); + fillResourceCounts(list); + return list; + } + + @Override + public List listChildrenByParentId(String parentId) { + List list = categoryMapper.selectChildrenByParentId(parentId); + fillResourceCounts(list); + return list; + } + + @Override + public List listTags() { + List list = categoryMapper.selectByType(FirstAidConstants.TYPE_TAG); + for (FirstAidResourceCategory tag : list) { + Integer count = categoryMapper.countResourcesByTagId(tag.getId()); + tag.setResourceCount(count != null ? count : 0); + } + return list; + } + + /** + * 填充分类的资源数量(分类直查 categoryId) + */ + private void fillResourceCounts(List categories) { + for (FirstAidResourceCategory cat : categories) { + Integer count = resourceMapper.countByCategoryId(cat.getId()); + cat.setResourceCount(count != null ? count : 0); + } + } + + @Override + public void deleteWithCheck(String id) { + FirstAidResourceCategory record = getById(id); + if (record == null) { + throw new RuntimeException("数据不存在"); + } + + if (FirstAidConstants.TYPE_CATEGORY.equals(record.getType())) { + // 分类:检查是否有子分类 + Integer childCount = categoryMapper.countChildrenByParentId(id); + if (childCount != null && childCount > 0) { + throw new RuntimeException("该分类下存在子分类,无法删除"); + } + // 分类:检查是否有资源 + Integer resourceCount = resourceMapper.countByCategoryId(id); + if (resourceCount != null && resourceCount > 0) { + throw new RuntimeException("该分类下存在资源,无法删除"); + } + } else if (FirstAidConstants.TYPE_TAG.equals(record.getType())) { + // 标签:检查是否有资源引用 + Integer resourceCount = categoryMapper.countResourcesByTagId(id); + if (resourceCount != null && resourceCount > 0) { + throw new RuntimeException("该标签已被资源引用,无法删除"); + } + } + + removeById(id); + } +} 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 new file mode 100644 index 0000000..15624e7 --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/impl/FirstAidResourceServiceImpl.java @@ -0,0 +1,338 @@ +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.constant.FirstAidConstants; +import com.renkang.emergency.entity.FirstAidResource; +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.IFirstAidResourceUserActionService; +import com.renkang.emergency.service.IFirstAidResourceVersionService; +import org.jeecg.common.constant.CommonConstant; +import org.jeecg.global.GlobalUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @Description: 急救宣教资源 + * @Author: jeecg-boot + * @Date: 2026-06-22 + * @Version: V1.0 + */ +@Service +public class FirstAidResourceServiceImpl extends ServiceImpl implements IFirstAidResourceService { + + @Autowired + private FirstAidResourceMapper resourceMapper; + + @Autowired + private FirstAidResourceCategoryMapper categoryMapper; + + @Autowired + private IFirstAidResourceUserActionService userActionService; + + @Autowired + private IFirstAidResourceVersionService versionService; + + @Override + @Transactional(rollbackFor = Exception.class) + public void saveResource(FirstAidResource resource) { + if (resource.getViewCount() == null) { + resource.setViewCount(0); + } + if (resource.getFavoriteCount() == null) { + resource.setFavoriteCount(0); + } + resource.setStatus(FirstAidConstants.STATUS_DRAFT); + resource.setAuditStatus(null); + save(resource); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateResource(FirstAidResource resource) { + FirstAidResource old = getById(resource.getId()); + if (old == null) { + throw new RuntimeException("资源不存在"); + } + versionService.saveVersion(old.getId(), old.getTitle(), old.getContent(), "编辑更新"); + // 编辑后自动退回草稿,清除审核状态(方案A) + resource.setStatus(FirstAidConstants.STATUS_DRAFT); + resource.setAuditStatus(null); + resource.setAuditRejectReason(null); + updateById(resource); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public FirstAidResource copyResource(String id) { + FirstAidResource source = getById(id); + if (source == null) { + throw new RuntimeException("源资源不存在"); + } + FirstAidResource copy = new FirstAidResource(); + copy.setTitle(source.getTitle() + " - 副本"); + copy.setSummary(source.getSummary()); + copy.setContentType(source.getContentType()); + copy.setCategoryId(source.getCategoryId()); + copy.setApplicableScenario(source.getApplicableScenario()); + copy.setTags(source.getTags()); + copy.setContent(source.getContent()); + copy.setCoverImage(source.getCoverImage()); + copy.setFileUrl(source.getFileUrl()); + copy.setStatus(FirstAidConstants.STATUS_DRAFT); + copy.setAuditStatus(null); + copy.setViewCount(0); + copy.setFavoriteCount(0); + save(copy); + return copy; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void submitForReview(String id) { + FirstAidResource resource = getById(id); + if (resource == null) { + throw new RuntimeException("资源不存在"); + } + resource.setAuditStatus(FirstAidConstants.AUDIT_STATUS_PENDING); + resource.setAuditRejectReason(null); + updateById(resource); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void takeDown(String id) { + FirstAidResource resource = getById(id); + if (resource == null) { + throw new RuntimeException("资源不存在"); + } + resource.setStatus(FirstAidConstants.STATUS_DOWN); + updateById(resource); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void publish(String id) { + FirstAidResource resource = getById(id); + if (resource == null) { + throw new RuntimeException("资源不存在"); + } + resource.setStatus(FirstAidConstants.STATUS_PUBLISHED); + resource.setAuditStatus(FirstAidConstants.AUDIT_STATUS_APPROVED); + resource.setAuditRejectReason(null); + resource.setAuditBy(GlobalUtils.getLoginUser().getRealname()); + resource.setAuditTime(new Date()); + updateById(resource); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void approve(String id) { + FirstAidResource resource = getById(id); + if (resource == null) { + throw new RuntimeException("资源不存在"); + } + resource.setAuditStatus(FirstAidConstants.AUDIT_STATUS_APPROVED); + resource.setAuditRejectReason(null); + resource.setStatus(FirstAidConstants.STATUS_PUBLISHED); + resource.setAuditBy(GlobalUtils.getLoginUser().getRealname()); + resource.setAuditTime(new Date()); + updateById(resource); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void reject(String id, String rejectReason) { + FirstAidResource resource = getById(id); + if (resource == null) { + throw new RuntimeException("资源不存在"); + } + resource.setAuditStatus(FirstAidConstants.AUDIT_STATUS_REJECTED); + resource.setAuditRejectReason(rejectReason); + resource.setAuditBy(GlobalUtils.getLoginUser().getRealname()); + resource.setAuditTime(new Date()); + updateById(resource); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void batchPublish(List ids) { + Date now = new Date(); + String auditBy = GlobalUtils.getLoginUser().getRealname(); + 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.setAuditTime(now); + resource.setAuditRejectReason(null); + updateById(resource); + } + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void batchTakeDown(List ids) { + for (String id : ids) { + FirstAidResource resource = getById(id); + if (resource != null) { + resource.setStatus(FirstAidConstants.STATUS_DOWN); + updateById(resource); + } + } + } + + @Override + public IPage 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())); + } + if (StrUtil.isNotBlank(resource.getCategoryId())) { + queryWrapper.eq(FirstAidResource::getCategoryId, resource.getCategoryId()); + } + if (StrUtil.isNotBlank(resource.getContentType())) { + queryWrapper.eq(FirstAidResource::getContentType, resource.getContentType()); + } + if (resource.getAuditStatus() != null) { + queryWrapper.eq(FirstAidResource::getAuditStatus, resource.getAuditStatus()); + } + if (resource.getStatus() != null) { + queryWrapper.eq(FirstAidResource::getStatus, resource.getStatus()); + } + // 前端复合状态筛选:≤9 查status,≥10 查auditStatus + if (resource.getCombinedStatus() != null) { + if (resource.getCombinedStatus() < 10) { + queryWrapper.eq(FirstAidResource::getStatus, resource.getCombinedStatus()); + } else { + queryWrapper.eq(FirstAidResource::getAuditStatus, resource.getCombinedStatus()); + } + } + // 标签过滤 + if (StrUtil.isNotBlank(resource.getTags())) { + String[] tagIds = resource.getTags().split(","); + for (String tagId : tagIds) { + if (StrUtil.isNotBlank(tagId)) { + queryWrapper.like(FirstAidResource::getTags, tagId.trim()); + } + } + } + + queryWrapper.eq(FirstAidResource::getDelFlag, CommonConstant.DEL_FLAG_0); + queryWrapper.orderByDesc(FirstAidResource::getCreateTime); + + IPage result = page(page, queryWrapper); + fillResourceExtras(result.getRecords(), userId); + return result; + } + + @Override + public IPage 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) { + return userActionService.recordRead(id, userId); + } + + @Override + public FirstAidResource getDetail(String id, String userId) { + FirstAidResource resource = getById(id); + if (resource != null) { + fillResourceExtras(Collections.singletonList(resource), userId); + } + return resource; + } + + private void fillResourceExtras(List resources, String userId) { + if (CollectionUtil.isEmpty(resources)) { + return; + } + List resourceIds = resources.stream().map(FirstAidResource::getId).collect(Collectors.toList()); + // 未登录用户无需查询收藏状态 + List favoritedIds = StrUtil.isNotBlank(userId) + ? userActionService.getFavoritedResourceIds(userId, resourceIds) + : Collections.emptyList(); + + for (FirstAidResource resource : resources) { + if (StrUtil.isNotBlank(resource.getCategoryId())) { + FirstAidResourceCategory category = categoryMapper.selectById(resource.getCategoryId()); + if (category != null) { + resource.setCategoryName(category.getName()); + } + } + if (StrUtil.isNotBlank(resource.getTags())) { + List tagNames = new ArrayList<>(); + String[] tagIds = resource.getTags().split(","); + for (String tagId : tagIds) { + String trimmedId = tagId.trim(); + if (StrUtil.isNotBlank(trimmedId)) { + FirstAidResourceCategory tag = categoryMapper.selectById(trimmedId); + if (tag != null) { + tagNames.add(tag.getName()); + } + } + } + resource.setTagNameList(tagNames); + } + resource.setIsFavorited(favoritedIds.contains(resource.getId())); + } + } +} diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/impl/FirstAidResourceUserActionServiceImpl.java b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/impl/FirstAidResourceUserActionServiceImpl.java new file mode 100644 index 0000000..af8bd71 --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/impl/FirstAidResourceUserActionServiceImpl.java @@ -0,0 +1,109 @@ +package com.renkang.emergency.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +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.constant.FirstAidConstants; +import com.renkang.emergency.entity.FirstAidResource; +import com.renkang.emergency.entity.FirstAidResourceUserAction; +import com.renkang.emergency.mapper.FirstAidResourceMapper; +import com.renkang.emergency.mapper.FirstAidResourceUserActionMapper; +import com.renkang.emergency.service.IFirstAidResourceUserActionService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collections; +import java.util.List; + +/** + * @Description: 用户行为记录(阅读/收藏) + * @Author: jeecg-boot + * @Date: 2026-06-22 + * @Version: V1.0 + */ +@Service +public class FirstAidResourceUserActionServiceImpl extends ServiceImpl implements IFirstAidResourceUserActionService { + + @Autowired + private FirstAidResourceUserActionMapper actionMapper; + + @Autowired + private FirstAidResourceMapper resourceMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean recordRead(String resourceId, String userId) { + // 检查是否已有阅读记录 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(FirstAidResourceUserAction::getResourceId, resourceId) + .eq(FirstAidResourceUserAction::getUserId, userId) + .eq(FirstAidResourceUserAction::getType, FirstAidConstants.ACTION_TYPE_READ); + if (ObjectUtil.isNotNull(getOne(queryWrapper, false))) { + return false; + } + + // 插入阅读记录 + FirstAidResourceUserAction action = new FirstAidResourceUserAction(); + action.setResourceId(resourceId); + action.setUserId(userId); + action.setType(FirstAidConstants.ACTION_TYPE_READ); + save(action); + + // 浏览计数+1 + resourceMapper.incrementViewCount(resourceId); + return true; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean toggleFavorite(String resourceId, String userId) { + // 查是否已收藏 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(FirstAidResourceUserAction::getResourceId, resourceId) + .eq(FirstAidResourceUserAction::getUserId, userId) + .eq(FirstAidResourceUserAction::getType, FirstAidConstants.ACTION_TYPE_FAVORITE); + FirstAidResourceUserAction existing = getOne(queryWrapper, false); + + if (ObjectUtil.isNotNull(existing)) { + // 已收藏 → 取消收藏 + removeById(existing.getId()); + resourceMapper.decrementFavoriteCount(resourceId); + return false; + } else { + // 未收藏 → 收藏 + FirstAidResourceUserAction action = new FirstAidResourceUserAction(); + action.setResourceId(resourceId); + action.setUserId(userId); + action.setType(FirstAidConstants.ACTION_TYPE_FAVORITE); + save(action); + resourceMapper.incrementFavoriteCount(resourceId); + return true; + } + } + + @Override + public boolean isFavorited(String resourceId, String userId) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(FirstAidResourceUserAction::getResourceId, resourceId) + .eq(FirstAidResourceUserAction::getUserId, userId) + .eq(FirstAidResourceUserAction::getType, FirstAidConstants.ACTION_TYPE_FAVORITE); + return ObjectUtil.isNotNull(getOne(queryWrapper, false)); + } + + @Override + public List getFavoritedResourceIds(String userId, List resourceIds) { + if (CollectionUtil.isEmpty(resourceIds)) { + return Collections.emptyList(); + } + return actionMapper.selectFavoritedResourceIds(userId, resourceIds); + } + + @Override + public IPage getMyFavoritePage(Page page, String userId) { + return actionMapper.selectFavoritePage(page, userId); + } +} diff --git a/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/impl/FirstAidResourceVersionServiceImpl.java b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/impl/FirstAidResourceVersionServiceImpl.java new file mode 100644 index 0000000..366173a --- /dev/null +++ b/health-emergency/health-emergency-biz/src/main/java/com/renkang/emergency/service/impl/FirstAidResourceVersionServiceImpl.java @@ -0,0 +1,75 @@ +package com.renkang.emergency.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.renkang.emergency.constant.FirstAidConstants; +import com.renkang.emergency.entity.FirstAidResource; +import com.renkang.emergency.entity.FirstAidResourceVersion; +import com.renkang.emergency.mapper.FirstAidResourceMapper; +import com.renkang.emergency.mapper.FirstAidResourceVersionMapper; +import com.renkang.emergency.service.IFirstAidResourceVersionService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * @Description: 资源版本历史 + * @Author: jeecg-boot + * @Date: 2026-06-22 + * @Version: V1.0 + */ +@Service +public class FirstAidResourceVersionServiceImpl extends ServiceImpl implements IFirstAidResourceVersionService { + + @Autowired + private FirstAidResourceVersionMapper versionMapper; + + @Autowired + private FirstAidResourceMapper resourceMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public void saveVersion(String resourceId, String title, String content, String changeDescription) { + Integer maxNo = versionMapper.selectMaxVersionNo(resourceId); + int nextVersion = (maxNo == null) ? 1 : maxNo + 1; + + FirstAidResourceVersion version = new FirstAidResourceVersion(); + version.setResourceId(resourceId); + version.setVersionNo(nextVersion); + version.setTitle(title); + version.setContent(content); + version.setChangeDescription(changeDescription); + save(version); + } + + @Override + public List listVersions(String resourceId) { + return versionMapper.selectByResourceId(resourceId); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void rollback(String versionId) { + FirstAidResourceVersion version = getById(versionId); + if (version == null) { + throw new RuntimeException("版本记录不存在"); + } + + FirstAidResource resource = resourceMapper.selectById(version.getResourceId()); + if (resource == null) { + throw new RuntimeException("资源不存在"); + } + + // 回滚前先保存当前状态为版本快照(防止回滚操作不可逆) + saveVersion(resource.getId(), resource.getTitle(), resource.getContent(), "回滚前自动保存"); + + // 恢复标题和内容,并退回草稿,清除审核状态(与编辑行为一致) + resource.setTitle(version.getTitle()); + resource.setContent(version.getContent()); + resource.setStatus(FirstAidConstants.STATUS_DRAFT); + resource.setAuditStatus(null); + resource.setAuditRejectReason(null); + resourceMapper.updateById(resource); + } +} diff --git a/health-emergency/health-emergency-start/src/main/resources/sql/first_aid_education_resource.sql b/health-emergency/health-emergency-start/src/main/resources/sql/first_aid_education_resource.sql new file mode 100644 index 0000000..a9d8c5a --- /dev/null +++ b/health-emergency/health-emergency-start/src/main/resources/sql/first_aid_education_resource.sql @@ -0,0 +1,174 @@ +-- ===================================================== +-- 急救宣教资源管理功能 DDL(达梦数据库) +-- 表名前缀: QH_EME_ (应急模块) +-- ===================================================== + +-- 1. 急救宣教资源分类/标签统一表 +-- TYPE: 1=分类, 2=标签 +-- 分类支持多级树形(PARENT_ID 指向父分类,NULL=根分类) +-- 标签为全局独立,不归属分类 +CREATE TABLE "QH_EME_FIRST_AID_RESOURCE_CATEGORY" ( + "ID" VARCHAR2(32) NOT NULL, + "NAME" VARCHAR2(100) NOT NULL, + "TYPE" NUMBER(1) DEFAULT 1 NOT NULL, + "PARENT_ID" VARCHAR2(32), + "DESCRIPTION" VARCHAR2(500), + "SORT_NO" NUMBER(10) DEFAULT 0, + "STATUS" NUMBER(1) DEFAULT 1, + "CREATE_BY" VARCHAR2(50), + "CREATE_TIME" TIMESTAMP, + "UPDATE_BY" VARCHAR2(50), + "UPDATE_TIME" TIMESTAMP, + "DEL_FLAG" NUMBER(1) DEFAULT 0, + "MEMO" VARCHAR2(500), + PRIMARY KEY ("ID") +); + +COMMENT ON TABLE "QH_EME_FIRST_AID_RESOURCE_CATEGORY" IS '急救宣教资源分类/标签'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE_CATEGORY"."ID" IS '主键'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE_CATEGORY"."NAME" IS '名称'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE_CATEGORY"."TYPE" IS '类型:1=分类,2=标签'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE_CATEGORY"."PARENT_ID" IS '父分类ID(分类树形结构,标签为NULL)'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE_CATEGORY"."DESCRIPTION" IS '描述'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE_CATEGORY"."SORT_NO" IS '排序号'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE_CATEGORY"."STATUS" IS '状态(1=正常,2=冻结)'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE_CATEGORY"."CREATE_BY" IS '创建人'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE_CATEGORY"."CREATE_TIME" IS '创建时间'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE_CATEGORY"."UPDATE_BY" IS '更新人'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE_CATEGORY"."UPDATE_TIME" IS '更新时间'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE_CATEGORY"."DEL_FLAG" IS '删除标记(0=正常,1=已删除)'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE_CATEGORY"."MEMO" IS '备注'; + +CREATE INDEX "IDX_FA_CATEGORY_TYPE" ON "QH_EME_FIRST_AID_RESOURCE_CATEGORY"("TYPE"); +CREATE INDEX "IDX_FA_CATEGORY_PARENT_ID" ON "QH_EME_FIRST_AID_RESOURCE_CATEGORY"("PARENT_ID"); + +-- 2. 急救宣教资源表 +CREATE TABLE "QH_EME_FIRST_AID_RESOURCE" ( + "ID" VARCHAR2(32) NOT NULL, + "TITLE" VARCHAR2(200) NOT NULL, + "SUMMARY" VARCHAR2(500), + "CONTENT_TYPE" VARCHAR2(32), + "CATEGORY_ID" VARCHAR2(32), + "APPLICABLE_SCENARIO" VARCHAR2(500), + "TAGS" VARCHAR2(2000), + "CONTENT" CLOB, + "COVER_IMAGE" VARCHAR2(500), + "FILE_URL" CLOB, + "EFFECTIVE_TIME" TIMESTAMP, + "EXPIRY_TIME" TIMESTAMP, + "AUDIT_STATUS" NUMBER(2), + "AUDIT_REJECT_REASON" VARCHAR2(500), + "AUDIT_BY" VARCHAR2(50), + "AUDIT_TIME" TIMESTAMP, + "VIEW_COUNT" NUMBER(10) DEFAULT 0, + "FAVORITE_COUNT" NUMBER(10) DEFAULT 0, + "STATUS" NUMBER(1) DEFAULT 1, + "CREATE_BY" VARCHAR2(50), + "CREATE_TIME" TIMESTAMP, + "UPDATE_BY" VARCHAR2(50), + "UPDATE_TIME" TIMESTAMP, + "DEL_FLAG" NUMBER(1) DEFAULT 0, + "MEMO" VARCHAR2(500), + PRIMARY KEY ("ID") +); + +COMMENT ON TABLE "QH_EME_FIRST_AID_RESOURCE" IS '急救宣教资源'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE"."ID" IS '主键'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE"."TITLE" IS '标题'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE"."SUMMARY" IS '摘要/简介(列表展示用)'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE"."CONTENT_TYPE" IS '内容类型:IMAGE_TEXT(图文)/VIDEO(视频)/AUDIO(音频)/PDF(PDF)'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE"."CATEGORY_ID" IS '所属分类ID'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE"."APPLICABLE_SCENARIO" IS '适用场景'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE"."TAGS" IS '标签ID列表(逗号分隔)'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE"."CONTENT" IS '正文内容(富文本HTML)'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE"."COVER_IMAGE" IS '封面图URL'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE"."FILE_URL" IS '附件URL列表(JSON数组)'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE"."EFFECTIVE_TIME" IS '生效时间'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE"."EXPIRY_TIME" IS '失效时间'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE"."AUDIT_STATUS" IS '审核状态(NULL=无审核/10=待审核/11=已通过/12=已驳回)'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE"."AUDIT_REJECT_REASON" IS '驳回原因'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE"."AUDIT_BY" IS '审核人'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE"."AUDIT_TIME" IS '审核时间'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE"."VIEW_COUNT" IS '浏览次数'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE"."FAVORITE_COUNT" IS '收藏次数'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE"."STATUS" IS '发布状态(0=草稿,1=已发布,2=已下架)'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE"."CREATE_BY" IS '创建人'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE"."CREATE_TIME" IS '创建时间'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE"."UPDATE_BY" IS '更新人'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE"."UPDATE_TIME" IS '更新时间'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE"."DEL_FLAG" IS '删除标记(0=正常,1=已删除)'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE"."MEMO" IS '备注'; + +CREATE INDEX "IDX_FA_RESOURCE_CATEGORY_ID" ON "QH_EME_FIRST_AID_RESOURCE"("CATEGORY_ID"); +CREATE INDEX "IDX_FA_RESOURCE_AUDIT_STATUS" ON "QH_EME_FIRST_AID_RESOURCE"("AUDIT_STATUS"); +CREATE INDEX "IDX_FA_RESOURCE_EFFECTIVE_TIME" ON "QH_EME_FIRST_AID_RESOURCE"("EFFECTIVE_TIME"); + +-- 3. 用户行为记录表(阅读+收藏合一) +-- TYPE: 1=阅读, 2=收藏 +CREATE TABLE "QH_EME_FIRST_AID_RESOURCE_USER_ACTION" ( + "ID" VARCHAR2(32) NOT NULL, + "RESOURCE_ID" VARCHAR2(32) NOT NULL, + "USER_ID" VARCHAR2(50) NOT NULL, + "TYPE" NUMBER(1) NOT NULL, + "CREATE_TIME" TIMESTAMP, + PRIMARY KEY ("ID") +); + +COMMENT ON TABLE "QH_EME_FIRST_AID_RESOURCE_USER_ACTION" IS '用户行为记录(阅读/收藏)'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE_USER_ACTION"."ID" IS '主键'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE_USER_ACTION"."RESOURCE_ID" IS '资源ID'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE_USER_ACTION"."USER_ID" IS '用户ID'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE_USER_ACTION"."TYPE" IS '行为类型:1=阅读,2=收藏'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE_USER_ACTION"."CREATE_TIME" IS '创建时间'; + +CREATE UNIQUE INDEX "UK_FA_USER_ACTION" + ON "QH_EME_FIRST_AID_RESOURCE_USER_ACTION"("RESOURCE_ID", "USER_ID", "TYPE"); +CREATE INDEX "IDX_FA_USER_ACTION_USER_TYPE" ON "QH_EME_FIRST_AID_RESOURCE_USER_ACTION"("USER_ID", "TYPE"); + +-- 4. 版本历史表 +-- 每次编辑资源时自动保存版本快照,支持回滚 +CREATE TABLE "QH_EME_FIRST_AID_RESOURCE_VERSION" ( + "ID" VARCHAR2(32) NOT NULL, + "RESOURCE_ID" VARCHAR2(32) NOT NULL, + "VERSION_NO" NUMBER(10) NOT NULL, + "TITLE" VARCHAR2(200), + "CONTENT" CLOB, + "CHANGE_DESCRIPTION" VARCHAR2(500), + "CREATE_BY" VARCHAR2(50), + "CREATE_TIME" TIMESTAMP, + PRIMARY KEY ("ID") +); + +COMMENT ON TABLE "QH_EME_FIRST_AID_RESOURCE_VERSION" IS '资源版本历史'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE_VERSION"."ID" IS '主键'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE_VERSION"."RESOURCE_ID" IS '资源ID'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE_VERSION"."VERSION_NO" IS '版本号(1,2,3...)'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE_VERSION"."TITLE" IS '版本时的标题'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE_VERSION"."CONTENT" IS '版本时的正文内容'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE_VERSION"."CHANGE_DESCRIPTION" IS '变更描述'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE_VERSION"."CREATE_BY" IS '创建人'; +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE_VERSION"."CREATE_TIME" IS '创建时间'; + +CREATE INDEX "IDX_FA_VERSION_RESOURCE_ID" ON "QH_EME_FIRST_AID_RESOURCE_VERSION"("RESOURCE_ID"); + +-- ===================================================== +-- 字典数据(需在应用启动后执行) +-- QH_SYS_DICT / QH_SYS_DICT_ITEM 表由 JEECG-BOOT 框架自动创建 +-- tenant_id = 0 表示系统级字典,所有租户可见 +-- ===================================================== + +-- 字典:内容类型 +INSERT INTO QH_SYS_DICT (ID, TYPE, DICT_NAME, DICT_CODE, DESCRIPTION, DEL_FLAG, TENANT_ID, LOW_APP_ID, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME) +VALUES ('1589123456789100001', 0, '内容类型', 'first_aid_content_type', '急救宣教资源内容类型', 0, 0, NULL, 'admin', SYSDATE, 'admin', SYSDATE); + +INSERT INTO QH_SYS_DICT_ITEM (ID, DICT_ID, ITEM_TEXT, ITEM_VALUE, DESCRIPTION, SORT_ORDER, STATUS, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME) VALUES +('1589123456789100011', '1589123456789100001', '图文', 'IMAGE_TEXT', '图文内容', 1, 1, 'admin', SYSDATE, 'admin', SYSDATE); + +INSERT INTO QH_SYS_DICT_ITEM (ID, DICT_ID, ITEM_TEXT, ITEM_VALUE, DESCRIPTION, SORT_ORDER, STATUS, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME) VALUES +('1589123456789100012', '1589123456789100001', '视频', 'VIDEO', '视频内容', 2, 1, 'admin', SYSDATE, 'admin', SYSDATE); + +INSERT INTO QH_SYS_DICT_ITEM (ID, DICT_ID, ITEM_TEXT, ITEM_VALUE, DESCRIPTION, SORT_ORDER, STATUS, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME) VALUES +('1589123456789100013', '1589123456789100001', '音频', 'AUDIO', '音频内容', 3, 1, 'admin', SYSDATE, 'admin', SYSDATE); + +INSERT INTO QH_SYS_DICT_ITEM (ID, DICT_ID, ITEM_TEXT, ITEM_VALUE, DESCRIPTION, SORT_ORDER, STATUS, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME) VALUES +('1589123456789100014', '1589123456789100001', 'PDF', 'PDF', 'PDF文档', 4, 1, 'admin', SYSDATE, 'admin', SYSDATE); diff --git a/health-emergency/health-emergency-start/src/main/resources/sql/first_aid_migrate_status.sql b/health-emergency/health-emergency-start/src/main/resources/sql/first_aid_migrate_status.sql new file mode 100644 index 0000000..9b156ad --- /dev/null +++ b/health-emergency/health-emergency-start/src/main/resources/sql/first_aid_migrate_status.sql @@ -0,0 +1,77 @@ +-- ===================================================== +-- 急救宣教资源 - 状态字段值域迁移脚本(达梦数据库) +-- 执行时机:代码变更后,启动前执行 +-- 说明:将 AUDIT_STATUS 值域从 {0,1,2} 迁移到 {10,11,12} +-- STATUS 值域不变 {0,1,2} +-- ===================================================== + +-- ===================================================== +-- 1. 数据迁移:AUDIT_STATUS 旧值 → 新值 +-- ===================================================== +-- 旧: 0=待审核, 1=已通过, 2=已驳回 +-- 新: null=无审核(草稿), 10=待审核, 11=已通过, 12=已驳回 +-- +-- 注意: 旧方案中 audit_status=0 同时表示"草稿(未提交)"和"待审核(已提交)" +-- 两者无法区分,为保证数据安全,统一视为"草稿"置为 NULL, +-- 需用户在系统内重新提交审核。 +-- 如需保留为"待审核"状态,将下方的 NULL 改为 10 即可。 + +UPDATE "QH_EME_FIRST_AID_RESOURCE" +SET "AUDIT_STATUS" = CASE + WHEN "AUDIT_STATUS" = 0 THEN NULL -- 草稿(无法区分是否已提交,保守处理) + WHEN "AUDIT_STATUS" = 1 THEN 11 -- 已通过 + WHEN "AUDIT_STATUS" = 2 THEN 12 -- 已驳回 + ELSE "AUDIT_STATUS" +END +WHERE "AUDIT_STATUS" IN (0, 1, 2); + +COMMIT; + + +-- ===================================================== +-- 2. 更新字典项(如有) +-- ===================================================== +-- 如果 QH_SYS_DICT_ITEM 中配置了审核状态字典,需同步更新 ITEM_VALUE +-- 示例(请根据实际字典数据调整): +/* +UPDATE QH_SYS_DICT_ITEM +SET ITEM_VALUE = CASE + WHEN ITEM_VALUE = '0' THEN '10' + WHEN ITEM_VALUE = '1' THEN '11' + WHEN ITEM_VALUE = '2' THEN '12' + ELSE ITEM_VALUE +END +WHERE DICT_ID = ( + SELECT ID FROM QH_SYS_DICT WHERE DICT_CODE = 'first_aid_audit_status' +) +AND ITEM_VALUE IN ('0', '1', '2'); +COMMIT; +*/ + + +-- ===================================================== +-- 3. 验证迁移结果 +-- ===================================================== +SELECT + "AUDIT_STATUS", + CASE + WHEN "AUDIT_STATUS" IS NULL THEN '草稿' + WHEN "AUDIT_STATUS" = 10 THEN '待审核' + WHEN "AUDIT_STATUS" = 11 THEN '已通过' + WHEN "AUDIT_STATUS" = 12 THEN '已驳回' + ELSE '未知状态' + END AS "审核状态描述", + COUNT(*) AS "数量" +FROM "QH_EME_FIRST_AID_RESOURCE" +WHERE "DEL_FLAG" = 0 +GROUP BY "AUDIT_STATUS" +ORDER BY "AUDIT_STATUS" ASC NULLS FIRST; + + +-- ===================================================== +-- 4. 更新表字段注释 +-- ===================================================== +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE"."AUDIT_STATUS" IS +'审核状态(NULL=无审核/10=待审核/11=已通过/12=已驳回)'; + +COMMIT; diff --git a/health-emergency/health-emergency-start/src/main/resources/sql/first_aid_migrate_status_rollback.sql b/health-emergency/health-emergency-start/src/main/resources/sql/first_aid_migrate_status_rollback.sql new file mode 100644 index 0000000..19dcfbe --- /dev/null +++ b/health-emergency/health-emergency-start/src/main/resources/sql/first_aid_migrate_status_rollback.sql @@ -0,0 +1,24 @@ +-- ===================================================== +-- 急救宣教资源 - 状态字段值域回滚脚本(达梦数据库) +-- 仅当需要回退代码时使用 +-- 将 AUDIT_STATUS 从 {null,10,11,12} 回退到 {0,1,2} +-- ===================================================== + +-- 注意: null(草稿) 回退为 0,但此时无法区分"草稿"和"待审核" +UPDATE "QH_EME_FIRST_AID_RESOURCE" +SET "AUDIT_STATUS" = CASE + WHEN "AUDIT_STATUS" IS NULL THEN 0 -- 草稿 → 0(待审核) + WHEN "AUDIT_STATUS" = 10 THEN 0 -- 待审核 → 0 + WHEN "AUDIT_STATUS" = 11 THEN 1 -- 已通过 → 1 + WHEN "AUDIT_STATUS" = 12 THEN 2 -- 已驳回 → 2 + ELSE "AUDIT_STATUS" +END +WHERE "AUDIT_STATUS" IS NULL OR "AUDIT_STATUS" IN (10, 11, 12); + +COMMIT; + +-- 恢复表字段注释 +COMMENT ON COLUMN "QH_EME_FIRST_AID_RESOURCE"."AUDIT_STATUS" IS +'审核状态(0=待审核,1=已通过,2=已驳回)'; + +COMMIT;