You've already forked FrameTour-BE
feat(notify): 新增用户通知授权管理功能
- 添加用户通知授权记录的完整CRUD操作 - 实现授权次数的记录与消费逻辑 - 提供授权状态检查与剩余次数查询接口 - 支持按用户、模板或景区维度查询授权记录 - 新增授权统计信息接口,包括总授权数、消费数等 - 完成移动端相关请求/响应DTO定义 - 集成MyBatis Mapper实现数据持久化操作 - 添加服务层事务控制确保操作一致性
This commit is contained in:
@@ -0,0 +1,237 @@
|
|||||||
|
package com.ycwl.basic.controller.mobile.notify;
|
||||||
|
|
||||||
|
import com.ycwl.basic.config.JwtInfo;
|
||||||
|
import com.ycwl.basic.model.mobile.notify.req.NotificationAuthCheckReq;
|
||||||
|
import com.ycwl.basic.model.mobile.notify.req.NotificationAuthConsumeReq;
|
||||||
|
import com.ycwl.basic.model.mobile.notify.req.NotificationAuthRecordReq;
|
||||||
|
import com.ycwl.basic.model.mobile.notify.req.NotificationAuthRecordsReq;
|
||||||
|
import com.ycwl.basic.model.mobile.notify.resp.NotificationAuthCheckResp;
|
||||||
|
import com.ycwl.basic.model.mobile.notify.resp.NotificationAuthConsumeResp;
|
||||||
|
import com.ycwl.basic.model.mobile.notify.resp.NotificationAuthRecordResp;
|
||||||
|
import com.ycwl.basic.model.pc.notify.entity.UserNotificationAuthorizationEntity;
|
||||||
|
import com.ycwl.basic.service.UserNotificationAuthorizationService;
|
||||||
|
import com.ycwl.basic.utils.ResponseData;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户通知授权记录Controller (移动端API)
|
||||||
|
*
|
||||||
|
* @Author: System
|
||||||
|
* @Date: 2024/12/28
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/mobile/notify/auth")
|
||||||
|
@Slf4j
|
||||||
|
public class UserNotificationAuthController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserNotificationAuthorizationService userNotificationAuthorizationService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查用户通知授权状态
|
||||||
|
*/
|
||||||
|
@PostMapping("/check")
|
||||||
|
public ResponseData<NotificationAuthCheckResp> checkAuthorization(
|
||||||
|
@JwtInfo Long memberId,
|
||||||
|
@Valid @RequestBody NotificationAuthCheckReq req) {
|
||||||
|
log.info("检查用户通知授权状态: memberId={}, templateId={}, scenicId={}",
|
||||||
|
memberId, req.getTemplateId(), req.getScenicId());
|
||||||
|
|
||||||
|
try {
|
||||||
|
UserNotificationAuthorizationEntity record = userNotificationAuthorizationService
|
||||||
|
.checkAuthorization(memberId, req.getTemplateId(), req.getScenicId());
|
||||||
|
|
||||||
|
NotificationAuthCheckResp resp = new NotificationAuthCheckResp();
|
||||||
|
if (record != null) {
|
||||||
|
resp.setHasAuthorization(true);
|
||||||
|
resp.setRemainingCount(record.getRemainingCount());
|
||||||
|
resp.setAuthorizationCount(record.getAuthorizationCount());
|
||||||
|
resp.setConsumedCount(record.getConsumedCount());
|
||||||
|
resp.setLastAuthorizedTime(record.getLastAuthorizedTime());
|
||||||
|
resp.setLastConsumedTime(record.getLastConsumedTime());
|
||||||
|
resp.setTemplateId(record.getTemplateId());
|
||||||
|
resp.setScenicId(record.getScenicId());
|
||||||
|
} else {
|
||||||
|
resp.setHasAuthorization(false);
|
||||||
|
resp.setRemainingCount(0);
|
||||||
|
resp.setAuthorizationCount(0);
|
||||||
|
resp.setConsumedCount(0);
|
||||||
|
resp.setTemplateId(req.getTemplateId());
|
||||||
|
resp.setScenicId(req.getScenicId());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResponseData.success(resp);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("检查用户通知授权状态失败", e);
|
||||||
|
return ResponseData.fail("检查授权状态失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录用户通知授权
|
||||||
|
*/
|
||||||
|
@PostMapping("/record")
|
||||||
|
public ResponseData<NotificationAuthRecordResp> recordAuthorization(
|
||||||
|
@JwtInfo Long memberId,
|
||||||
|
@Valid @RequestBody NotificationAuthRecordReq req) {
|
||||||
|
log.info("记录用户通知授权: memberId={}, templateId={}, scenicId={}",
|
||||||
|
memberId, req.getTemplateId(), req.getScenicId());
|
||||||
|
|
||||||
|
try {
|
||||||
|
UserNotificationAuthorizationEntity record = userNotificationAuthorizationService
|
||||||
|
.recordAuthorization(memberId, req.getTemplateId(), req.getScenicId());
|
||||||
|
|
||||||
|
NotificationAuthRecordResp resp = new NotificationAuthRecordResp();
|
||||||
|
BeanUtils.copyProperties(record, resp);
|
||||||
|
|
||||||
|
return ResponseData.success(resp);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("记录用户通知授权失败", e);
|
||||||
|
return ResponseData.fail("记录授权失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消费通知授权
|
||||||
|
*/
|
||||||
|
@PostMapping("/consume")
|
||||||
|
public ResponseData<NotificationAuthConsumeResp> consumeAuthorization(
|
||||||
|
@JwtInfo Long memberId,
|
||||||
|
@Valid @RequestBody NotificationAuthConsumeReq req) {
|
||||||
|
log.info("消费通知授权: memberId={}, templateId={}, scenicId={}",
|
||||||
|
memberId, req.getTemplateId(), req.getScenicId());
|
||||||
|
|
||||||
|
try {
|
||||||
|
boolean consumeSuccess = userNotificationAuthorizationService
|
||||||
|
.consumeAuthorization(memberId, req.getTemplateId(), req.getScenicId());
|
||||||
|
|
||||||
|
NotificationAuthConsumeResp resp = new NotificationAuthConsumeResp();
|
||||||
|
resp.setConsumeSuccess(consumeSuccess);
|
||||||
|
|
||||||
|
if (consumeSuccess) {
|
||||||
|
Integer remainingCount = userNotificationAuthorizationService
|
||||||
|
.getRemainingCount(memberId, req.getTemplateId(), req.getScenicId());
|
||||||
|
resp.setRemainingCount(remainingCount);
|
||||||
|
} else {
|
||||||
|
resp.setFailReason("授权次数不足或授权记录不存在");
|
||||||
|
resp.setRemainingCount(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResponseData.success(resp);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("消费通知授权失败", e);
|
||||||
|
return ResponseData.fail("消费授权失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询用户通知授权记录
|
||||||
|
*/
|
||||||
|
@GetMapping("/records")
|
||||||
|
public ResponseData<List<NotificationAuthRecordResp>> getUserAuthorizationRecords(
|
||||||
|
@JwtInfo Long memberId,
|
||||||
|
@Valid NotificationAuthRecordsReq req) {
|
||||||
|
log.info("查询用户通知授权记录: memberId={}, templateId={}", memberId, req.getTemplateId());
|
||||||
|
|
||||||
|
try {
|
||||||
|
List<UserNotificationAuthorizationEntity> records;
|
||||||
|
if (req.getTemplateId() != null && !req.getTemplateId().trim().isEmpty()) {
|
||||||
|
records = userNotificationAuthorizationService
|
||||||
|
.getUserAuthorizationsByTemplate(memberId, req.getTemplateId());
|
||||||
|
} else {
|
||||||
|
records = userNotificationAuthorizationService.getUserAuthorizations(memberId);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<NotificationAuthRecordResp> respList = new ArrayList<>();
|
||||||
|
if (!CollectionUtils.isEmpty(records)) {
|
||||||
|
for (UserNotificationAuthorizationEntity record : records) {
|
||||||
|
NotificationAuthRecordResp resp = new NotificationAuthRecordResp();
|
||||||
|
BeanUtils.copyProperties(record, resp);
|
||||||
|
// TODO: 可以在这里添加景区名称查询
|
||||||
|
respList.add(resp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResponseData.success(respList);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("查询用户通知授权记录失败", e);
|
||||||
|
return ResponseData.fail("查询授权记录失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户授权统计信息
|
||||||
|
*/
|
||||||
|
@GetMapping("/stats")
|
||||||
|
public ResponseData<AuthorizationStats> getAuthorizationStats(@JwtInfo Long memberId) {
|
||||||
|
log.info("获取用户授权统计信息: memberId={}", memberId);
|
||||||
|
|
||||||
|
try {
|
||||||
|
List<UserNotificationAuthorizationEntity> records = userNotificationAuthorizationService
|
||||||
|
.getUserAuthorizations(memberId);
|
||||||
|
|
||||||
|
int totalTemplates = records.size();
|
||||||
|
int totalAuthorizations = records.stream()
|
||||||
|
.mapToInt(UserNotificationAuthorizationEntity::getAuthorizationCount)
|
||||||
|
.sum();
|
||||||
|
int totalConsumed = records.stream()
|
||||||
|
.mapToInt(UserNotificationAuthorizationEntity::getConsumedCount)
|
||||||
|
.sum();
|
||||||
|
int totalRemaining = totalAuthorizations - totalConsumed;
|
||||||
|
|
||||||
|
// 创建统计信息对象
|
||||||
|
AuthorizationStats stats = new AuthorizationStats();
|
||||||
|
stats.totalTemplates = totalTemplates;
|
||||||
|
stats.totalAuthorizations = totalAuthorizations;
|
||||||
|
stats.totalConsumed = totalConsumed;
|
||||||
|
stats.totalRemaining = totalRemaining;
|
||||||
|
stats.queryTime = new Date();
|
||||||
|
|
||||||
|
return ResponseData.success(stats);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("获取用户授权统计信息失败", e);
|
||||||
|
return ResponseData.fail("获取统计信息失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 授权统计信息DTO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class AuthorizationStats {
|
||||||
|
/**
|
||||||
|
* 总模板数
|
||||||
|
*/
|
||||||
|
private int totalTemplates;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 总授权次数
|
||||||
|
*/
|
||||||
|
private int totalAuthorizations;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 总消费次数
|
||||||
|
*/
|
||||||
|
private int totalConsumed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 剩余授权次数
|
||||||
|
*/
|
||||||
|
private int totalRemaining;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询时间
|
||||||
|
*/
|
||||||
|
private Date queryTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
package com.ycwl.basic.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.ycwl.basic.model.pc.notify.entity.UserNotificationAuthorizationEntity;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户通知授权记录Mapper接口
|
||||||
|
*
|
||||||
|
* @Author: System
|
||||||
|
* @Date: 2024/12/28
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface UserNotificationAuthorizationMapper extends BaseMapper<UserNotificationAuthorizationEntity> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户ID、模板ID和景区ID查询授权记录
|
||||||
|
*
|
||||||
|
* @param memberId 用户ID
|
||||||
|
* @param templateId 模板ID
|
||||||
|
* @param scenicId 景区ID
|
||||||
|
* @return 授权记录
|
||||||
|
*/
|
||||||
|
UserNotificationAuthorizationEntity selectByMemberAndTemplateAndScenic(
|
||||||
|
@Param("memberId") Long memberId,
|
||||||
|
@Param("templateId") String templateId,
|
||||||
|
@Param("scenicId") Long scenicId
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户ID查询授权记录列表
|
||||||
|
*
|
||||||
|
* @param memberId 用户ID
|
||||||
|
* @return 授权记录列表
|
||||||
|
*/
|
||||||
|
List<UserNotificationAuthorizationEntity> selectByMemberId(@Param("memberId") Long memberId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户ID和模板ID查询授权记录列表
|
||||||
|
*
|
||||||
|
* @param memberId 用户ID
|
||||||
|
* @param templateId 模板ID
|
||||||
|
* @return 授权记录列表
|
||||||
|
*/
|
||||||
|
List<UserNotificationAuthorizationEntity> selectByMemberIdAndTemplateId(
|
||||||
|
@Param("memberId") Long memberId,
|
||||||
|
@Param("templateId") String templateId
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据景区ID查询授权记录列表
|
||||||
|
*
|
||||||
|
* @param scenicId 景区ID
|
||||||
|
* @return 授权记录列表
|
||||||
|
*/
|
||||||
|
List<UserNotificationAuthorizationEntity> selectByScenicId(@Param("scenicId") Long scenicId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 增加授权次数
|
||||||
|
*
|
||||||
|
* @param id 记录ID
|
||||||
|
* @param count 增加的数量
|
||||||
|
* @return 影响行数
|
||||||
|
*/
|
||||||
|
int increaseAuthorizationCount(@Param("id") Long id, @Param("count") Integer count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 增加消费次数
|
||||||
|
*
|
||||||
|
* @param id 记录ID
|
||||||
|
* @param count 增加的数量
|
||||||
|
* @return 影响行数
|
||||||
|
*/
|
||||||
|
int increaseConsumedCount(@Param("id") Long id, @Param("count") Integer count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查用户是否还有剩余授权次数
|
||||||
|
*
|
||||||
|
* @param memberId 用户ID
|
||||||
|
* @param templateId 模板ID
|
||||||
|
* @param scenicId 景区ID
|
||||||
|
* @return 剩余授权次数
|
||||||
|
*/
|
||||||
|
Integer selectRemainingCount(
|
||||||
|
@Param("memberId") Long memberId,
|
||||||
|
@Param("templateId") String templateId,
|
||||||
|
@Param("scenicId") Long scenicId
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.ycwl.basic.model.mobile.notify.req;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知授权检查请求
|
||||||
|
*
|
||||||
|
* @Author: System
|
||||||
|
* @Date: 2024/12/28
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class NotificationAuthCheckReq {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知模板ID
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "模板ID不能为空")
|
||||||
|
private String templateId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 景区ID
|
||||||
|
*/
|
||||||
|
@NotNull(message = "景区ID不能为空")
|
||||||
|
private Long scenicId;
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.ycwl.basic.model.mobile.notify.req;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知授权消费请求
|
||||||
|
*
|
||||||
|
* @Author: System
|
||||||
|
* @Date: 2024/12/28
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class NotificationAuthConsumeReq {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知模板ID
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "模板ID不能为空")
|
||||||
|
private String templateId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 景区ID
|
||||||
|
*/
|
||||||
|
@NotNull(message = "景区ID不能为空")
|
||||||
|
private Long scenicId;
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.ycwl.basic.model.mobile.notify.req;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知授权记录请求
|
||||||
|
*
|
||||||
|
* @Author: System
|
||||||
|
* @Date: 2024/12/28
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class NotificationAuthRecordReq {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知模板ID
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "模板ID不能为空")
|
||||||
|
private String templateId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 景区ID
|
||||||
|
*/
|
||||||
|
@NotNull(message = "景区ID不能为空")
|
||||||
|
private Long scenicId;
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.ycwl.basic.model.mobile.notify.req;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知授权记录查询请求
|
||||||
|
*
|
||||||
|
* @Author: System
|
||||||
|
* @Date: 2024/12/28
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class NotificationAuthRecordsReq {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板ID(可选)
|
||||||
|
*/
|
||||||
|
private String templateId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页码
|
||||||
|
*/
|
||||||
|
private Integer page = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 每页大小
|
||||||
|
*/
|
||||||
|
private Integer size = 10;
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package com.ycwl.basic.model.mobile.notify.resp;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知授权检查响应
|
||||||
|
*
|
||||||
|
* @Author: System
|
||||||
|
* @Date: 2024/12/28
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class NotificationAuthCheckResp {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否有授权
|
||||||
|
*/
|
||||||
|
private Boolean hasAuthorization;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 剩余授权次数
|
||||||
|
*/
|
||||||
|
private Integer remainingCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 总授权次数
|
||||||
|
*/
|
||||||
|
private Integer authorizationCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 已消费次数
|
||||||
|
*/
|
||||||
|
private Integer consumedCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最后授权时间
|
||||||
|
*/
|
||||||
|
private Date lastAuthorizedTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最后消费时间
|
||||||
|
*/
|
||||||
|
private Date lastConsumedTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板ID
|
||||||
|
*/
|
||||||
|
private String templateId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 景区ID
|
||||||
|
*/
|
||||||
|
private Long scenicId;
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.ycwl.basic.model.mobile.notify.resp;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知授权消费响应
|
||||||
|
*
|
||||||
|
* @Author: System
|
||||||
|
* @Date: 2024/12/28
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class NotificationAuthConsumeResp {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否消费成功
|
||||||
|
*/
|
||||||
|
private Boolean consumeSuccess;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 剩余授权次数
|
||||||
|
*/
|
||||||
|
private Integer remainingCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消费失败原因
|
||||||
|
*/
|
||||||
|
private String failReason;
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package com.ycwl.basic.model.mobile.notify.resp;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知授权记录响应
|
||||||
|
*
|
||||||
|
* @Author: System
|
||||||
|
* @Date: 2024/12/28
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class NotificationAuthRecordResp {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录ID
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板ID
|
||||||
|
*/
|
||||||
|
private String templateId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 景区ID
|
||||||
|
*/
|
||||||
|
private Long scenicId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 景区名称
|
||||||
|
*/
|
||||||
|
private String scenicName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 授权次数
|
||||||
|
*/
|
||||||
|
private Integer authorizationCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 已消费次数
|
||||||
|
*/
|
||||||
|
private Integer consumedCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 剩余授权次数
|
||||||
|
*/
|
||||||
|
private Integer remainingCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最后授权时间
|
||||||
|
*/
|
||||||
|
private Date lastAuthorizedTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最后消费时间
|
||||||
|
*/
|
||||||
|
private Date lastConsumedTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态
|
||||||
|
*/
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
private Date createTime;
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package com.ycwl.basic.model.pc.notify.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户通知授权记录实体类
|
||||||
|
*
|
||||||
|
* @Author: System
|
||||||
|
* @Date: 2024/12/28
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@TableName("user_notification_authorization")
|
||||||
|
public class UserNotificationAuthorizationEntity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键ID
|
||||||
|
*/
|
||||||
|
@TableId
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户ID
|
||||||
|
*/
|
||||||
|
private Long memberId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知模板ID(微信消息模板ID)
|
||||||
|
*/
|
||||||
|
private String templateId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 景区ID
|
||||||
|
*/
|
||||||
|
private Long scenicId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 授权次数
|
||||||
|
*/
|
||||||
|
private Integer authorizationCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 已消费次数
|
||||||
|
*/
|
||||||
|
private Integer consumedCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 剩余授权次数(计算字段)
|
||||||
|
*/
|
||||||
|
private Integer remainingCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最后授权时间
|
||||||
|
*/
|
||||||
|
private Date lastAuthorizedTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最后消费时间
|
||||||
|
*/
|
||||||
|
private Date lastConsumedTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态:1-有效,0-无效
|
||||||
|
*/
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新时间
|
||||||
|
*/
|
||||||
|
private Date updateTime;
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
package com.ycwl.basic.service;
|
||||||
|
|
||||||
|
import com.ycwl.basic.model.pc.notify.entity.UserNotificationAuthorizationEntity;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户通知授权记录Service接口
|
||||||
|
*
|
||||||
|
* @Author: System
|
||||||
|
* @Date: 2024/12/28
|
||||||
|
*/
|
||||||
|
public interface UserNotificationAuthorizationService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查用户是否对指定模板有授权
|
||||||
|
*
|
||||||
|
* @param memberId 用户ID
|
||||||
|
* @param templateId 模板ID
|
||||||
|
* @param scenicId 景区ID
|
||||||
|
* @return 授权记录,如果没有授权返回null
|
||||||
|
*/
|
||||||
|
UserNotificationAuthorizationEntity checkAuthorization(Long memberId, String templateId, Long scenicId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查用户是否还有剩余授权次数
|
||||||
|
*
|
||||||
|
* @param memberId 用户ID
|
||||||
|
* @param templateId 模板ID
|
||||||
|
* @param scenicId 景区ID
|
||||||
|
* @return 剩余授权次数,0表示没有剩余
|
||||||
|
*/
|
||||||
|
Integer getRemainingCount(Long memberId, String templateId, Long scenicId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录用户授权
|
||||||
|
*
|
||||||
|
* @param memberId 用户ID
|
||||||
|
* @param templateId 模板ID
|
||||||
|
* @param scenicId 景区ID
|
||||||
|
* @return 授权记录
|
||||||
|
*/
|
||||||
|
UserNotificationAuthorizationEntity recordAuthorization(Long memberId, String templateId, Long scenicId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消费一次授权
|
||||||
|
*
|
||||||
|
* @param memberId 用户ID
|
||||||
|
* @param templateId 模板ID
|
||||||
|
* @param scenicId 景区ID
|
||||||
|
* @return 是否消费成功
|
||||||
|
*/
|
||||||
|
boolean consumeAuthorization(Long memberId, String templateId, Long scenicId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询用户的授权记录列表
|
||||||
|
*
|
||||||
|
* @param memberId 用户ID
|
||||||
|
* @return 授权记录列表
|
||||||
|
*/
|
||||||
|
List<UserNotificationAuthorizationEntity> getUserAuthorizations(Long memberId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询用户对指定模板的授权记录列表
|
||||||
|
*
|
||||||
|
* @param memberId 用户ID
|
||||||
|
* @param templateId 模板ID
|
||||||
|
* @return 授权记录列表
|
||||||
|
*/
|
||||||
|
List<UserNotificationAuthorizationEntity> getUserAuthorizationsByTemplate(Long memberId, String templateId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询景区的授权记录列表
|
||||||
|
*
|
||||||
|
* @param scenicId 景区ID
|
||||||
|
* @return 授权记录列表
|
||||||
|
*/
|
||||||
|
List<UserNotificationAuthorizationEntity> getScenicAuthorizations(Long scenicId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID查询授权记录
|
||||||
|
*
|
||||||
|
* @param id 记录ID
|
||||||
|
* @return 授权记录
|
||||||
|
*/
|
||||||
|
UserNotificationAuthorizationEntity getById(Long id);
|
||||||
|
}
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
package com.ycwl.basic.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.ycwl.basic.mapper.UserNotificationAuthorizationMapper;
|
||||||
|
import com.ycwl.basic.model.pc.notify.entity.UserNotificationAuthorizationEntity;
|
||||||
|
import com.ycwl.basic.service.UserNotificationAuthorizationService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户通知授权记录Service实现类
|
||||||
|
*
|
||||||
|
* @Author: System
|
||||||
|
* @Date: 2024/12/28
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class UserNotificationAuthorizationServiceImpl implements UserNotificationAuthorizationService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserNotificationAuthorizationMapper userNotificationAuthorizationMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserNotificationAuthorizationEntity checkAuthorization(Long memberId, String templateId, Long scenicId) {
|
||||||
|
log.debug("检查用户授权: memberId={}, templateId={}, scenicId={}", memberId, templateId, scenicId);
|
||||||
|
return userNotificationAuthorizationMapper.selectByMemberAndTemplateAndScenic(memberId, templateId, scenicId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getRemainingCount(Long memberId, String templateId, Long scenicId) {
|
||||||
|
log.debug("获取剩余授权次数: memberId={}, templateId={}, scenicId={}", memberId, templateId, scenicId);
|
||||||
|
Integer remainingCount = userNotificationAuthorizationMapper.selectRemainingCount(memberId, templateId, scenicId);
|
||||||
|
return remainingCount != null ? remainingCount : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public UserNotificationAuthorizationEntity recordAuthorization(Long memberId, String templateId, Long scenicId) {
|
||||||
|
log.info("记录用户授权: memberId={}, templateId={}, scenicId={}", memberId, templateId, scenicId);
|
||||||
|
|
||||||
|
// 先查询是否已存在记录
|
||||||
|
UserNotificationAuthorizationEntity existingRecord = userNotificationAuthorizationMapper
|
||||||
|
.selectByMemberAndTemplateAndScenic(memberId, templateId, scenicId);
|
||||||
|
|
||||||
|
if (existingRecord != null) {
|
||||||
|
// 增加授权次数
|
||||||
|
int updated = userNotificationAuthorizationMapper.increaseAuthorizationCount(existingRecord.getId(), 1);
|
||||||
|
if (updated > 0) {
|
||||||
|
log.info("成功增加授权次数: recordId={}, newCount={}", existingRecord.getId(),
|
||||||
|
existingRecord.getAuthorizationCount() + 1);
|
||||||
|
// 重新查询最新数据
|
||||||
|
return userNotificationAuthorizationMapper.selectById(existingRecord.getId());
|
||||||
|
} else {
|
||||||
|
log.error("增加授权次数失败: recordId={}", existingRecord.getId());
|
||||||
|
throw new RuntimeException("增加授权次数失败");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 创建新记录
|
||||||
|
UserNotificationAuthorizationEntity newRecord = new UserNotificationAuthorizationEntity();
|
||||||
|
newRecord.setMemberId(memberId);
|
||||||
|
newRecord.setTemplateId(templateId);
|
||||||
|
newRecord.setScenicId(scenicId);
|
||||||
|
newRecord.setAuthorizationCount(1);
|
||||||
|
newRecord.setConsumedCount(0);
|
||||||
|
newRecord.setLastAuthorizedTime(new Date());
|
||||||
|
newRecord.setStatus(1);
|
||||||
|
newRecord.setCreateTime(new Date());
|
||||||
|
newRecord.setUpdateTime(new Date());
|
||||||
|
|
||||||
|
int inserted = userNotificationAuthorizationMapper.insert(newRecord);
|
||||||
|
if (inserted > 0) {
|
||||||
|
log.info("成功创建授权记录: recordId={}", newRecord.getId());
|
||||||
|
return newRecord;
|
||||||
|
} else {
|
||||||
|
log.error("创建授权记录失败: memberId={}, templateId={}, scenicId={}", memberId, templateId, scenicId);
|
||||||
|
throw new RuntimeException("创建授权记录失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean consumeAuthorization(Long memberId, String templateId, Long scenicId) {
|
||||||
|
log.info("消费授权: memberId={}, templateId={}, scenicId={}", memberId, templateId, scenicId);
|
||||||
|
|
||||||
|
UserNotificationAuthorizationEntity record = userNotificationAuthorizationMapper
|
||||||
|
.selectByMemberAndTemplateAndScenic(memberId, templateId, scenicId);
|
||||||
|
|
||||||
|
if (record == null) {
|
||||||
|
log.warn("未找到授权记录: memberId={}, templateId={}, scenicId={}", memberId, templateId, scenicId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (record.getRemainingCount() <= 0) {
|
||||||
|
log.warn("剩余授权次数不足: recordId={}, remainingCount={}", record.getId(), record.getRemainingCount());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int updated = userNotificationAuthorizationMapper.increaseConsumedCount(record.getId(), 1);
|
||||||
|
if (updated > 0) {
|
||||||
|
log.info("成功消费授权: recordId={}, newConsumedCount={}", record.getId(),
|
||||||
|
record.getConsumedCount() + 1);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
log.error("消费授权失败: recordId={}", record.getId());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<UserNotificationAuthorizationEntity> getUserAuthorizations(Long memberId) {
|
||||||
|
log.debug("查询用户授权记录: memberId={}", memberId);
|
||||||
|
return userNotificationAuthorizationMapper.selectByMemberId(memberId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<UserNotificationAuthorizationEntity> getUserAuthorizationsByTemplate(Long memberId, String templateId) {
|
||||||
|
log.debug("查询用户模板授权记录: memberId={}, templateId={}", memberId, templateId);
|
||||||
|
return userNotificationAuthorizationMapper.selectByMemberIdAndTemplateId(memberId, templateId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<UserNotificationAuthorizationEntity> getScenicAuthorizations(Long scenicId) {
|
||||||
|
log.debug("查询景区授权记录: scenicId={}", scenicId);
|
||||||
|
return userNotificationAuthorizationMapper.selectByScenicId(scenicId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserNotificationAuthorizationEntity getById(Long id) {
|
||||||
|
log.debug("根据ID查询授权记录: id={}", id);
|
||||||
|
return userNotificationAuthorizationMapper.selectById(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
<?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.ycwl.basic.mapper.UserNotificationAuthorizationMapper">
|
||||||
|
|
||||||
|
<!-- 结果映射 -->
|
||||||
|
<resultMap id="BaseResultMap" type="com.ycwl.basic.model.pc.notify.entity.UserNotificationAuthorizationEntity">
|
||||||
|
<id column="id" property="id" jdbcType="BIGINT"/>
|
||||||
|
<result column="member_id" property="memberId" jdbcType="BIGINT"/>
|
||||||
|
<result column="template_id" property="templateId" jdbcType="VARCHAR"/>
|
||||||
|
<result column="scenic_id" property="scenicId" jdbcType="BIGINT"/>
|
||||||
|
<result column="authorization_count" property="authorizationCount" jdbcType="INTEGER"/>
|
||||||
|
<result column="consumed_count" property="consumedCount" jdbcType="INTEGER"/>
|
||||||
|
<result column="remaining_count" property="remainingCount" jdbcType="INTEGER"/>
|
||||||
|
<result column="last_authorized_time" property="lastAuthorizedTime" jdbcType="TIMESTAMP"/>
|
||||||
|
<result column="last_consumed_time" property="lastConsumedTime" jdbcType="TIMESTAMP"/>
|
||||||
|
<result column="status" property="status" jdbcType="TINYINT"/>
|
||||||
|
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
|
||||||
|
<result column="update_time" property="updateTime" jdbcType="TIMESTAMP"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<!-- 基础字段 -->
|
||||||
|
<sql id="Base_Column_List">
|
||||||
|
id, member_id, template_id, scenic_id, authorization_count, consumed_count,
|
||||||
|
remaining_count, last_authorized_time, last_consumed_time, status, create_time, update_time
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<!-- 根据用户ID、模板ID和景区ID查询授权记录 -->
|
||||||
|
<select id="selectByMemberAndTemplateAndScenic" resultMap="BaseResultMap">
|
||||||
|
SELECT
|
||||||
|
<include refid="Base_Column_List"/>
|
||||||
|
FROM user_notification_authorization
|
||||||
|
WHERE member_id = #{memberId}
|
||||||
|
AND template_id = #{templateId}
|
||||||
|
AND scenic_id = #{scenicId}
|
||||||
|
AND status = 1
|
||||||
|
LIMIT 1
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- 根据用户ID查询授权记录列表 -->
|
||||||
|
<select id="selectByMemberId" resultMap="BaseResultMap">
|
||||||
|
SELECT
|
||||||
|
<include refid="Base_Column_List"/>
|
||||||
|
FROM user_notification_authorization
|
||||||
|
WHERE member_id = #{memberId}
|
||||||
|
AND status = 1
|
||||||
|
ORDER BY create_time DESC
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- 根据用户ID和模板ID查询授权记录列表 -->
|
||||||
|
<select id="selectByMemberIdAndTemplateId" resultMap="BaseResultMap">
|
||||||
|
SELECT
|
||||||
|
<include refid="Base_Column_List"/>
|
||||||
|
FROM user_notification_authorization
|
||||||
|
WHERE member_id = #{memberId}
|
||||||
|
AND template_id = #{templateId}
|
||||||
|
AND status = 1
|
||||||
|
ORDER BY create_time DESC
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- 根据景区ID查询授权记录列表 -->
|
||||||
|
<select id="selectByScenicId" resultMap="BaseResultMap">
|
||||||
|
SELECT
|
||||||
|
<include refid="Base_Column_List"/>
|
||||||
|
FROM user_notification_authorization
|
||||||
|
WHERE scenic_id = #{scenicId}
|
||||||
|
AND status = 1
|
||||||
|
ORDER BY create_time DESC
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- 增加授权次数 -->
|
||||||
|
<update id="increaseAuthorizationCount">
|
||||||
|
UPDATE user_notification_authorization
|
||||||
|
SET authorization_count = authorization_count + #{count},
|
||||||
|
last_authorized_time = NOW(),
|
||||||
|
update_time = NOW()
|
||||||
|
WHERE id = #{id}
|
||||||
|
AND status = 1
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<!-- 增加消费次数 -->
|
||||||
|
<update id="increaseConsumedCount">
|
||||||
|
UPDATE user_notification_authorization
|
||||||
|
SET consumed_count = consumed_count + #{count},
|
||||||
|
last_consumed_time = NOW(),
|
||||||
|
update_time = NOW()
|
||||||
|
WHERE id = #{id}
|
||||||
|
AND status = 1
|
||||||
|
AND consumed_count + #{count} <= authorization_count
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<!-- 检查用户是否还有剩余授权次数 -->
|
||||||
|
<select id="selectRemainingCount" resultType="java.lang.Integer">
|
||||||
|
SELECT COALESCE(remaining_count, 0)
|
||||||
|
FROM user_notification_authorization
|
||||||
|
WHERE member_id = #{memberId}
|
||||||
|
AND template_id = #{templateId}
|
||||||
|
AND scenic_id = #{scenicId}
|
||||||
|
AND status = 1
|
||||||
|
AND remaining_count > 0
|
||||||
|
LIMIT 1
|
||||||
|
</select>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
Reference in New Issue
Block a user