diff --git a/luoo_common/src/main/java/enums/MembershipEnums.java b/luoo_common/src/main/java/enums/MembershipEnums.java new file mode 100644 index 0000000..f7aadc5 --- /dev/null +++ b/luoo_common/src/main/java/enums/MembershipEnums.java @@ -0,0 +1,33 @@ +package enums; + +import lombok.Getter; + +/** + * @Author: yawei.huang + * @Package: enums + * @Project: luoo_parent + * @Date: 2024/7/19 20:09 + * @Filename: MembershipEnums + * @Describe: + */ +@Getter +public enum MembershipEnums { + CREATED(1, "已生成"), + BIND(2, "已绑定"), + REFUND(3, "已退款"), + DISCARD(4, "已废弃"), + + + + + + ; + private final Integer code; + private final String description; + + MembershipEnums(int code, String description) { + this.code = code; + this.description = description; + } + +} diff --git a/luoo_common/src/main/java/enums/UserVipStatusEnum.java b/luoo_common/src/main/java/enums/UserVipStatusEnum.java new file mode 100644 index 0000000..d24ee3d --- /dev/null +++ b/luoo_common/src/main/java/enums/UserVipStatusEnum.java @@ -0,0 +1,29 @@ +package enums; + +import lombok.Getter; + +/** + * @Author: yawei.huang + * @Package: enums + * @Project: luoo_parent + * @Date: 2024/7/19 20:31 + * @Filename: UserVipStatusEnum + * @Describe: 用户会员状态 + */ +@Getter +public enum UserVipStatusEnum { + + INITIAL(0, "未开通"), + ACTIVE(1, "生效中"), + EXPIRED(2, "已过期"), + + ; + + private final Integer code; + private final String description; + + UserVipStatusEnum(int code, String description) { + this.code = code; + this.description = description; + } +} diff --git a/luoo_music/src/main/java/com/luoo/music/dto/response/RandomTopicDTO.java b/luoo_music/src/main/java/com/luoo/music/dto/response/RandomTopicDTO.java index 31e86e5..e468051 100644 --- a/luoo_music/src/main/java/com/luoo/music/dto/response/RandomTopicDTO.java +++ b/luoo_music/src/main/java/com/luoo/music/dto/response/RandomTopicDTO.java @@ -1,6 +1,7 @@ package com.luoo.music.dto.response; import java.io.Serializable; +import java.util.List; import lombok.AllArgsConstructor; import lombok.Data; @@ -11,4 +12,5 @@ public class RandomTopicDTO implements Serializable { private static final long serialVersionUID = 1L; private int id; private String name; + private List gifList; // 随机gif列表 } diff --git a/luoo_music/src/main/java/com/luoo/music/service/JournalSongService.java b/luoo_music/src/main/java/com/luoo/music/service/JournalSongService.java index 4a91d67..2ad990c 100644 --- a/luoo_music/src/main/java/com/luoo/music/service/JournalSongService.java +++ b/luoo_music/src/main/java/com/luoo/music/service/JournalSongService.java @@ -61,8 +61,9 @@ public class JournalSongService { Integer id=Integer.valueOf(segs[0]); String name=segs[1]; List tags=Arrays.stream(segs[2].split(",")).collect(Collectors.toList()); + List gifList=Arrays.stream(segs[3].split(",")).collect(Collectors.toList()); List journalNos=getJournalNoByTags(tags); - randomTopicDTOs.add(new RandomTopicDTO(id,name)); + randomTopicDTOs.add(new RandomTopicDTO(id,name,gifList)); topicJournalMap.put(id, journalNos); }); } @@ -221,6 +222,7 @@ public class JournalSongService { } public List getRandomTopic() { + return randomTopicDTOs; } diff --git a/luoo_music/src/main/resources/topic.txt b/luoo_music/src/main/resources/topic.txt index 8d23e0d..51478c6 100644 --- a/luoo_music/src/main/resources/topic.txt +++ b/luoo_music/src/main/resources/topic.txt @@ -1,5 +1,5 @@ -1|力量之源|金属,朋克,说唱,摇滚 -2|靡靡之音|民谣,流行,爵士,乡村,蓝调,雷鬼 -3|情绪之下|后摇,世界音乐,古典,原声,口哨,轻音乐 -4|黑暗之舞|暗潮,仙音,新民谣,黑暗民谣 -5|节奏之魂|电子 \ No newline at end of file +0|自由畅听|金属,朋克,说唱,摇滚,民谣,流行,爵士,乡村,蓝调,雷鬼,后摇,世界音乐,古典,原声,口哨,轻音乐,暗潮,仙音,新民谣,黑暗民谣,电子|https://cdn2.indie.cn/indie/media/0/1.webp +1|黑暗低语|暗潮,仙音,新民谣,黑暗民谣|https://cdn2.indie.cn/indie/media/1/1.webp,https://cdn2.indie.cn/indie/media/1/2.webp,https://cdn2.indie.cn/indie/media/1/3.webp,https://cdn2.indie.cn/indie/media/1/4.webp,https://cdn2.indie.cn/indie/media/1/5.webp +2|心灵之舞|后摇,世界音乐,古典,原声,口哨,轻音乐|https://cdn2.indie.cn/indie/media/2/1.webp,https://cdn2.indie.cn/indie/media/2/2.webp +3|暮色余晖|民谣,流行,爵士,乡村,蓝调,雷鬼|https://cdn2.indie.cn/indie/media/3/1.webp,https://cdn2.indie.cn/indie/media/3/2.webp,https://cdn2.indie.cn/indie/media/3/3.webp,https://cdn2.indie.cn/indie/media/3/4.webp,https://cdn2.indie.cn/indie/media/3/5.webp,https://cdn2.indie.cn/indie/media/3/6.webp +4|不羁之音|金属,朋克,说唱,摇滚|https://cdn2.indie.cn/indie/media/4/1.webp,https://cdn2.indie.cn/indie/media/4/2.webp,https://cdn2.indie.cn/indie/media/4/3.webp \ No newline at end of file diff --git a/luoo_user/src/main/java/com/luoo/user/controller/MembershipController.java b/luoo_user/src/main/java/com/luoo/user/controller/MembershipController.java new file mode 100644 index 0000000..7843d26 --- /dev/null +++ b/luoo_user/src/main/java/com/luoo/user/controller/MembershipController.java @@ -0,0 +1,54 @@ +package com.luoo.user.controller; + +import annotation.GlobalInterceptor; +import api.Result; +import com.luoo.user.service.MembershipCodeService; +import controller.BaseController; +import io.swagger.annotations.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.constraints.NotNull; + +/** + * @Author: yawei.huang + * @Package: com.luoo.user.controller + * @Project: luoo_parent + * @Date: 2024/7/19 19:51 + * @Filename: MembershipController + * @Describe: + */ +@RestController +@Slf4j +@RequestMapping("/membership") +@Api(tags = "会员模块") +public class MembershipController extends BaseController { + + @Autowired + private MembershipCodeService membershipCodeService; + + @ApiOperation(value = "1.生成会员码", notes = "仅限admin权限用户调用") + @GetMapping("/code/generate") + @GlobalInterceptor(checkAdminLogin = true) + @ApiImplicitParams(value = { + @ApiImplicitParam(name = "duration", value = "会员时长(天)", required = true, dataType = "Integer", paramType = "query") + }) + public Result generateMembershipCode(@RequestHeader(value = "Authorization", required = true) String authorization, + @NotNull Integer duration) { + return Result.success(membershipCodeService.generateMembershipCode(authorization, duration)); + } + + + @ApiOperation(value = "2.绑定会员码", notes = "仅限app用户调用") + @PostMapping("/code/bind") + @GlobalInterceptor(checkAppUserLogin = true) + @ApiImplicitParams(value = { + @ApiImplicitParam(name = "code", value = "会员码", required = true, dataType = "String", paramType = "query") + }) + public Result bindMembershipCode(@RequestHeader(value = "Authorization", required = true) String authorization, + @NotNull String code) { + membershipCodeService.bindMembershipCode(authorization, code); + return Result.success(); + } +} diff --git a/luoo_user/src/main/java/com/luoo/user/dao/MembershipCodeDao.java b/luoo_user/src/main/java/com/luoo/user/dao/MembershipCodeDao.java new file mode 100644 index 0000000..2624342 --- /dev/null +++ b/luoo_user/src/main/java/com/luoo/user/dao/MembershipCodeDao.java @@ -0,0 +1,18 @@ +package com.luoo.user.dao; + +import com.luoo.user.pojo.MembershipCode; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** + * @Author: yawei.huang + * @Package: com.luoo.user.dao + * @Project: luoo_parent + * @Date: 2024/7/19 19:53 + * @Filename: MembershipCodeDao + * @Describe: + */ +public interface MembershipCodeDao extends JpaRepository, JpaSpecificationExecutor { + + public MembershipCode findMembershipCodeByCodeAndStatus(String code, Integer status); +} diff --git a/luoo_user/src/main/java/com/luoo/user/pojo/MembershipCode.java b/luoo_user/src/main/java/com/luoo/user/pojo/MembershipCode.java new file mode 100644 index 0000000..e104b20 --- /dev/null +++ b/luoo_user/src/main/java/com/luoo/user/pojo/MembershipCode.java @@ -0,0 +1,75 @@ +package com.luoo.user.pojo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import org.hibernate.annotations.DynamicInsert; +import org.hibernate.annotations.DynamicUpdate; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.persistence.*; +import javax.validation.constraints.Size; +import java.io.Serializable; +import java.time.Instant; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode +@Builder +@Entity +@DynamicInsert +@DynamicUpdate +@Table(name = "tb_membership_code") +@EntityListeners(AuditingEntityListener.class) +public class MembershipCode implements Serializable { + @Id + @Size(max = 20) + @Column(name = "id", nullable = false, length = 20) + @ApiModelProperty(value = "主键") + private String id; + + @Size(max = 50) + @Column(name = "code", length = 50) + @ApiModelProperty(value = "会员码") + private String code; + + @Column(name = "status") + @ApiModelProperty(value = "状态 1-已生成 2-已绑定 3-已退款 4-已废弃") + private Integer status; + + @Column(name = "duration") + @ApiModelProperty(value = "时长") + private Integer duration; + + @Size(max = 20) + @Column(name = "user_id", length = 20) + @ApiModelProperty(value = "用户id") + private String userId; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @ApiModelProperty("创建时间") + @CreatedDate + private Instant createTime; + + @ApiModelProperty("修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @LastModifiedDate + private Instant updateTime; + + @Size(max = 20) + @Column(name = "create_user", length = 20) + @ApiModelProperty(value = "创建人") + private String createUser; + + @Size(max = 20) + @Column(name = "update_user", length = 20) + @ApiModelProperty(value = "更新人") + private String updateUser; + +} \ No newline at end of file diff --git a/luoo_user/src/main/java/com/luoo/user/pojo/UserInfo.java b/luoo_user/src/main/java/com/luoo/user/pojo/UserInfo.java index 2f63d33..d05ee8a 100644 --- a/luoo_user/src/main/java/com/luoo/user/pojo/UserInfo.java +++ b/luoo_user/src/main/java/com/luoo/user/pojo/UserInfo.java @@ -1,15 +1,17 @@ package com.luoo.user.pojo; +import java.util.Date; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + import com.fasterxml.jackson.annotation.JsonFormat; import com.luoo.user.util.EmojiConverterUtil; import lombok.*; import org.springframework.format.annotation.DateTimeFormat; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; import java.io.Serializable; -import java.util.Date; @Getter @@ -186,6 +188,18 @@ public class UserInfo implements Serializable { * 用户type */ private Integer type; - + + /** + * 会员状态 0-未开通 1-生效中 2-已过期 + */ + private Integer vipStatus; + + /** + * 会员到期时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") + @DateTimeFormat(pattern = "yyyy-MM-dd") + private LocalDate vipExpireTime; + } diff --git a/luoo_user/src/main/java/com/luoo/user/pojo/UserPointLog.java b/luoo_user/src/main/java/com/luoo/user/pojo/UserPointLog.java new file mode 100644 index 0000000..99109b2 --- /dev/null +++ b/luoo_user/src/main/java/com/luoo/user/pojo/UserPointLog.java @@ -0,0 +1,75 @@ +package com.luoo.user.pojo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import org.hibernate.annotations.DynamicInsert; +import org.hibernate.annotations.DynamicUpdate; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.persistence.*; +import javax.validation.constraints.Size; +import java.io.Serializable; +import java.time.Instant; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode +@Builder +@Entity +@DynamicInsert +@DynamicUpdate +@Table(name = "tb_user_point_log") +@EntityListeners(AuditingEntityListener.class) +public class UserPointLog implements Serializable { + @Id + @Size(max = 20) + @Column(name = "id", nullable = false, length = 20) + @ApiModelProperty(value = "主键") + private String id; + + @Column(name = "score") + @ApiModelProperty(value = "积分") + private Integer score; + + @Column(name = "type") + @ApiModelProperty(value = "类型 1-增加 2-减少") + private Integer type; + + @Size(max = 20) + @Column(name = "user_id", length = 20) + @ApiModelProperty(value = "用户id") + private String userId; + + @Size(max = 255) + @Column(name = "description") + @ApiModelProperty(value = "事件描述") + private String description; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @ApiModelProperty("创建时间") + @CreatedDate + private Instant createTime; + + @ApiModelProperty("修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @LastModifiedDate + private Instant updateTime; + + @Size(max = 20) + @Column(name = "create_user", length = 20) + @ApiModelProperty(value = "创建人") + private String createUser; + + @Size(max = 20) + @Column(name = "update_user", length = 20) + @ApiModelProperty(value = "更新人") + private String updateUser; + +} \ No newline at end of file diff --git a/luoo_user/src/main/java/com/luoo/user/service/MembershipCodeService.java b/luoo_user/src/main/java/com/luoo/user/service/MembershipCodeService.java new file mode 100644 index 0000000..e55b45d --- /dev/null +++ b/luoo_user/src/main/java/com/luoo/user/service/MembershipCodeService.java @@ -0,0 +1,110 @@ +package com.luoo.user.service; + +import com.luoo.user.dao.MembershipCodeDao; +import com.luoo.user.dao.UserInfoDao; +import com.luoo.user.pojo.MembershipCode; +import com.luoo.user.pojo.UserInfo; +import dto.UserLoginDto; +import enums.MembershipEnums; +import enums.UserVipStatusEnum; +import exception.BizException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import util.IdWorker; +import util.JwtUtil; + +import java.time.LocalDate; +import java.util.Date; +import java.util.Objects; +import java.util.UUID; + +/** + * @Author: yawei.huang + * @Package: com.luoo.user.service + * @Project: luoo_parent + * @Date: 2024/7/19 19:52 + * @Filename: MembershipCodeService + * @Describe: + */ +@Service +@Slf4j +public class MembershipCodeService { + + private final MembershipCodeDao membershipCodeDao; + + private final IdWorker idWorker; + + private final JwtUtil jwtUtil; + + private final UserInfoDao userInfoDao; + + public MembershipCodeService(JwtUtil jwtUtil, IdWorker idWorker, MembershipCodeDao membershipCodeDao, UserInfoDao userInfoDao) { + this.jwtUtil = jwtUtil; + this.idWorker = idWorker; + this.membershipCodeDao = membershipCodeDao; + this.userInfoDao = userInfoDao; + } + + /** + * 创建会员码并保存 + * 会员码取UUID + * + * @param token token + * @param duration 会员时长(天) + * @return 会员码 + */ + @Transactional(rollbackFor = Exception.class) + public String generateMembershipCode(String token, Integer duration) { + UserLoginDto userLoginDto = jwtUtil.getUserLoginDto(token); + + // UUID作为会员码 + String code = UUID.randomUUID().toString(); + MembershipCode build = MembershipCode.builder() + .id(String.valueOf(idWorker.nextId())) + .code(code) + .status(MembershipEnums.CREATED.getCode()) + .duration(duration) + .createUser(userLoginDto.getUserId()) + .build(); + membershipCodeDao.save(build); + return code; + } + + /** + * 绑定会员码 + * + * @param token token + * @param code 会员码 + */ + @Transactional(rollbackFor = Exception.class) + public void bindMembershipCode(String token, String code) { + UserLoginDto userLoginDto = jwtUtil.getUserLoginDto(token); + MembershipCode membershipCode = membershipCodeDao.findMembershipCodeByCodeAndStatus(code, MembershipEnums.CREATED.getCode()); + if (membershipCode == null) { + throw new BizException("会员码不存在"); + } + // 处理会员码表 + membershipCode.setStatus(MembershipEnums.BIND.getCode()); + membershipCode.setUserId(userLoginDto.getUserId()); + membershipCode.setUpdateUser(userLoginDto.getUserId()); + membershipCodeDao.save(membershipCode); + + // 处理用户表 + UserInfo userInfo = userInfoDao.findById(userLoginDto.getUserId()).get(); + // 计算会员到期时间 + LocalDate vipExpireTime; + if(Objects.equals(UserVipStatusEnum.INITIAL.getCode(), userInfo.getVipStatus())){ + vipExpireTime = userInfo.getVipExpireTime().plusDays(membershipCode.getDuration()); + } else { + // 从今天开始,增加membershipCode的duration天 + userInfo.setVipStatus(UserVipStatusEnum.INITIAL.getCode()); + vipExpireTime = LocalDate.now().plusDays(membershipCode.getDuration()); + } + userInfo.setVipExpireTime(vipExpireTime); + // 无论如何当即设置为会员生效状态 + userInfo.setVipStatus(UserVipStatusEnum.ACTIVE.getCode()); + userInfoDao.save(userInfo); + + } +} diff --git a/luoo_user/src/main/resources/sql/2024-07-19.sql b/luoo_user/src/main/resources/sql/2024-07-19.sql new file mode 100644 index 0000000..e59b6b8 --- /dev/null +++ b/luoo_user/src/main/resources/sql/2024-07-19.sql @@ -0,0 +1,36 @@ +create table tb_membership_code +( + id varchar(20) not null comment 'id' + primary key, + code varchar(50) null comment '会员码', + status tinyint null comment '状态 1-已生成 2-已绑定 3-已退款 4-已废弃', + duration int null comment '会员时长(天)', + user_id varchar(20) null comment '使用用户', + create_time datetime null comment '创建时间', + update_time datetime null comment '修改时间', + create_user varchar(20) null comment '创建人', + update_user varchar(20) null comment '修改人' +) + comment '会员码'; + + +create table tb_user_point_log +( + id varchar(20) not null comment 'id' + primary key, + score int null comment '分数', + type tinyint null comment '1- 增加 2-减少', + user_id varchar(20) null comment '所属用户', + description varchar(255) null comment '事件描述', + create_time datetime null comment '创建时间', + update_time datetime null comment '修改时间', + create_user varchar(20) null comment '创建人', + update_user varchar(20) null comment '修改人' +) + comment '积分记录表'; + +alter table tb_user_info + add vip_status tinyint default 0 not null comment '会员状态 0-未开通 1-生效中 2-已过期'; + +alter table tb_user_info + add vip_expire_time date null comment '会员到期时间';