feat(emergency): 急救宣教资源管理模块

新增急救宣教资源管理完整功能,包含6个子模块:

- 分类管理:树形结构,CRUD + 级联删除校验
- 标签管理:扁平结构,CRUD + 引用校验
- 资源管理:CRUD + 状态流转(草稿→审核→发布→下架) + 批量操作 + 阅读去重 + 复制
- 审核管理:待审核/已通过/已驳回列表 + 审核操作 + 审核记录
- 收藏管理:收藏/取消切换 + 状态查询 + 我的收藏列表
- 版本管理:编辑自动保存版本快照 + 回滚 + 差异对比

业务规则:
- 编辑/回滚后自动退回草稿,清除审核状态(方案A)
- 阅读去重:同用户重复阅读不增加计数
- 逻辑删除 + 租户隔离

Co-Authored-By: Claude <noreply@anthropic.com>
@
This commit is contained in:
2026-06-23 17:40:30 +08:00
parent 74ebe26a6c
commit 6384021c4d
30 changed files with 2432 additions and 0 deletions
@@ -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;
}
@@ -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<String> tagNameList;
/** 当前用户是否已收藏(非持久字段) */
@TableField(exist = false)
@Schema(title = "当前用户是否已收藏")
private Boolean isFavorited;
/** 复合状态(非持久字段,前端统一筛选:0-9查status10+查auditStatus) */
@TableField(exist = false)
@Schema(title = "复合状态(0=草稿,1=已发布,2=已下架,10=待审核,11=已通过,12=已驳回)")
private Integer combinedStatus;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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<IPage<FirstAidResource>> pending(FirstAidResource entity,
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
Page<FirstAidResource> 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<IPage<FirstAidResource>> passed(FirstAidResource entity,
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
Page<FirstAidResource> 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<IPage<FirstAidResource>> rejected(FirstAidResource entity,
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
Page<FirstAidResource> 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<String> 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<String> 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<IPage<FirstAidResource>> 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<FirstAidResource> 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));
}
}
@@ -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<FirstAidResourceCategory, IFirstAidResourceCategoryService> {
@Autowired
private IFirstAidResourceCategoryService categoryService;
@Operation(summary = "急救宣教资源分类-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<FirstAidResourceCategory>> 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<FirstAidResourceCategory> queryWrapper = QueryGenerator.initQueryWrapper(entity, req.getParameterMap());
Page<FirstAidResourceCategory> page = new Page<>(pageNo, pageSize);
IPage<FirstAidResourceCategory> 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<List<FirstAidResourceCategory>> listAll() {
return Result.OK(categoryService.listCategories());
}
@Operation(summary = "急救宣教资源分类-根分类列表")
@GetMapping(value = "/listRoot")
public Result<List<FirstAidResourceCategory>> listRoot() {
return Result.OK(categoryService.listRootCategories());
}
@Operation(summary = "急救宣教资源分类-子分类列表")
@GetMapping(value = "/listChildren")
public Result<List<FirstAidResourceCategory>> 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<String> 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<String> 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<String> 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<String> deleteBatch(@RequestBody List<String> 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<FirstAidResourceCategory> 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);
}
}
@@ -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<FirstAidResource, IFirstAidResourceService> {
@Autowired
private IFirstAidResourceService resourceService;
@Operation(summary = "急救宣教资源-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<FirstAidResource>> queryPageList(FirstAidResource entity,
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest req) {
Page<FirstAidResource> 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<String> 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<String> 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<String> delete(@RequestParam(name = "id") String id) {
resourceService.removeById(id);
return Result.OK("删除成功!");
}
@Operation(summary = "急救宣教资源-批量删除")
@AutoLog(value = "急救宣教资源-批量删除")
@PostMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestBody List<String> ids) {
resourceService.removeByIds(ids);
return Result.OK("批量删除成功!");
}
@Operation(summary = "急救宣教资源-批量发布")
@AutoLog(value = "急救宣教资源-批量发布")
@PostMapping(value = "/batchPublish")
public Result<String> batchPublish(@RequestBody List<String> ids) {
resourceService.batchPublish(ids);
return Result.OK("批量发布成功!");
}
@Operation(summary = "急救宣教资源-批量下架")
@AutoLog(value = "急救宣教资源-批量下架")
@PostMapping(value = "/batchTakeDown")
public Result<String> batchTakeDown(@RequestBody List<String> ids) {
resourceService.batchTakeDown(ids);
return Result.OK("批量下架成功!");
}
@Operation(summary = "急救宣教资源-提交审核")
@AutoLog(value = "急救宣教资源-提交审核")
@PostMapping(value = "/submitForReview")
public Result<String> 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<String> 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<String> 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<FirstAidResource> 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<String> 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<FirstAidResource> 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);
}
}
@@ -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<Map<String, Object>> 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<String, Object> result = new HashMap<>();
result.put("favorited", favorited);
return Result.OK(favorited ? "收藏成功" : "已取消收藏", result);
}
/**
* 判断是否已收藏
*/
@Operation(summary = "判断收藏状态", description = "查询当前用户是否已收藏该资源")
@GetMapping(value = "/isFavorited")
public Result<Map<String, Object>> 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<String, Object> result = new HashMap<>();
result.put("favorited", favorited);
return Result.OK(result);
}
/**
* 我的收藏列表
*/
@Operation(summary = "我的收藏列表", description = "查询当前用户的收藏资源列表")
@GetMapping(value = "/myList")
public Result<IPage<FirstAidResource>> myList(@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
String userId = GlobalUtils.getLoginUser().getId();
Page<FirstAidResource> page = new Page<>(pageNo, pageSize);
IPage<FirstAidResource> pageList = userActionService.getMyFavoritePage(page, userId);
return Result.OK(pageList);
}
}
@@ -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<FirstAidResourceCategory, IFirstAidResourceCategoryService> {
@Autowired
private IFirstAidResourceCategoryService categoryService;
@Operation(summary = "急救宣教资源标签-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<FirstAidResourceCategory>> 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<FirstAidResourceCategory> queryWrapper = QueryGenerator.initQueryWrapper(entity, req.getParameterMap());
Page<FirstAidResourceCategory> page = new Page<>(pageNo, pageSize);
return Result.OK(categoryService.page(page, queryWrapper));
}
@Operation(summary = "急救宣教资源标签-全部列表")
@GetMapping(value = "/listAll")
public Result<List<FirstAidResourceCategory>> listAll() {
return Result.OK(categoryService.listTags());
}
@Operation(summary = "急救宣教资源标签-添加")
@AutoLog(value = "急救宣教资源标签-添加")
//@RequiresPermissions("emergency:firstAidTag:add")
@PostMapping(value = "/add")
public Result<String> 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<String> 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<String> 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<String> deleteBatch(@RequestBody List<String> 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<FirstAidResourceCategory> 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);
}
}
@@ -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<FirstAidResourceVersion>> list(@RequestParam(name = "resourceId", required = true) String resourceId) {
List<FirstAidResourceVersion> list = versionService.listVersions(resourceId);
return Result.OK(list);
}
/**
* 回滚到指定版本
*/
@AutoLog(value = "急救宣教资源-版本回滚")
//@RequiresPermissions("emergency:firstAidResource:edit")
@Operation(summary = "回滚到指定版本", description = "将指定版本的内容恢复到资源表")
@PostMapping(value = "/rollback")
public Result<String> 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<Map<String, Object>> 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<String, Object> result = new HashMap<>();
result.put("version1", v1);
result.put("version2", v2);
return Result.OK(result);
}
}
@@ -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<FirstAidResourceCategory> {
/**
* 查询某分类下的子分类数量(级联删除校验用)
*/
@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<FirstAidResourceCategory> 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<FirstAidResourceCategory> 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<FirstAidResourceCategory> selectRootCategories();
}
@@ -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<FirstAidResource> {
/**
* 查询某分类下的资源数量(级联删除校验用)
*/
@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);
}
@@ -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<FirstAidResourceUserAction> {
/**
* 查询用户对一批资源的收藏状态
*/
@Select("<script>" +
"SELECT RESOURCE_ID FROM QH_EME_FIRST_AID_RESOURCE_USER_ACTION " +
"WHERE USER_ID = #{userId} AND TYPE = 2 " +
"AND RESOURCE_ID IN " +
"<foreach collection='resourceIds' item='id' open='(' separator=',' close=')'>" +
"#{id}" +
"</foreach>" +
"</script>")
List<String> selectFavoritedResourceIds(@Param("userId") String userId,
@Param("resourceIds") List<String> 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<FirstAidResource> selectFavoritePage(Page<FirstAidResource> page, @Param("userId") String userId);
}
@@ -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<FirstAidResourceVersion> {
/**
* 查询某资源的最高版本号
*/
@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<FirstAidResourceVersion> selectByResourceId(@Param("resourceId") String resourceId);
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.renkang.emergency.mapper.FirstAidResourceCategoryMapper">
</mapper>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.renkang.emergency.mapper.FirstAidResourceMapper">
</mapper>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.renkang.emergency.mapper.FirstAidResourceUserActionMapper">
</mapper>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.renkang.emergency.mapper.FirstAidResourceVersionMapper">
</mapper>
@@ -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<FirstAidResourceCategory> {
/**
* 查询所有有效分类(根分类+子分类)
*/
List<FirstAidResourceCategory> listCategories();
/**
* 查询根分类列表(树形结构顶层)
*/
List<FirstAidResourceCategory> listRootCategories();
/**
* 按父分类ID查询子分类
*/
List<FirstAidResourceCategory> listChildrenByParentId(String parentId);
/**
* 查询所有有效标签列表
*/
List<FirstAidResourceCategory> listTags();
/**
* 删除前校验(分类下有子分类/资源则拒绝;标签有资源引用则拒绝)
*/
void deleteWithCheck(String id);
}
@@ -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<FirstAidResource> {
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<String> ids);
/** 批量下架 */
void batchTakeDown(List<String> ids);
IPage<FirstAidResource> queryPageList(FirstAidResource resource, Page<FirstAidResource> page, String userId);
/** 审核记录分页列表(支持时间范围筛选) */
IPage<FirstAidResource> queryAuditRecords(FirstAidResource resource, Page<FirstAidResource> page, String startDate, String endDate);
boolean incrementViewCount(String id, String userId);
FirstAidResource getDetail(String id, String userId);
}
@@ -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<FirstAidResourceUserAction> {
/**
* 记录阅读行为(去重,已读则忽略)
*
* @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<String> getFavoritedResourceIds(String userId, List<String> resourceIds);
/**
* 我的收藏分页列表
*/
IPage<FirstAidResource> getMyFavoritePage(Page<FirstAidResource> page, String userId);
}
@@ -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<FirstAidResourceVersion> {
/**
* 保存版本快照
*/
void saveVersion(String resourceId, String title, String content, String changeDescription);
/**
* 查询某资源的所有版本
*/
List<FirstAidResourceVersion> listVersions(String resourceId);
/**
* 回滚到指定版本(将版本内容恢复到资源表)
*/
void rollback(String versionId);
}
@@ -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<FirstAidResourceCategoryMapper, FirstAidResourceCategory> implements IFirstAidResourceCategoryService {
@Autowired
private FirstAidResourceCategoryMapper categoryMapper;
@Autowired
private FirstAidResourceMapper resourceMapper;
@Override
public List<FirstAidResourceCategory> listCategories() {
List<FirstAidResourceCategory> list = categoryMapper.selectByType(FirstAidConstants.TYPE_CATEGORY);
fillResourceCounts(list);
return list;
}
@Override
public List<FirstAidResourceCategory> listRootCategories() {
List<FirstAidResourceCategory> list = categoryMapper.selectRootCategories();
fillResourceCounts(list);
return list;
}
@Override
public List<FirstAidResourceCategory> listChildrenByParentId(String parentId) {
List<FirstAidResourceCategory> list = categoryMapper.selectChildrenByParentId(parentId);
fillResourceCounts(list);
return list;
}
@Override
public List<FirstAidResourceCategory> listTags() {
List<FirstAidResourceCategory> 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<FirstAidResourceCategory> 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);
}
}
@@ -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<FirstAidResourceMapper, FirstAidResource> 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<String> 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<String> ids) {
for (String id : ids) {
FirstAidResource resource = getById(id);
if (resource != null) {
resource.setStatus(FirstAidConstants.STATUS_DOWN);
updateById(resource);
}
}
}
@Override
public IPage<FirstAidResource> queryPageList(FirstAidResource resource, Page<FirstAidResource> page, String userId) {
LambdaQueryWrapper<FirstAidResource> 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<FirstAidResource> result = page(page, queryWrapper);
fillResourceExtras(result.getRecords(), userId);
return result;
}
@Override
public IPage<FirstAidResource> queryAuditRecords(FirstAidResource resource, Page<FirstAidResource> page, String startDate, String endDate) {
LambdaQueryWrapper<FirstAidResource> 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<FirstAidResource> 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<FirstAidResource> resources, String userId) {
if (CollectionUtil.isEmpty(resources)) {
return;
}
List<String> resourceIds = resources.stream().map(FirstAidResource::getId).collect(Collectors.toList());
// 未登录用户无需查询收藏状态
List<String> 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<String> 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()));
}
}
}
@@ -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<FirstAidResourceUserActionMapper, FirstAidResourceUserAction> implements IFirstAidResourceUserActionService {
@Autowired
private FirstAidResourceUserActionMapper actionMapper;
@Autowired
private FirstAidResourceMapper resourceMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public boolean recordRead(String resourceId, String userId) {
// 检查是否已有阅读记录
LambdaQueryWrapper<FirstAidResourceUserAction> 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<FirstAidResourceUserAction> 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<FirstAidResourceUserAction> 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<String> getFavoritedResourceIds(String userId, List<String> resourceIds) {
if (CollectionUtil.isEmpty(resourceIds)) {
return Collections.emptyList();
}
return actionMapper.selectFavoritedResourceIds(userId, resourceIds);
}
@Override
public IPage<FirstAidResource> getMyFavoritePage(Page<FirstAidResource> page, String userId) {
return actionMapper.selectFavoritePage(page, userId);
}
}
@@ -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<FirstAidResourceVersionMapper, FirstAidResourceVersion> 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<FirstAidResourceVersion> 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);
}
}
@@ -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);
@@ -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;
@@ -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;