feat(cms): 新增多图轮播组及轮播项管理功能
- 新增轮播组及轮播项实体定义,支持组内多图轮播配置 - 实现轮播组包含轮播项的分页、查询、详情接口,支持一并返回组内items - 支持轮播组的新增、修改(含全量替换items)、删除操作,确保组及items数据一致 - 提供轮播组状态启用/停用修改接口 - 提供轮播项的单独新增、修改、删除接口,支持组内单项维护 - 实现轮播组和轮播项Mapper及Service层逻辑,含批量查询与保存items的功能 - 新增对应数据库表结构及索引,支持多图轮播组及轮播项数据存储 - 接口编写包含Swagger注解,完善API文档描述
This commit is contained in:
@@ -0,0 +1,153 @@
|
|||||||
|
package com.gxwebsoft.cms.controller;
|
||||||
|
|
||||||
|
import com.gxwebsoft.cms.entity.CmsBannerGroup;
|
||||||
|
import com.gxwebsoft.cms.entity.CmsBannerItem;
|
||||||
|
import com.gxwebsoft.cms.mapper.CmsBannerItemMapper;
|
||||||
|
import com.gxwebsoft.cms.param.CmsBannerGroupParam;
|
||||||
|
import com.gxwebsoft.cms.service.CmsBannerGroupService;
|
||||||
|
import com.gxwebsoft.common.core.web.ApiResult;
|
||||||
|
import com.gxwebsoft.common.core.web.BaseController;
|
||||||
|
import com.gxwebsoft.common.core.web.PageResult;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 轮播组管理控制器
|
||||||
|
*
|
||||||
|
* @author WorkBuddy
|
||||||
|
* @since 2026-07-19
|
||||||
|
*/
|
||||||
|
@Tag(name = "轮播组管理")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/cms/cms-banner-group")
|
||||||
|
public class CmsBannerGroupController extends BaseController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CmsBannerGroupService cmsBannerGroupService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CmsBannerItemMapper cmsBannerItemMapper;
|
||||||
|
|
||||||
|
@Operation(summary = "分页查询轮播组(带组内items)")
|
||||||
|
@GetMapping("/page")
|
||||||
|
public ApiResult<PageResult<CmsBannerGroup>> page(CmsBannerGroupParam param) {
|
||||||
|
return success(cmsBannerGroupService.pageRel(param));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "查询全部轮播组(带组内items)")
|
||||||
|
@GetMapping()
|
||||||
|
public ApiResult<List<CmsBannerGroup>> list(CmsBannerGroupParam param) {
|
||||||
|
return success(cmsBannerGroupService.listRel(param));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "根据id查询轮播组(含组内items)")
|
||||||
|
@GetMapping("/{groupId}")
|
||||||
|
public ApiResult<CmsBannerGroup> get(@PathVariable("groupId") Integer groupId) {
|
||||||
|
CmsBannerGroup group = cmsBannerGroupService.getByIdRel(groupId);
|
||||||
|
if (group == null) {
|
||||||
|
return fail("轮播组不存在", group);
|
||||||
|
}
|
||||||
|
return success(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "添加轮播组(可携带items一次性创建)")
|
||||||
|
@PostMapping()
|
||||||
|
public ApiResult<?> save(@RequestBody CmsBannerGroup group) {
|
||||||
|
if (cmsBannerGroupService.saveGroup(group)) {
|
||||||
|
return success("添加成功");
|
||||||
|
}
|
||||||
|
return fail("添加失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "修改轮播组(可携带items一次性全量替换)")
|
||||||
|
@PutMapping()
|
||||||
|
public ApiResult<?> update(@RequestBody CmsBannerGroup group) {
|
||||||
|
if (group.getGroupId() == null) {
|
||||||
|
return fail("轮播组ID不能为空");
|
||||||
|
}
|
||||||
|
if (cmsBannerGroupService.updateGroup(group)) {
|
||||||
|
return success("修改成功");
|
||||||
|
}
|
||||||
|
return fail("修改失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "删除轮播组(连带删除组内items)")
|
||||||
|
@DeleteMapping("/{groupId}")
|
||||||
|
public ApiResult<?> remove(@PathVariable("groupId") Integer groupId) {
|
||||||
|
if (cmsBannerGroupService.removeGroup(groupId)) {
|
||||||
|
return success("删除成功");
|
||||||
|
}
|
||||||
|
return fail("删除失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "修改轮播组状态(启用/停用)")
|
||||||
|
@PutMapping("/status")
|
||||||
|
public ApiResult<?> updateStatus(@RequestBody CmsBannerGroup group) {
|
||||||
|
CmsBannerGroup entity = new CmsBannerGroup();
|
||||||
|
entity.setGroupId(group.getGroupId());
|
||||||
|
entity.setStatus(group.getStatus());
|
||||||
|
if (cmsBannerGroupService.updateById(entity)) {
|
||||||
|
return success("修改成功");
|
||||||
|
}
|
||||||
|
return fail("修改失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------- 单项 CRUD(可选,保存组时已全量提交items,以下接口用于单独维护) ----------------
|
||||||
|
|
||||||
|
@Operation(summary = "单独新增轮播项")
|
||||||
|
@PostMapping("/{groupId}/item")
|
||||||
|
public ApiResult<?> addItem(@PathVariable("groupId") Integer groupId,
|
||||||
|
@RequestBody CmsBannerItem item) {
|
||||||
|
item.setItemId(null);
|
||||||
|
item.setGroupId(groupId);
|
||||||
|
if (item.getLinkType() == null) {
|
||||||
|
item.setLinkType(0);
|
||||||
|
}
|
||||||
|
if (cmsBannerGroupService.getById(groupId) == null) {
|
||||||
|
return fail("轮播组不存在");
|
||||||
|
}
|
||||||
|
if (bannerItemInsert(item)) {
|
||||||
|
return success("添加成功");
|
||||||
|
}
|
||||||
|
return fail("添加失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "单独修改轮播项")
|
||||||
|
@PutMapping("/item")
|
||||||
|
public ApiResult<?> updateItem(@RequestBody CmsBannerItem item) {
|
||||||
|
if (item.getItemId() == null) {
|
||||||
|
return fail("轮播项ID不能为空");
|
||||||
|
}
|
||||||
|
if (bannerItemUpdate(item)) {
|
||||||
|
return success("修改成功");
|
||||||
|
}
|
||||||
|
return fail("修改失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "单独删除轮播项")
|
||||||
|
@DeleteMapping("/item/{itemId}")
|
||||||
|
public ApiResult<?> removeItem(@PathVariable("itemId") Integer itemId) {
|
||||||
|
if (bannerItemDelete(itemId)) {
|
||||||
|
return success("删除成功");
|
||||||
|
}
|
||||||
|
return fail("删除失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------- 单项CRUD依赖的mapper ----------------
|
||||||
|
|
||||||
|
private boolean bannerItemInsert(CmsBannerItem item) {
|
||||||
|
return cmsBannerItemMapper.insert(item) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean bannerItemUpdate(CmsBannerItem item) {
|
||||||
|
return cmsBannerItemMapper.updateById(item) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean bannerItemDelete(Integer itemId) {
|
||||||
|
return cmsBannerItemMapper.deleteById(itemId) > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
83
src/main/java/com/gxwebsoft/cms/entity/CmsBannerGroup.java
Normal file
83
src/main/java/com/gxwebsoft/cms/entity/CmsBannerGroup.java
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
package com.gxwebsoft.cms.entity;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 轮播组(多图轮播)
|
||||||
|
*
|
||||||
|
* @author WorkBuddy
|
||||||
|
* @since 2026-07-19
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@TableName("cms_banner_group")
|
||||||
|
@Schema(name = "CmsBannerGroup对象", description = "轮播组(多图轮播)")
|
||||||
|
public class CmsBannerGroup implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Schema(description = "轮播组ID")
|
||||||
|
@TableId(value = "group_id", type = IdType.AUTO)
|
||||||
|
private Integer groupId;
|
||||||
|
|
||||||
|
@Schema(description = "组标题(如:首页幻灯片)")
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@Schema(description = "展示位置标识(home_slider/home_promo/inner_page等)")
|
||||||
|
private String position;
|
||||||
|
|
||||||
|
@Schema(description = "状态: 1启用 0停用")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@Schema(description = "排序权重(越小越靠前)")
|
||||||
|
@JsonProperty("sortNum")
|
||||||
|
@JSONField(name = "sortNum")
|
||||||
|
private Integer sortNumber;
|
||||||
|
|
||||||
|
@Schema(description = "生效开始时间")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime startTime;
|
||||||
|
|
||||||
|
@Schema(description = "生效结束时间")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime endTime;
|
||||||
|
|
||||||
|
@Schema(description = "备注")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
@Schema(description = "是否删除: 0否 1是")
|
||||||
|
@TableLogic
|
||||||
|
private Integer deleted;
|
||||||
|
|
||||||
|
@Schema(description = "租户id")
|
||||||
|
private Integer tenantId;
|
||||||
|
|
||||||
|
@Schema(description = "创建时间")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
@Schema(description = "更新时间")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组内轮播项(非数据库字段)
|
||||||
|
* 列表/详情查询时返回
|
||||||
|
*/
|
||||||
|
@Schema(description = "组内轮播项")
|
||||||
|
@TableField(exist = false)
|
||||||
|
private List<CmsBannerItem> items;
|
||||||
|
}
|
||||||
71
src/main/java/com/gxwebsoft/cms/entity/CmsBannerItem.java
Normal file
71
src/main/java/com/gxwebsoft/cms/entity/CmsBannerItem.java
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
package com.gxwebsoft.cms.entity;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 轮播项(组内单张图)
|
||||||
|
*
|
||||||
|
* @author WorkBuddy
|
||||||
|
* @since 2026-07-19
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@TableName("cms_banner_item")
|
||||||
|
@Schema(name = "CmsBannerItem对象", description = "轮播项(组内单张图)")
|
||||||
|
public class CmsBannerItem implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Schema(description = "轮播项ID")
|
||||||
|
@TableId(value = "item_id", type = IdType.AUTO)
|
||||||
|
private Integer itemId;
|
||||||
|
|
||||||
|
@Schema(description = "所属轮播组ID")
|
||||||
|
private Integer groupId;
|
||||||
|
|
||||||
|
@Schema(description = "图片地址")
|
||||||
|
private String image;
|
||||||
|
|
||||||
|
@Schema(description = "单图标题(alt/无障碍)")
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@Schema(description = "跳转类型: 0无 1外链 2文章 3产品")
|
||||||
|
private Integer linkType;
|
||||||
|
|
||||||
|
@Schema(description = "外链地址")
|
||||||
|
private String linkUrl;
|
||||||
|
|
||||||
|
@Schema(description = "跳转目标ID(文章/产品)")
|
||||||
|
private Integer linkTargetId;
|
||||||
|
|
||||||
|
@Schema(description = "组内排序(越小越靠前)")
|
||||||
|
@JsonProperty("sortNum")
|
||||||
|
@JSONField(name = "sortNum")
|
||||||
|
private Integer sortNumber;
|
||||||
|
|
||||||
|
@Schema(description = "是否删除: 0否 1是")
|
||||||
|
@TableLogic
|
||||||
|
private Integer deleted;
|
||||||
|
|
||||||
|
@Schema(description = "租户id")
|
||||||
|
private Integer tenantId;
|
||||||
|
|
||||||
|
@Schema(description = "创建时间")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
@Schema(description = "更新时间")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.gxwebsoft.cms.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.gxwebsoft.cms.entity.CmsBannerGroup;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 轮播组Mapper
|
||||||
|
*
|
||||||
|
* @author WorkBuddy
|
||||||
|
* @since 2026-07-19
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface CmsBannerGroupMapper extends BaseMapper<CmsBannerGroup> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.gxwebsoft.cms.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.gxwebsoft.cms.entity.CmsBannerItem;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 轮播项Mapper
|
||||||
|
*
|
||||||
|
* @author WorkBuddy
|
||||||
|
* @since 2026-07-19
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface CmsBannerItemMapper extends BaseMapper<CmsBannerItem> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package com.gxwebsoft.cms.param;
|
||||||
|
|
||||||
|
import com.gxwebsoft.common.core.annotation.QueryField;
|
||||||
|
import com.gxwebsoft.common.core.annotation.QueryType;
|
||||||
|
import com.gxwebsoft.common.core.web.BaseParam;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 轮播组查询参数
|
||||||
|
*
|
||||||
|
* @author WorkBuddy
|
||||||
|
* @since 2026-07-19
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Schema(name = "CmsBannerGroupParam对象", description = "轮播组查询参数")
|
||||||
|
public class CmsBannerGroupParam extends BaseParam {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Schema(description = "轮播组ID")
|
||||||
|
@QueryField(type = QueryType.EQ)
|
||||||
|
private Integer groupId;
|
||||||
|
|
||||||
|
@Schema(description = "组标题")
|
||||||
|
@QueryField(type = QueryType.LIKE)
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@Schema(description = "展示位置标识")
|
||||||
|
@QueryField(type = QueryType.EQ)
|
||||||
|
private String position;
|
||||||
|
|
||||||
|
@Schema(description = "状态: 1启用 0停用")
|
||||||
|
@QueryField(type = QueryType.EQ)
|
||||||
|
private Integer status;
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package com.gxwebsoft.cms.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.gxwebsoft.cms.entity.CmsBannerGroup;
|
||||||
|
import com.gxwebsoft.cms.param.CmsBannerGroupParam;
|
||||||
|
import com.gxwebsoft.common.core.web.PageResult;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 轮播组Service接口
|
||||||
|
*
|
||||||
|
* @author WorkBuddy
|
||||||
|
* @since 2026-07-19
|
||||||
|
*/
|
||||||
|
public interface CmsBannerGroupService extends IService<CmsBannerGroup> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询(带组内items)
|
||||||
|
*
|
||||||
|
* @param param 查询参数
|
||||||
|
* @return 分页结果
|
||||||
|
*/
|
||||||
|
PageResult<CmsBannerGroup> pageRel(CmsBannerGroupParam param);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询全部(带组内items)
|
||||||
|
*
|
||||||
|
* @param param 查询参数
|
||||||
|
* @return 列表
|
||||||
|
*/
|
||||||
|
List<CmsBannerGroup> listRel(CmsBannerGroupParam param);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据id查询(带组内items)
|
||||||
|
*
|
||||||
|
* @param groupId 轮播组ID
|
||||||
|
* @return 轮播组
|
||||||
|
*/
|
||||||
|
CmsBannerGroup getByIdRel(Integer groupId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存轮播组(可携带items一次性创建)
|
||||||
|
*
|
||||||
|
* @param group 轮播组(含items)
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean saveGroup(CmsBannerGroup group);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新轮播组(可携带items一次性全量替换)
|
||||||
|
*
|
||||||
|
* @param group 轮播组(含items)
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean updateGroup(CmsBannerGroup group);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除轮播组(连带删除组内items)
|
||||||
|
*
|
||||||
|
* @param groupId 轮播组ID
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean removeGroup(Integer groupId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,175 @@
|
|||||||
|
package com.gxwebsoft.cms.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.gxwebsoft.cms.entity.CmsBannerGroup;
|
||||||
|
import com.gxwebsoft.cms.entity.CmsBannerItem;
|
||||||
|
import com.gxwebsoft.cms.mapper.CmsBannerGroupMapper;
|
||||||
|
import com.gxwebsoft.cms.mapper.CmsBannerItemMapper;
|
||||||
|
import com.gxwebsoft.cms.param.CmsBannerGroupParam;
|
||||||
|
import com.gxwebsoft.cms.service.CmsBannerGroupService;
|
||||||
|
import com.gxwebsoft.common.core.web.PageParam;
|
||||||
|
import com.gxwebsoft.common.core.web.PageResult;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 轮播组Service实现
|
||||||
|
*
|
||||||
|
* @author WorkBuddy
|
||||||
|
* @since 2026-07-19
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class CmsBannerGroupServiceImpl extends ServiceImpl<CmsBannerGroupMapper, CmsBannerGroup> implements CmsBannerGroupService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CmsBannerItemMapper bannerItemMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<CmsBannerGroup> pageRel(CmsBannerGroupParam param) {
|
||||||
|
PageParam<CmsBannerGroup, CmsBannerGroupParam> page = new PageParam<>(param);
|
||||||
|
page.setDefaultOrder("sort_number asc, create_time desc");
|
||||||
|
IPage<CmsBannerGroup> result = page(page, page.getOrderWrapper());
|
||||||
|
List<CmsBannerGroup> records = result.getRecords();
|
||||||
|
// 批量填充 items
|
||||||
|
fillItems(records);
|
||||||
|
return new PageResult<>(records, result.getTotal());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CmsBannerGroup> listRel(CmsBannerGroupParam param) {
|
||||||
|
PageParam<CmsBannerGroup, CmsBannerGroupParam> page = new PageParam<>(param);
|
||||||
|
page.setDefaultOrder("sort_number asc, create_time desc");
|
||||||
|
List<CmsBannerGroup> records = list(page.getOrderWrapper());
|
||||||
|
fillItems(records);
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CmsBannerGroup getByIdRel(Integer groupId) {
|
||||||
|
CmsBannerGroup group = getById(groupId);
|
||||||
|
if (group == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<CmsBannerItem> items = listItemsByGroupId(groupId);
|
||||||
|
group.setItems(items);
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean saveGroup(CmsBannerGroup group) {
|
||||||
|
// 先保存组
|
||||||
|
boolean ok = save(group);
|
||||||
|
if (!ok) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 再保存组内items
|
||||||
|
saveItems(group.getGroupId(), group.getItems());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean updateGroup(CmsBannerGroup group) {
|
||||||
|
// 更新组主信息
|
||||||
|
boolean ok = updateById(group);
|
||||||
|
if (!ok) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Integer groupId = group.getGroupId();
|
||||||
|
// 全量替换items: 先删除旧items, 再插入新items
|
||||||
|
if (group.getItems() != null) {
|
||||||
|
bannerItemMapper.delete(new LambdaQueryWrapper<CmsBannerItem>()
|
||||||
|
.eq(CmsBannerItem::getGroupId, groupId));
|
||||||
|
saveItems(groupId, group.getItems());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean removeGroup(Integer groupId) {
|
||||||
|
// 逻辑删除组
|
||||||
|
boolean ok = removeById(groupId);
|
||||||
|
if (!ok) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 逻辑删除组内items
|
||||||
|
bannerItemMapper.delete(new LambdaQueryWrapper<CmsBannerItem>()
|
||||||
|
.eq(CmsBannerItem::getGroupId, groupId));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------- private -----------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询某个组下的所有轮播项(按sort_number升序)
|
||||||
|
*/
|
||||||
|
private List<CmsBannerItem> listItemsByGroupId(Integer groupId) {
|
||||||
|
if (groupId == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return bannerItemMapper.selectList(new LambdaQueryWrapper<CmsBannerItem>()
|
||||||
|
.eq(CmsBannerItem::getGroupId, groupId)
|
||||||
|
.orderByAsc(CmsBannerItem::getSortNumber));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量查询多个组的items并按group分组
|
||||||
|
*/
|
||||||
|
private Map<Integer, List<CmsBannerItem>> listItemsByGroupIds(List<Integer> groupIds) {
|
||||||
|
if (groupIds == null || groupIds.isEmpty()) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
List<CmsBannerItem> allItems = bannerItemMapper.selectList(new LambdaQueryWrapper<CmsBannerItem>()
|
||||||
|
.in(CmsBannerItem::getGroupId, groupIds)
|
||||||
|
.orderByAsc(CmsBannerItem::getSortNumber));
|
||||||
|
return allItems.stream().collect(Collectors.groupingBy(CmsBannerItem::getGroupId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量给group列表填充items
|
||||||
|
*/
|
||||||
|
private void fillItems(List<CmsBannerGroup> records) {
|
||||||
|
if (records == null || records.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<Integer> groupIds = records.stream()
|
||||||
|
.map(CmsBannerGroup::getGroupId)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
Map<Integer, List<CmsBannerItem>> itemsMap = listItemsByGroupIds(groupIds);
|
||||||
|
for (CmsBannerGroup g : records) {
|
||||||
|
g.setItems(itemsMap.getOrDefault(g.getGroupId(), new ArrayList<>()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量保存组内items
|
||||||
|
*/
|
||||||
|
private void saveItems(Integer groupId, List<CmsBannerItem> items) {
|
||||||
|
if (groupId == null || items == null || items.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < items.size(); i++) {
|
||||||
|
CmsBannerItem item = items.get(i);
|
||||||
|
item.setItemId(null); // 新增时清除前端可能传入的ID
|
||||||
|
item.setGroupId(groupId);
|
||||||
|
if (item.getSortNumber() == null) {
|
||||||
|
item.setSortNumber(i);
|
||||||
|
}
|
||||||
|
if (item.getLinkType() == null) {
|
||||||
|
item.setLinkType(0);
|
||||||
|
}
|
||||||
|
bannerItemMapper.insert(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
45
src/main/java/com/gxwebsoft/cms/sql/cms_banner_group.sql
Normal file
45
src/main/java/com/gxwebsoft/cms/sql/cms_banner_group.sql
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
-- ----------------------------
|
||||||
|
-- 轮播组表
|
||||||
|
-- 一个轮播组对应一组多图轮播(如首页幻灯片)
|
||||||
|
-- 与 cms_banner(旧版单图) 并存,互不影响
|
||||||
|
-- ----------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS `cms_banner_group` (
|
||||||
|
`group_id` INT NOT NULL AUTO_INCREMENT COMMENT '轮播组ID',
|
||||||
|
`title` VARCHAR(120) NOT NULL COMMENT '组标题(如:首页幻灯片)',
|
||||||
|
`position` VARCHAR(60) NOT NULL DEFAULT 'home_slider' COMMENT '展示位置标识(home_slider/home_promo/inner_page等)',
|
||||||
|
`status` TINYINT NOT NULL DEFAULT 1 COMMENT '状态: 1启用 0停用',
|
||||||
|
`sort_number` INT NOT NULL DEFAULT 0 COMMENT '排序权重(越小越靠前)',
|
||||||
|
`start_time` DATETIME DEFAULT NULL COMMENT '生效开始时间',
|
||||||
|
`end_time` DATETIME DEFAULT NULL COMMENT '生效结束时间',
|
||||||
|
`remark` VARCHAR(255) DEFAULT NULL COMMENT '备注',
|
||||||
|
`deleted` TINYINT NOT NULL DEFAULT 0 COMMENT '是否删除: 0否 1是',
|
||||||
|
`tenant_id` INT DEFAULT NULL COMMENT '租户ID',
|
||||||
|
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`group_id`),
|
||||||
|
KEY `idx_position` (`position`),
|
||||||
|
KEY `idx_status` (`status`),
|
||||||
|
KEY `idx_tenant_id` (`tenant_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='轮播组(多图轮播)';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 轮播项表
|
||||||
|
-- 组内单张图片及其跳转配置
|
||||||
|
-- ----------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS `cms_banner_item` (
|
||||||
|
`item_id` INT NOT NULL AUTO_INCREMENT COMMENT '轮播项ID',
|
||||||
|
`group_id` INT NOT NULL COMMENT '所属轮播组ID',
|
||||||
|
`image` VARCHAR(500) NOT NULL COMMENT '图片地址',
|
||||||
|
`title` VARCHAR(120) DEFAULT NULL COMMENT '单图标题(alt/无障碍)',
|
||||||
|
`link_type` TINYINT NOT NULL DEFAULT 0 COMMENT '跳转类型: 0无 1外链 2文章 3产品',
|
||||||
|
`link_url` VARCHAR(500) DEFAULT NULL COMMENT '外链地址',
|
||||||
|
`link_target_id` INT DEFAULT NULL COMMENT '跳转目标ID(文章/产品)',
|
||||||
|
`sort_number` INT NOT NULL DEFAULT 0 COMMENT '组内排序(越小越靠前)',
|
||||||
|
`deleted` TINYINT NOT NULL DEFAULT 0 COMMENT '是否删除: 0否 1是',
|
||||||
|
`tenant_id` INT DEFAULT NULL COMMENT '租户ID',
|
||||||
|
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`item_id`),
|
||||||
|
KEY `idx_group_id` (`group_id`),
|
||||||
|
KEY `idx_tenant_id` (`tenant_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='轮播项(组内单张图)';
|
||||||
Reference in New Issue
Block a user