增加活动轮播图的API

This commit is contained in:
Wang 2026-01-30 16:18:14 +08:00
parent 98217a5cfe
commit 527743b322
20 changed files with 899 additions and 17 deletions

View File

@ -0,0 +1,215 @@
# 活动轮播图功能接口文档
本文档详细描述了活动轮播图功能的所有接口。
## 1. 管理端接口
### 1.1 获取活动轮播图列表
- **接口路径**: `POST /seer/admin/mp/activity-carousel/page-list`
- **功能描述**: 分页获取活动轮播图列表
- **权限要求**: `mp:admin:activity:carousel:list`
- **请求参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| activityId | Integer | 否 | 活动ID |
| isActive | Boolean | 否 | 激活状态 |
| title | String | 否 | 标题 |
| pageNum | Integer | 是 | 页码 |
| pageSize | Integer | 是 | 每页数量 |
- **请求示例**:
```json
{
"activityId": 1,
"isActive": true,
"title": "轮播图",
"pageNum": 1,
"pageSize": 10
}
```
- **响应示例**:
```json
{
"code": 200,
"message": "success",
"data": {
"total": 1,
"list": [
{
"id": 1,
"imageUrl": "https://example.com/image.jpg",
"linkUrl": "https://example.com/link",
"title": "轮播图标题",
"description": "轮播图描述",
"sortOrder": 1,
"isActive": true,
"activityId": 1,
"createTime": "2026-01-30 10:00:00",
"updateTime": "2026-01-30 10:00:00"
}
]
}
}
```
### 1.2 创建或更新活动轮播图
- **接口路径**: `POST /seer/admin/mp/activity-carousel/save`
- **功能描述**: 创建或更新活动轮播图
- **权限要求**: `mp:admin:activity:carousel:save`
- **请求参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| id | Integer | 否 | 轮播图ID不传表示新增 |
| imageUrl | String | 是 | 图片地址 |
| linkUrl | String | 否 | 跳转链接 |
| title | String | 否 | 标题 |
| description | String | 否 | 描述/替代文本 |
| sortOrder | Integer | 是 | 排序值 |
| isActive | Boolean | 是 | 激活状态true-显示false-隐藏 |
| activityId | Integer | 是 | 关联活动ID |
- **请求示例**:
```json
{
"imageUrl": "https://example.com/image.jpg",
"linkUrl": "https://example.com/link",
"title": "轮播图标题",
"description": "轮播图描述",
"sortOrder": 1,
"isActive": true,
"activityId": 1
}
```
- **响应示例**:
```json
{
"code": 200,
"message": "success",
"data": true
}
```
### 1.3 删除活动轮播图
- **接口路径**: `DELETE /seer/admin/mp/activity-carousel/{id}`
- **功能描述**: 删除指定ID的活动轮播图
- **权限要求**: `mp:admin:activity:carousel:delete`
- **路径参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| id | Integer | 是 | 轮播图ID |
- **响应示例**:
```json
{
"code": 200,
"message": "success",
"data": true
}
```
### 1.4 获取活动轮播图详情
- **接口路径**: `GET /seer/admin/mp/activity-carousel/{id}`
- **功能描述**: 获取指定ID的活动轮播图详情
- **权限要求**: `mp:admin:activity:carousel:get`
- **路径参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| id | Integer | 是 | 轮播图ID |
- **响应示例**:
```json
{
"code": 200,
"message": "success",
"data": {
"id": 1,
"imageUrl": "https://example.com/image.jpg",
"linkUrl": "https://example.com/link",
"title": "轮播图标题",
"description": "轮播图描述",
"sortOrder": 1,
"isActive": true,
"activityId": 1,
"createTime": "2026-01-30 10:00:00",
"updateTime": "2026-01-30 10:00:00"
}
}
```
### 1.5 根据活动ID获取轮播图列表
- **接口路径**: `GET /seer/admin/mp/activity-carousel/activity/{activityId}`
- **功能描述**: 根据活动ID获取轮播图列表
- **权限要求**: `mp:admin:activity:carousel:list`
- **路径参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| activityId | Integer | 是 | 活动ID |
- **响应示例**:
```json
{
"code": 200,
"message": "success",
"data": [
{
"id": 1,
"imageUrl": "https://example.com/image.jpg",
"linkUrl": "https://example.com/link",
"title": "轮播图标题",
"description": "轮播图描述",
"sortOrder": 1,
"isActive": true,
"activityId": 1,
"createTime": "2026-01-30 10:00:00",
"updateTime": "2026-01-30 10:00:00"
}
]
}
```
## 2. 应用端接口
### 2.1 根据活动ID获取激活的轮播图列表
- **接口路径**: `GET /seer/admin/mp/app/activity-carousel/activity/{activityId}`
- **功能描述**: 根据活动ID获取激活的轮播图列表仅返回激活状态为true的轮播图并按排序值升序排列
- **请求参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| activityId | Integer | 是 | 活动ID |
- **响应示例**:
```json
{
"code": 200,
"message": "success",
"data": [
{
"id": 1,
"imageUrl": "https://example.com/image.jpg",
"linkUrl": "https://example.com/link",
"title": "轮播图标题",
"description": "轮播图描述",
"sortOrder": 1,
"isActive": true,
"activityId": 1,
"createTime": "2026-01-30 10:00:00",
"updateTime": "2026-01-30 10:00:00"
}
]
}
```

View File

@ -0,0 +1,38 @@
package com.seer.teach.mp.api.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
/**
* 活动轮播图数据传输对象
*/
@Data
@Schema(name = "MpActivityCarouselDTO", description = "活动轮播图数据传输对象")
public class MpActivityCarouselDTO implements Serializable {
@Schema(description = "轮播图ID")
private Integer id;
@Schema(description = "图片地址")
private String imageUrl;
@Schema(description = "跳转链接")
private String linkUrl;
@Schema(description = "标题")
private String title;
@Schema(description = "描述/替代文本")
private String description;
@Schema(description = "排序值")
private Integer sortOrder;
@Schema(description = "激活状态1-显示0-隐藏")
private Boolean isActive;
@Schema(description = "关联活动ID")
private Integer activityId;
}

View File

@ -0,0 +1,65 @@
package com.seer.teach.mp.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.seer.teach.common.entity.BaseEntity;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
/**
* <p>
* 活动轮播图表
* </p>
*
* @author Lingma
* @since 2026-01-30
*/
@Getter
@Setter
@TableName("mp_activity_carousel")
@Schema(name = "MpActivityCarouselEntity", description = "活动轮播图表")
public class MpActivityCarouselEntity extends BaseEntity {
/**
* 图片地址
*/
@TableField("image_url")
private String imageUrl;
/**
* 跳转链接
*/
@TableField("link_url")
private String linkUrl;
/**
* 标题
*/
@TableField("title")
private String title;
/**
* 描述/替代文本
*/
@TableField("description")
private String description;
/**
* 排序值
*/
@TableField("sort_order")
private Integer sortOrder;
/**
* 激活状态1-显示0-隐藏
*/
@TableField("is_active")
private Boolean isActive;
/**
* 关联活动ID
*/
@TableField("activity_id")
private Integer activityId;
}

View File

@ -0,0 +1,18 @@
package com.seer.teach.mp.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.seer.teach.mp.entity.MpActivityCarouselEntity;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* 活动轮播图 Mapper 接口
* </p>
*
* @author Lingma
* @since 2026-01-30
*/
@Mapper
public interface MpActivityCarouselMapper extends BaseMapper<MpActivityCarouselEntity> {
}

View File

@ -0,0 +1,70 @@
package com.seer.teach.mp.admin.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.seer.teach.common.PageListBean;
import com.seer.teach.common.ResultBean;
import com.seer.teach.common.annotation.LogPrint;
import com.seer.teach.mp.admin.controller.req.MpActivityCarouselQueryReq;
import com.seer.teach.mp.admin.controller.req.MpActivityCarouselReq;
import com.seer.teach.mp.admin.controller.resp.AdminActivityCarouselResp;
import com.seer.teach.mp.admin.service.IAdminActivityCarouselService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@LogPrint
@RequiredArgsConstructor
@RestController
@Tag(name = "管理端 - 活动轮播图")
@RequestMapping("/mp/activity-carousel")
public class AdminActivityCarouselController {
private final IAdminActivityCarouselService adminActivityCarouselService;
@Operation(summary = "活动轮播图列表")
@PostMapping("/page-list")
@SaCheckPermission("mp:admin:activity:carousel:list")
public ResultBean<PageListBean<AdminActivityCarouselResp>> pageList(@RequestBody @Validated MpActivityCarouselQueryReq query) {
return ResultBean.success(adminActivityCarouselService.pageList(query));
}
@Operation(summary = "创建或更新活动轮播图")
@PostMapping("/save")
@SaCheckPermission("mp:admin:activity:carousel:save")
public ResultBean<Boolean> save(@Valid @RequestBody MpActivityCarouselReq request) {
return ResultBean.success(adminActivityCarouselService.saveOrUpdateCarousel(request));
}
@Operation(summary = "删除活动轮播图")
@DeleteMapping("/{id}")
@SaCheckPermission("mp:admin:activity:carousel:delete")
public ResultBean<Boolean> delete(@PathVariable("id") Integer id) {
return ResultBean.success(adminActivityCarouselService.deleteCarousel(id));
}
@Operation(summary = "详情")
@GetMapping("/{id}")
@SaCheckPermission("mp:admin:activity:carousel:get")
public ResultBean<AdminActivityCarouselResp> get(@PathVariable("id") Integer id) {
AdminActivityCarouselResp result = adminActivityCarouselService.getById(id);
return ResultBean.success(result);
}
@Operation(summary = "根据活动ID获取轮播图列表")
@GetMapping("/activity/{activityId}")
@SaCheckPermission("mp:admin:activity:carousel:list")
public ResultBean<List<AdminActivityCarouselResp>> getByActivityId(@PathVariable("activityId") Integer activityId) {
return ResultBean.success(adminActivityCarouselService.getByActivityId(activityId));
}
}

View File

@ -0,0 +1,17 @@
package com.seer.teach.mp.admin.controller.req;
import com.seer.teach.common.request.PageRequest;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 活动轮播图请求参数
*/
@Data
@Schema(name = "MpActivityCarouselReq", description = "活动轮播图请求参数")
public class MpActivityCarouselQueryReq extends PageRequest {
@Schema(description = "激活状态1-显示0-隐藏")
private Boolean isActive;
}

View File

@ -0,0 +1,43 @@
package com.seer.teach.mp.admin.controller.req;
import com.seer.teach.common.request.PageRequest;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
/**
* 活动轮播图请求参数
*/
@Data
@Schema(name = "MpActivityCarouselReq", description = "活动轮播图请求参数")
public class MpActivityCarouselReq {
@Schema(description = "轮播图ID")
private Integer id;
@NotBlank(message = "图片地址不能为空")
@Schema(description = "图片地址")
private String imageUrl;
@Schema(description = "跳转链接")
private String linkUrl;
@Schema(description = "标题")
private String title;
@Schema(description = "描述/替代文本")
private String description;
@NotNull(message = "排序值不能为空")
@Schema(description = "排序值")
private Integer sortOrder;
@NotNull(message = "激活状态不能为空")
@Schema(description = "激活状态1-显示0-隐藏")
private Boolean isActive;
@NotNull(message = "关联活动ID不能为空")
@Schema(description = "关联活动ID")
private Integer activityId;
}

View File

@ -0,0 +1,42 @@
package com.seer.teach.mp.admin.controller.resp;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 活动轮播图响应参数
*/
@Data
@Schema(name = "AdminActivityCarouselResp", description = "活动轮播图响应参数")
public class AdminActivityCarouselResp {
@Schema(description = "轮播图ID")
private Integer id;
@Schema(description = "图片地址")
private String imageUrl;
@Schema(description = "跳转链接")
private String linkUrl;
@Schema(description = "标题")
private String title;
@Schema(description = "描述/替代文本")
private String description;
@Schema(description = "排序值")
private Integer sortOrder;
@Schema(description = "激活状态1-显示0-隐藏")
private Boolean isActive;
@Schema(description = "关联活动ID")
private Integer activityId;
@Schema(description = "创建时间")
private String createTime;
@Schema(description = "更新时间")
private String updateTime;
}

View File

@ -0,0 +1,44 @@
package com.seer.teach.mp.admin.service;
import com.seer.teach.common.PageListBean;
import com.seer.teach.mp.admin.controller.req.MpActivityCarouselQueryReq;
import com.seer.teach.mp.admin.controller.req.MpActivityCarouselReq;
import com.seer.teach.mp.admin.controller.resp.AdminActivityCarouselResp;
import java.util.List;
/**
* <p>
* 管理端活动轮播图服务类
* </p>
*
* @author Lingma
* @since 2026-01-30
*/
public interface IAdminActivityCarouselService {
/**
* 分页查询活动轮播图列表
*/
PageListBean<AdminActivityCarouselResp> pageList(MpActivityCarouselQueryReq query);
/**
* 获取活动轮播图详情
*/
AdminActivityCarouselResp getById(Integer id);
/**
* 保存或更新活动轮播图
*/
Boolean saveOrUpdateCarousel(MpActivityCarouselReq request);
/**
* 删除活动轮播图
*/
Boolean deleteCarousel(Integer id);
/**
* 根据活动ID获取轮播图列表
*/
List<AdminActivityCarouselResp> getByActivityId(Integer activityId);
}

View File

@ -0,0 +1,119 @@
package com.seer.teach.mp.admin.service.impl;
import cn.hutool.core.bean.BeanUtil;
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.seer.teach.common.PageListBean;
import com.seer.teach.common.utils.PageConverterUtils;
import com.seer.teach.mp.admin.controller.req.MpActivityCarouselQueryReq;
import com.seer.teach.mp.admin.controller.req.MpActivityCarouselReq;
import com.seer.teach.mp.admin.controller.resp.AdminActivityCarouselResp;
import com.seer.teach.mp.admin.service.IAdminActivityCarouselService;
import com.seer.teach.mp.entity.MpActivityCarouselEntity;
import com.seer.teach.mp.mapper.MpActivityCarouselMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
/**
* <p>
* 管理端活动轮播图服务实现类
* </p>
*
* @author Lingma
* @since 2026-01-30
*/
@Service
@RequiredArgsConstructor
public class AdminActivityCarouselServiceImpl extends ServiceImpl<MpActivityCarouselMapper, MpActivityCarouselEntity> implements IAdminActivityCarouselService {
private final MpActivityCarouselMapper mpActivityCarouselMapper;
@Override
public PageListBean<AdminActivityCarouselResp> pageList(MpActivityCarouselQueryReq query) {
LambdaQueryWrapper<MpActivityCarouselEntity> wrapper = new LambdaQueryWrapper<>();
if (ObjectUtil.isNotNull(query.getIsActive())) {
wrapper.eq(MpActivityCarouselEntity::getIsActive, query.getIsActive());
}
// 按排序值升序排列
wrapper.orderByAsc(MpActivityCarouselEntity::getSortOrder);
IPage<MpActivityCarouselEntity> page = new Page<>(query.getPageNo(), query.getPageSize());
IPage<MpActivityCarouselEntity> result = mpActivityCarouselMapper.selectPage(page, wrapper);
return PageConverterUtils.convertPageList(result, this::convertToResp);
}
@Override
public AdminActivityCarouselResp getById(Integer id) {
MpActivityCarouselEntity entity = mpActivityCarouselMapper.selectById(id);
return convertToResp(entity);
}
@Override
public Boolean saveOrUpdateCarousel(MpActivityCarouselReq request) {
MpActivityCarouselEntity entity = new MpActivityCarouselEntity();
if (request.getId() != null) {
entity = mpActivityCarouselMapper.selectById(request.getId());
}
BeanUtil.copyProperties(request, entity);
if (request.getId() != null) {
return mpActivityCarouselMapper.updateById(entity) > 0;
} else {
return mpActivityCarouselMapper.insert(entity) > 0;
}
}
@Override
public Boolean deleteCarousel(Integer id) {
MpActivityCarouselEntity entity = mpActivityCarouselMapper.selectById(id);
if (entity != null) {
return mpActivityCarouselMapper.deleteById(id) > 0;
}
return false;
}
@Override
public List<AdminActivityCarouselResp> getByActivityId(Integer activityId) {
LambdaQueryWrapper<MpActivityCarouselEntity> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(MpActivityCarouselEntity::getActivityId, activityId)
.eq(MpActivityCarouselEntity::getIsActive, true) // 只查询激活的轮播图
.orderByAsc(MpActivityCarouselEntity::getSortOrder); // 按排序值升序排列
List<MpActivityCarouselEntity> entities = mpActivityCarouselMapper.selectList(wrapper);
return entities.stream()
.map(this::convertToResp)
.collect(Collectors.toList());
}
/**
* 将实体转换为响应对象
*/
private AdminActivityCarouselResp convertToResp(MpActivityCarouselEntity entity) {
if (entity == null) {
return null;
}
AdminActivityCarouselResp resp = new AdminActivityCarouselResp();
resp.setId(entity.getId());
resp.setImageUrl(entity.getImageUrl());
resp.setLinkUrl(entity.getLinkUrl());
resp.setTitle(entity.getTitle());
resp.setDescription(entity.getDescription());
resp.setSortOrder(entity.getSortOrder());
resp.setIsActive(entity.getIsActive());
resp.setActivityId(entity.getActivityId());
resp.setCreateTime(entity.getCreateTime() != null ? entity.getCreateTime().toString() : null);
resp.setUpdateTime(entity.getUpdateTime() != null ? entity.getUpdateTime().toString() : null);
return resp;
}
}

View File

@ -0,0 +1,110 @@
package com.seer.teach.mp.admin.service.impl;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import com.seer.teach.mp.entity.MpActivityCarouselEntity;
import com.seer.teach.mp.mapper.MpActivityCarouselMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
class AdminActivityCarouselServiceImplTest {
@Mock
private MpActivityCarouselMapper mpActivityCarouselMapper;
@InjectMocks
private AdminActivityCarouselServiceImpl adminActivityCarouselService;
private MpActivityCarouselEntity carouselEntity;
@BeforeEach
void setUp() {
carouselEntity = new MpActivityCarouselEntity();
carouselEntity.setId(1);
carouselEntity.setImageUrl("https://example.com/image.jpg");
carouselEntity.setTitle("Test Carousel");
carouselEntity.setActivityId(1);
carouselEntity.setIsActive(true);
carouselEntity.setSortOrder(1);
}
@Test
void testSaveOrUpdateCarousel_Create() {
// Given
when(mpActivityCarouselMapper.insert(any(MpActivityCarouselEntity.class))).thenReturn(1);
com.seer.teach.mp.admin.controller.req.MpActivityCarouselReq request = new com.seer.teach.mp.admin.controller.req.MpActivityCarouselReq();
request.setImageUrl("https://example.com/image.jpg");
request.setTitle("Test Carousel");
request.setActivityId(1);
request.setIsActive(true);
request.setSortOrder(1);
// When
Boolean result = adminActivityCarouselService.saveOrUpdateCarousel(request);
// Then
assertTrue(result);
verify(mpActivityCarouselMapper, times(1)).insert(any(MpActivityCarouselEntity.class));
}
@Test
void testSaveOrUpdateCarousel_Update() {
// Given
when(mpActivityCarouselMapper.selectById(1)).thenReturn(carouselEntity);
when(mpActivityCarouselMapper.updateById(any(MpActivityCarouselEntity.class))).thenReturn(1);
com.seer.teach.mp.admin.controller.req.MpActivityCarouselReq request = new com.seer.teach.mp.admin.controller.req.MpActivityCarouselReq();
request.setId(1);
request.setImageUrl("https://example.com/image.jpg");
request.setTitle("Updated Carousel");
request.setActivityId(1);
request.setIsActive(true);
request.setSortOrder(2);
// When
Boolean result = adminActivityCarouselService.saveOrUpdateCarousel(request);
// Then
assertTrue(result);
verify(mpActivityCarouselMapper, times(1)).selectById(1);
verify(mpActivityCarouselMapper, times(1)).updateById(any(MpActivityCarouselEntity.class));
}
@Test
void testDeleteCarousel() {
// Given
when(mpActivityCarouselMapper.selectById(1)).thenReturn(carouselEntity);
when(mpActivityCarouselMapper.deleteById(1)).thenReturn(1);
// When
Boolean result = adminActivityCarouselService.deleteCarousel(1);
// Then
assertTrue(result);
verify(mpActivityCarouselMapper, times(1)).selectById(1);
verify(mpActivityCarouselMapper, times(1)).deleteById(1);
}
@Test
void testGetById() {
// Given
when(mpActivityCarouselMapper.selectById(1)).thenReturn(carouselEntity);
// When
var result = adminActivityCarouselService.getById(1);
// Then
assertNotNull(result);
assertEquals("Test Carousel", result.getTitle());
assertEquals("https://example.com/image.jpg", result.getImageUrl());
verify(mpActivityCarouselMapper, times(1)).selectById(1);
}
}

View File

@ -153,4 +153,27 @@ CREATE TABLE `mp_activity_info_collection` (
KEY `idx_activity_id` (`activity_id`),
KEY `idx_parent_id` (`parent_id`),
KEY `idx_relation_id` (`relation_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='活动信息收集表';
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='活动信息收集表';
-- 创建活动轮播图表
DROP TABLE IF EXISTS `mp_activity_carousel`;
CREATE TABLE `mp_activity_carousel` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '轮播图ID',
`image_url` VARCHAR(255) NOT NULL COMMENT '图片地址',
`link_url` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '跳转链接',
`title` VARCHAR(100) DEFAULT NULL COMMENT '标题',
`description` VARCHAR(255) DEFAULT NULL COMMENT '描述/替代文本',
`sort_order` INT NOT NULL DEFAULT 0 COMMENT '排序值',
`is_active` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '激活状态1-显示0-隐藏',
`activity_id` int NOT NULL COMMENT '关联活动ID',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`create_by` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_german2_ci NULL DEFAULT NULL COMMENT '创建人',
`update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`update_by` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_german2_ci NULL DEFAULT NULL COMMENT '修改人',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` varchar(20) DEFAULT 'Default' COMMENT '租户id',
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_activity_id` (`activity_id`),
KEY `idx_sort_order` (`sort_order`),
KEY `idx_is_active` (`is_active`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='活动轮播图表';

View File

@ -8,6 +8,7 @@ import com.seer.teach.common.annotation.DecryptionAnnotation;
import com.seer.teach.common.annotation.EncryptionAnnotation;
import com.seer.teach.common.annotation.LogPrint;
import com.seer.teach.mp.app.controller.req.AppActivityQueryReq;
import com.seer.teach.mp.app.controller.resp.AppActivityCarouselResp;
import com.seer.teach.mp.app.controller.resp.AppActivityResp;
import com.seer.teach.mp.app.service.IAppActivityService;
import io.swagger.v3.oas.annotations.Operation;
@ -19,6 +20,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* <p>
* 代理商活动App控制器
@ -53,4 +56,9 @@ public class AppMpActivityController {
return ResultBean.success(agentActivityService.getById(id));
}
@Operation(summary = "根据活动ID获取激活的轮播图列表")
@GetMapping("/carousel/{activityId}")
public ResultBean<List<AppActivityCarouselResp>> getByActivityId(@PathVariable("activityId") Integer activityId) {
return ResultBean.success(agentActivityService.getCarouselListByActivityId(activityId));
}
}

View File

@ -0,0 +1,42 @@
package com.seer.teach.mp.app.controller.resp;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 活动轮播图响应参数
*/
@Data
@Schema(name = "AppActivityCarouselResp", description = "活动轮播图响应参数")
public class AppActivityCarouselResp {
@Schema(description = "轮播图ID")
private Integer id;
@Schema(description = "图片地址")
private String imageUrl;
@Schema(description = "跳转链接")
private String linkUrl;
@Schema(description = "标题")
private String title;
@Schema(description = "描述/替代文本")
private String description;
@Schema(description = "排序值")
private Integer sortOrder;
@Schema(description = "激活状态1-显示0-隐藏")
private Boolean isActive;
@Schema(description = "关联活动ID")
private Integer activityId;
@Schema(description = "创建时间")
private String createTime;
@Schema(description = "更新时间")
private String updateTime;
}

View File

@ -1,7 +1,9 @@
package com.seer.teach.mp.app.convert;
import com.seer.teach.mp.app.controller.req.AppActivityQueryReq;
import com.seer.teach.mp.app.controller.resp.AppActivityCarouselResp;
import com.seer.teach.mp.app.controller.resp.AppActivityResp;
import com.seer.teach.mp.entity.MpActivityCarouselEntity;
import com.seer.teach.mp.entity.MpActivityEntity;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
@ -21,4 +23,6 @@ public interface AppAgentActivityConvert {
AppActivityResp convertToResp(MpActivityEntity entity);
List<AppActivityResp> convertToRespList(List<MpActivityEntity> mpAgentActivityEntities);
List<AppActivityCarouselResp> convertToCarouselRespList(List<MpActivityCarouselEntity> list);
}

View File

@ -2,8 +2,11 @@ package com.seer.teach.mp.app.service;
import com.seer.teach.common.PageListBean;
import com.seer.teach.mp.app.controller.req.AppActivityQueryReq;
import com.seer.teach.mp.app.controller.resp.AppActivityCarouselResp;
import com.seer.teach.mp.app.controller.resp.AppActivityResp;
import java.util.List;
/**
* <p>
* APP端代理商活动服务类
@ -31,4 +34,11 @@ public interface IAppActivityService {
*/
AppActivityResp getById(Integer id);
/**
* 获取活动轮播图列表
*
* @param activityId 活动ID
* @return 活动轮播图列表
*/
List<AppActivityCarouselResp> getCarouselListByActivityId(Integer activityId);
}

View File

@ -7,11 +7,14 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.seer.teach.common.PageListBean;
import com.seer.teach.common.utils.PageConverterUtils;
import com.seer.teach.mp.app.controller.req.AppActivityQueryReq;
import com.seer.teach.mp.app.controller.resp.AppActivityCarouselResp;
import com.seer.teach.mp.app.controller.resp.AppActivityResp;
import com.seer.teach.mp.app.convert.AppAgentActivityConvert;
import com.seer.teach.mp.app.service.AppOfficialQrCodeService;
import com.seer.teach.mp.app.service.IAppActivityService;
import com.seer.teach.mp.entity.MpActivityCarouselEntity;
import com.seer.teach.mp.entity.MpActivityEntity;
import com.seer.teach.mp.service.IMpActivityCarouselService;
import com.seer.teach.mp.service.IMpActivityService;
import com.seer.teach.mp.service.IMpAgentActivityRelationService;
import lombok.RequiredArgsConstructor;
@ -19,6 +22,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Objects;
/**
@ -36,9 +40,8 @@ public class AppActivityServiceImpl implements IAppActivityService {
private final IMpActivityService activityService;
private final AppOfficialQrCodeService officialQrCodeService;
private final IMpAgentActivityRelationService agentActivityParticipantService;
private final IMpActivityCarouselService activityCarouselService;
@Override
public PageListBean<AppActivityResp> pageList(AppActivityQueryReq query, Integer agentId) {
@ -59,4 +62,10 @@ public class AppActivityServiceImpl implements IAppActivityService {
MpActivityEntity entity = activityService.getById(id);
return AppAgentActivityConvert.INSTANCE.convertToResp(entity);
}
@Override
public List<AppActivityCarouselResp> getCarouselListByActivityId(Integer activityId) {
List<MpActivityCarouselEntity> list = activityCarouselService.list(new LambdaQueryWrapper<>(MpActivityCarouselEntity.class).eq(MpActivityCarouselEntity::getActivityId, activityId));
return AppAgentActivityConvert.INSTANCE.convertToCarouselRespList(list);
}
}

View File

@ -0,0 +1,7 @@
package com.seer.teach.mp.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.seer.teach.mp.entity.MpActivityCarouselEntity;
public interface IMpActivityCarouselService extends IService<MpActivityCarouselEntity> {
}

View File

@ -0,0 +1,11 @@
package com.seer.teach.mp.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.seer.teach.mp.entity.MpActivityCarouselEntity;
import com.seer.teach.mp.mapper.MpActivityCarouselMapper;
import com.seer.teach.mp.service.IMpActivityCarouselService;
import org.springframework.stereotype.Service;
@Service
public class MpActivityCarouselServiceImpl extends ServiceImpl<MpActivityCarouselMapper, MpActivityCarouselEntity> implements IMpActivityCarouselService {
}

View File

@ -47,9 +47,6 @@ public abstract class AbstractWxPayClient extends AbstractPayClient {
protected WxPayService client;
protected String notifyUrl;
protected String refundNotifyUrl;
public AbstractWxPayClient(String channelCode, String configJson) {
super(channelCode, configJson);
@ -71,8 +68,6 @@ public abstract class AbstractWxPayClient extends AbstractPayClient {
String merchantSerialNumber = channelConfig.getStr("merchantSerialNumber");
String privateKeyPem = channelConfig.getStr("privateKeyPem");
String publicKeyPem = channelConfig.getStr("publicKeyPem");
this.notifyUrl = channelConfig.getStr("jsPayNotifyUrl");
this.refundNotifyUrl = channelConfig.getStr("jsRefundNotifyUrl");
// 使用安全解密方法处理敏感配置参数
apiV3Key = ConfigDecryptUtil.safeDecrypt(apiV3Key);
publicKeyId = ConfigDecryptUtil.safeDecrypt(publicKeyId);
@ -91,9 +86,6 @@ public abstract class AbstractWxPayClient extends AbstractPayClient {
wxPayConfig.setPrivateCertString(privateKeyPem);
wxPayConfig.setNotifyUrl(notifyUrl);
wxPayConfig.setRefundNotifyUrl(refundNotifyUrl);
client = new WxPayServiceImpl();
client.setConfig(wxPayConfig);
}
@ -240,7 +232,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient {
request.setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal(reqDTO.getTotalAmount())); // 单位分
request.setTimeExpire(formatDateV3(reqDTO.getExpireTime()));
request.setSceneInfo(new WxPayUnifiedOrderV3Request.SceneInfo().setPayerClientIp(reqDTO.getUserIp()));
request.setNotifyUrl(getNotifyUrl());
request.setNotifyUrl(reqDTO.getNotifyUrl());
return request;
}
@ -269,11 +261,6 @@ public abstract class AbstractWxPayClient extends AbstractPayClient {
return headers.get(lowercaseKey);
}
protected String getNotifyUrl() {
return notifyUrl;
}
protected static Integer parseStatus(String tradeState) {
switch (tradeState) {
case "NOTPAY":