新增家族动态功能

This commit is contained in:
tianfeng 2025-12-26 15:11:41 +08:00
parent 3b97886fab
commit 5563f3efbc
18 changed files with 693 additions and 2 deletions

View File

@ -158,6 +158,14 @@ public class FamilyRestController extends BaseController {
return familyService.familyHomeList(cmd);
}
/**
* 家族动态列表
*/
@GetMapping("/news/list")
public PageResult<FamilyNewsCO> familyNewsList(FamilyNewsListCmd cmd) {
return familyService.familyNewsList(cmd);
}
/**
* 家族在线房间.
*

View File

@ -3,12 +3,18 @@ package com.red.circle.other.app.command.family;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.other.app.dto.cmd.family.FamilyGrantUserRoleCmd;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.infra.common.family.FamilyCommon;
import com.red.circle.other.infra.common.family.FamilyNewsRecorder;
import com.red.circle.other.infra.database.rds.entity.family.FamilyMemberInfo;
import com.red.circle.other.infra.database.rds.service.family.FamilyMemberInfoService;
import com.red.circle.other.infra.enums.family.FamilyNewsTypeEnum;
import com.red.circle.other.infra.enums.family.FamilyRoleEnum;
import com.red.circle.other.inner.asserts.FamilyErrorCode;
import java.util.Objects;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
@ -20,6 +26,8 @@ import org.springframework.stereotype.Component;
public class FamilyGrantUserRoleExe {
private final FamilyCommon familyCommon;
private final FamilyNewsRecorder familyNewsRecorder;
private final UserProfileGateway userProfileGateway;
private final FamilyMemberInfoService familyMemberInfoService;
public void execute(FamilyGrantUserRoleCmd cmd) {
@ -39,7 +47,37 @@ public class FamilyGrantUserRoleExe {
validateBusinessRules(cmd, operator);
String oldRole = target.getMemberRole();
familyMemberInfoService.updateRoleById(cmd.getAuthorizedMemberId(), cmd.getRoleKey());
UserProfile userProfile = userProfileGateway.getByUserId(target.getMemberUserId());
String targetNickname = Optional.ofNullable(userProfile).map(UserProfile::getUserNickname).orElse(null);
FamilyNewsTypeEnum newsType = determineNewsType(oldRole, cmd.getRoleKey());
if (newsType != null) {
familyNewsRecorder.recordAndUpdateNotice(
cmd.getReqSysOrigin().getOrigin(),
operator.getFamilyId(),
newsType,
operator.getMemberUserId(),
null,
target.getMemberUserId(),
targetNickname
);
}
}
/**
* 根据旧角色和新角色确定动态类型
*/
private FamilyNewsTypeEnum determineNewsType(String oldRole, String newRole) {
if (FamilyRoleEnum.MEMBER.getKey().equals(oldRole) && FamilyRoleEnum.MANAGE.getKey().equals(newRole)) {
return FamilyNewsTypeEnum.MEMBER_PROMOTED_ADMIN;
}
if (FamilyRoleEnum.MANAGE.getKey().equals(oldRole) && FamilyRoleEnum.MEMBER.getKey().equals(newRole)) {
return FamilyNewsTypeEnum.MEMBER_DEMOTED;
}
return null;
}
/**

View File

@ -8,11 +8,13 @@ import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.other.app.dto.cmd.family.FamilyInfoEditCmd;
import com.red.circle.other.infra.common.family.FamilyCommon;
import com.red.circle.other.infra.common.family.FamilyNewsRecorder;
import com.red.circle.other.infra.database.rds.entity.family.FamilyBaseInfo;
import com.red.circle.other.infra.database.rds.entity.family.FamilyMemberInfo;
import com.red.circle.other.infra.database.rds.service.approval.ApprovalUserSettingDataService;
import com.red.circle.other.infra.database.rds.service.family.FamilyBaseInfoService;
import com.red.circle.other.infra.database.rds.service.family.FamilyMemberInfoService;
import com.red.circle.other.infra.enums.family.FamilyNewsTypeEnum;
import com.red.circle.other.inner.asserts.DynamicErrorCode;
import com.red.circle.other.inner.asserts.FamilyErrorCode;
import com.red.circle.tool.core.text.StringUtils;
@ -32,6 +34,7 @@ import org.springframework.stereotype.Component;
public class FamilyInfoEditExe {
private final FamilyCommon familyCommon;
private final FamilyNewsRecorder familyNewsRecorder;
private final OssServiceClient ossServiceClient;
private final FamilyBaseInfoService familyBaseInfoService;
private final FamilyMemberInfoService familyMemberInfoService;
@ -60,8 +63,22 @@ public class FamilyInfoEditExe {
FamilyBaseInfo baseInfo = familyBaseInfoService.getBaseInfoById(manageMember.getFamilyId());
ResponseAssert.notNull(FamilyErrorCode.NOT_EXIST_FAMILY_INFO_DATA, baseInfo);
boolean noticeChanged = StringUtils.isNotBlank(cmd.getFamilyNotice());
familyBaseInfoService.updateSelectiveById(getFamilyBaseInfo(cmd, manageMember.getFamilyId()));
FamilyNewsTypeEnum newsType = noticeChanged
? FamilyNewsTypeEnum.FAMILY_NOTICE_EDIT
: FamilyNewsTypeEnum.FAMILY_INFO_EDIT;
familyNewsRecorder.recordAndUpdateNotice(
cmd.getReqSysOrigin().getOrigin(),
manageMember.getFamilyId(),
newsType,
manageMember.getMemberUserId(),
null,
null,
null
);
}
private FamilyBaseInfo getFamilyBaseInfo(FamilyInfoEditCmd cmd, Long familyId) {

View File

@ -7,15 +7,18 @@ import com.red.circle.external.inner.model.enums.message.OfficialNoticeTypeEnum;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.other.app.dto.cmd.family.FamilyMessageHandleCmd;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.domain.propcoupon.PropCoupon;
import com.red.circle.other.domain.propcoupon.PropCouponType;
import com.red.circle.other.infra.common.family.FamilyCommon;
import com.red.circle.other.infra.common.family.FamilyNewsRecorder;
import com.red.circle.other.infra.database.rds.entity.family.FamilyMemberInfo;
import com.red.circle.other.infra.database.rds.entity.family.FamilyMessage;
import com.red.circle.other.infra.database.rds.service.family.FamilyMemberInfoService;
import com.red.circle.other.infra.database.rds.service.family.FamilyMessageService;
import com.red.circle.other.infra.enums.family.FamilyMsgBusinessEnum;
import com.red.circle.other.infra.enums.family.FamilyNewsTypeEnum;
import com.red.circle.other.infra.enums.family.FamilyRoleEnum;
import com.red.circle.other.inner.asserts.FamilyErrorCode;
import com.red.circle.other.inner.enums.FamilyMessageStatusEnum;
@ -41,6 +44,8 @@ import org.springframework.transaction.annotation.Transactional;
public class FamilyMessageHandleExe {
private final FamilyCommon familyCommon;
private final FamilyNewsRecorder familyNewsRecorder;
private final UserProfileGateway userProfileGateway;
private final OfficialNoticeClient officialNoticeClient;
private final FamilyMessageService familyMessageService;
private final FamilyMemberInfoService familyMemberInfoService;
@ -150,6 +155,19 @@ public class FamilyMessageHandleExe {
.setMemberUserId(userId)
.setMemberRole(FamilyRoleEnum.MEMBER.name())
);
UserProfile userProfile = userProfileGateway.getByUserId(userId);
String userNickname = Optional.ofNullable(userProfile).map(UserProfile::getUserNickname).orElse(null);
familyNewsRecorder.recordAndUpdateNotice(
sysOrigin,
familyId,
FamilyNewsTypeEnum.MEMBER_JOIN,
null,
null,
userId,
userNickname
);
// familyCommon.addGroup(familyId, userId);
}

View File

@ -0,0 +1,69 @@
package com.red.circle.other.app.command.family;
import com.red.circle.framework.dto.PageResult;
import com.red.circle.other.app.dto.clientobject.family.FamilyNewsCO;
import com.red.circle.other.app.dto.cmd.family.FamilyNewsListCmd;
import com.red.circle.other.infra.database.rds.entity.family.FamilyMemberInfo;
import com.red.circle.other.infra.database.rds.entity.family.FamilyNews;
import com.red.circle.other.infra.database.rds.service.family.FamilyMemberInfoService;
import com.red.circle.other.infra.database.rds.service.family.FamilyNewsService;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.TimestampUtils;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
/**
* 家族动态列表查询
*/
@Component
@RequiredArgsConstructor
public class FamilyNewsListExe {
private final FamilyNewsService familyNewsService;
public PageResult<FamilyNewsCO> execute(FamilyNewsListCmd cmd) {
List<FamilyNews> newsList = familyNewsService.listByFamilyId(
cmd.getFamilyId(),
100
);
if (CollectionUtils.isEmpty(newsList)) {
return PageResult.newPageResult(0);
}
int pageNo = cmd.getCursor();
int pageSize = cmd.getLimit();
int fromIndex = (pageNo - 1) * pageSize;
int toIndex = Math.min(fromIndex + pageSize, newsList.size());
PageResult<FamilyNewsCO> pageResult = PageResult.newPageResult(fromIndex, toIndex, newsList.size());
if (fromIndex >= newsList.size()) {
return pageResult;
}
List<FamilyNewsCO> resultList = newsList.subList(fromIndex, toIndex).stream()
.map(this::convertToCO)
.toList();
pageResult.setRecords(resultList);
return pageResult;
}
private FamilyNewsCO convertToCO(FamilyNews news) {
return new FamilyNewsCO()
.setId(news.getId())
.setNewsType(news.getNewsType())
.setOperatorId(news.getOperatorId())
.setOperatorName(news.getOperatorName())
.setTargetUserId(news.getTargetUserId())
.setTargetUserName(news.getTargetUserName())
.setContent(news.getContent())
.setCreateTime(news.getCreateTime().toString());
}
}

View File

@ -3,10 +3,15 @@ package com.red.circle.other.app.command.family;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.other.app.dto.cmd.family.FamilyRemoveUserCmd;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.infra.common.family.FamilyCommon;
import com.red.circle.other.infra.common.family.FamilyNewsRecorder;
import com.red.circle.other.infra.database.rds.entity.family.FamilyMemberInfo;
import com.red.circle.other.infra.database.rds.service.family.FamilyMemberInfoService;
import com.red.circle.other.infra.enums.family.FamilyNewsTypeEnum;
import java.util.Objects;
import java.util.Optional;
import com.red.circle.other.inner.asserts.FamilyErrorCode;
import lombok.RequiredArgsConstructor;
@ -27,6 +32,8 @@ import org.springframework.stereotype.Component;
public class FamilyRemoveUserExe {
private final FamilyCommon familyCommon;
private final FamilyNewsRecorder familyNewsRecorder;
private final UserProfileGateway userProfileGateway;
private final FamilyMemberInfoService familyMemberInfoService;
public void execute(FamilyRemoveUserCmd cmd) {
@ -44,12 +51,12 @@ public class FamilyRemoveUserExe {
Objects.equals(member.getMemberUserId(), manageMember.getMemberUserId()));
if (isAdmin(manageMember)) {
familyCommon.removeFamilyUser(member);
removeUserAndRecordNews(member, manageMember, cmd, FamilyNewsTypeEnum.MEMBER_KICKED_ADMIN);
return;
}
if (isAllowUpdate(manageMember, member)) {
familyCommon.removeFamilyUser(member);
removeUserAndRecordNews(member, manageMember, cmd, FamilyNewsTypeEnum.MEMBER_KICKED_MANAGE);
return;
}
@ -57,6 +64,24 @@ public class FamilyRemoveUserExe {
}
private void removeUserAndRecordNews(FamilyMemberInfo member, FamilyMemberInfo operator, FamilyRemoveUserCmd cmd,
FamilyNewsTypeEnum newsType) {
UserProfile userProfile = userProfileGateway.getByUserId(member.getMemberUserId());
String targetNickname = Optional.ofNullable(userProfile).map(UserProfile::getUserNickname).orElse(null);
familyCommon.removeFamilyUser(member);
familyNewsRecorder.recordAndUpdateNotice(
cmd.getReqSysOrigin().getOrigin(),
operator.getFamilyId(),
newsType,
operator.getMemberUserId(),
null,
member.getMemberUserId(),
targetNickname
);
}
private Boolean getExistFamilyByUserId(FamilyRemoveUserCmd cmd) {
return familyCommon.isExistFamilyByUserId(cmd.getReqUserId());
}

View File

@ -2,13 +2,19 @@ package com.red.circle.other.app.command.family;
import com.red.circle.common.business.dto.cmd.AppExtCommand;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.infra.common.family.FamilyCommon;
import com.red.circle.other.infra.common.family.FamilyNewsRecorder;
import com.red.circle.other.infra.database.rds.entity.family.FamilyMemberInfo;
import com.red.circle.other.infra.database.rds.service.family.FamilyMemberInfoService;
import com.red.circle.other.infra.enums.family.FamilyNewsTypeEnum;
import com.red.circle.other.inner.asserts.FamilyErrorCode;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import java.util.Optional;
/**
* <p>
* 用户退出所在家族.
@ -22,6 +28,8 @@ import org.springframework.stereotype.Component;
public class FamilyUserExitExe {
private final FamilyCommon familyCommon;
private final FamilyNewsRecorder familyNewsRecorder;
private final UserProfileGateway userProfileGateway;
private final FamilyMemberInfoService familyMemberInfoService;
public void execute(AppExtCommand cmd) {
@ -33,8 +41,20 @@ public class FamilyUserExitExe {
ResponseAssert.isFalse(FamilyErrorCode.FOUNDER_NOT_ALLOWED_EXIT_FAMILY,
isAdmin(familyMemberInfo));
UserProfile userProfile = userProfileGateway.getByUserId(familyMemberInfo.getMemberUserId());
String userNickname = Optional.ofNullable(userProfile).map(UserProfile::getUserNickname).orElse(null);
familyCommon.removeFamilyUser(familyMemberInfo);
familyNewsRecorder.recordAndUpdateNotice(
cmd.getReqSysOrigin().getOrigin(),
familyMemberInfo.getFamilyId(),
FamilyNewsTypeEnum.MEMBER_LEFT,
null,
null,
familyMemberInfo.getMemberUserId(),
userNickname
);
}
private boolean isAdmin(FamilyMemberInfo familyMemberInfo) {

View File

@ -33,6 +33,7 @@ import com.red.circle.other.app.command.family.FamilyBoxContributeExe;
import com.red.circle.other.app.command.family.FamilyBoxClaimExe;
import com.red.circle.other.app.command.family.FamilyHomeListExe;
import com.red.circle.other.app.command.family.FamilyMemberTop100Exe;
import com.red.circle.other.app.command.family.FamilyNewsListExe;
import com.red.circle.other.app.dto.clientobject.family.*;
import com.red.circle.other.app.dto.clientobject.room.RoomVoiceProfileCO;
import com.red.circle.other.app.dto.cmd.family.*;
@ -89,6 +90,7 @@ public class FamilyServiceImpl implements FamilyService {
private final FamilyBoxClaimExe familyBoxClaimExe;
private final FamilyHomeListExe familyHomeListExe;
private final FamilyMemberTop100Exe familyMemberTop100Exe;
private final FamilyNewsListExe familyNewsListExe;
private final DistributedLockUtil distributedLockUtil;
@Override
@ -269,4 +271,9 @@ public class FamilyServiceImpl implements FamilyService {
public PageResult<FamilyHomeListCO> familyHomeList(FamilyHomeListCmd cmd) {
return familyHomeListExe.execute(cmd);
}
@Override
public PageResult<FamilyNewsCO> familyNewsList(FamilyNewsListCmd cmd) {
return familyNewsListExe.execute(cmd);
}
}

View File

@ -0,0 +1,61 @@
package com.red.circle.other.app.dto.clientobject.family;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import java.io.Serializable;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 家族动态CO
*/
@Data
@Accessors(chain = true)
public class FamilyNewsCO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 动态ID
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
/**
* 动态类型
*/
private String newsType;
/**
* 操作人用户ID
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long operatorId;
/**
* 操作人昵称
*/
private String operatorName;
/**
* 目标用户ID
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long targetUserId;
/**
* 目标用户昵称
*/
private String targetUserName;
/**
* 动态内容文本
*/
private String content;
/**
* 创建时间
*/
private String createTime;
}

View File

@ -0,0 +1,19 @@
package com.red.circle.other.app.dto.cmd.family;
import com.red.circle.common.business.dto.cmd.AppExtCommand;
import com.red.circle.framework.dto.PageQuery;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 家族动态列表查询
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class FamilyNewsListCmd extends PageQuery {
private static final long serialVersionUID = 1L;
private Long familyId;
}

View File

@ -175,4 +175,9 @@ public interface FamilyService {
* 家族首页列表.
*/
PageResult<FamilyHomeListCO> familyHomeList(FamilyHomeListCmd cmd);
/**
* 家族动态列表.
*/
PageResult<FamilyNewsCO> familyNewsList(FamilyNewsListCmd cmd);
}

View File

@ -0,0 +1,71 @@
package com.red.circle.other.infra.common.family;
import com.red.circle.other.infra.database.rds.entity.family.FamilyBaseInfo;
import com.red.circle.other.infra.database.rds.entity.family.FamilyNews;
import com.red.circle.other.infra.database.rds.service.family.FamilyBaseInfoService;
import com.red.circle.other.infra.database.rds.service.family.FamilyNewsService;
import com.red.circle.other.infra.enums.family.FamilyNewsTypeEnum;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* 家族动态记录通用服务
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class FamilyNewsRecorder {
private final FamilyNewsService familyNewsService;
private final FamilyBaseInfoService familyBaseInfoService;
/**
* 记录家族动态并更新家族公告
*/
public void recordAndUpdateNotice(
String sysOrigin,
Long familyId,
FamilyNewsTypeEnum newsType,
Long operatorId,
String operatorName,
Long targetUserId,
String targetUserName
) {
familyNewsService.recordNews(
sysOrigin,
familyId,
newsType,
operatorId,
operatorName,
targetUserId,
targetUserName
);
updateFamilyNotice(familyId, newsType);
}
/**
* 更新家族公告为最新动态
*/
private void updateFamilyNotice(Long familyId, FamilyNewsTypeEnum newsType) {
try {
FamilyNews latestNews = familyNewsService.getLatestNews(familyId);
if (Objects.isNull(latestNews)) {
return;
}
if (newsType == FamilyNewsTypeEnum.FAMILY_INFO_EDIT || newsType == FamilyNewsTypeEnum.FAMILY_NOTICE_EDIT) {
return ;
}
familyBaseInfoService.updateSelectiveById(new FamilyBaseInfo()
.setId(familyId)
.setFamilyNotice(latestNews.getContent())
);
} catch (Exception e) {
log.error("更新家族公告失败, familyId:{}, error:{}", familyId, e.getMessage());
}
}
}

View File

@ -0,0 +1,11 @@
package com.red.circle.other.infra.database.rds.dao.family;
import com.red.circle.framework.mybatis.dao.BaseDAO;
import com.red.circle.other.infra.database.rds.entity.family.FamilyNews;
/**
* 家族动态 DAO
*/
public interface FamilyNewsDAO extends BaseDAO<FamilyNews> {
}

View File

@ -0,0 +1,88 @@
package com.red.circle.other.infra.database.rds.entity.family;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.red.circle.framework.mybatis.entity.TimestampBaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
/**
* 家族动态记录
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("family_news")
public class FamilyNews {
private static final long serialVersionUID = 1L;
/**
* 主键标识
*/
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
/**
* 来源系统
*/
@TableField("sys_origin")
private String sysOrigin;
/**
* 家族ID
*/
@TableField("family_id")
private Long familyId;
/**
* 动态类型
*/
@TableField("news_type")
private String newsType;
/**
* 操作人用户ID
*/
@TableField("operator_id")
private Long operatorId;
/**
* 操作人昵称
*/
@TableField("operator_name")
private String operatorName;
/**
* 目标用户ID
*/
@TableField("target_user_id")
private Long targetUserId;
/**
* 目标用户昵称
*/
@TableField("target_user_name")
private String targetUserName;
/**
* 动态内容文本
*/
@TableField("content")
private String content;
/**
* 额外数据JSON
*/
@TableField("extra_data")
private String extraData;
@TableField("create_time")
private LocalDateTime createTime;
}

View File

@ -0,0 +1,40 @@
package com.red.circle.other.infra.database.rds.service.family;
import com.red.circle.framework.mybatis.service.BaseService;
import com.red.circle.other.infra.database.rds.entity.family.FamilyNews;
import com.red.circle.other.infra.enums.family.FamilyNewsTypeEnum;
import java.util.List;
/**
* 家族动态服务
*/
public interface FamilyNewsService extends BaseService<FamilyNews> {
/**
* 记录家族动态
*/
void recordNews(
String sysOrigin,
Long familyId,
FamilyNewsTypeEnum newsType,
Long operatorId,
String operatorName,
Long targetUserId,
String targetUserName
);
/**
* 查询家族动态列表最新100条
*/
List<FamilyNews> listByFamilyId(Long familyId, Integer limit);
/**
* 获取最新一条动态
*/
FamilyNews getLatestNews(Long familyId);
/**
* 删除家族所有动态
*/
void deleteByFamilyId(Long familyId);
}

View File

@ -0,0 +1,117 @@
package com.red.circle.other.infra.database.rds.service.family.impl;
import com.red.circle.framework.mybatis.constant.PageConstant;
import com.red.circle.framework.mybatis.service.impl.BaseServiceImpl;
import com.red.circle.other.infra.database.rds.dao.family.FamilyNewsDAO;
import com.red.circle.other.infra.database.rds.entity.family.FamilyNews;
import com.red.circle.other.infra.database.rds.service.family.FamilyNewsService;
import com.red.circle.other.infra.enums.family.FamilyNewsTypeEnum;
import com.red.circle.tool.core.collection.CollectionUtils;
import java.util.List;
import java.util.Objects;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* 家族动态服务实现
*/
@Slf4j
@Service
public class FamilyNewsServiceImpl extends
BaseServiceImpl<FamilyNewsDAO, FamilyNews> implements FamilyNewsService {
@Override
public void recordNews(
String sysOrigin,
Long familyId,
FamilyNewsTypeEnum newsType,
Long operatorId,
String operatorName,
Long targetUserId,
String targetUserName
) {
try {
String content = newsType.generateContent(targetUserName);
FamilyNews news = new FamilyNews()
.setSysOrigin(sysOrigin)
.setFamilyId(familyId)
.setNewsType(newsType.getCode())
.setOperatorId(operatorId)
.setOperatorName(operatorName)
.setTargetUserId(targetUserId)
.setTargetUserName(targetUserName)
.setContent(content);
super.save(news);
cleanOldNews(familyId);
} catch (Exception e) {
log.error("记录家族动态失败, familyId:{}, newsType:{}, error:{}",
familyId, newsType.getCode(), e.getMessage(), e);
}
}
@Override
public List<FamilyNews> listByFamilyId(Long familyId, Integer limit) {
if (Objects.isNull(familyId)) {
return List.of();
}
int pageSize = Objects.nonNull(limit) && limit > 0 ? limit : 100;
return query()
.eq(FamilyNews::getFamilyId, familyId)
.orderByDesc(FamilyNews::getCreateTime)
.last("LIMIT " + pageSize)
.list();
}
@Override
public FamilyNews getLatestNews(Long familyId) {
if (Objects.isNull(familyId)) {
return null;
}
return query()
.eq(FamilyNews::getFamilyId, familyId)
.orderByDesc(FamilyNews::getCreateTime)
.last(PageConstant.LIMIT_ONE)
.getOne();
}
@Override
public void deleteByFamilyId(Long familyId) {
if (Objects.isNull(familyId)) {
return;
}
delete().eq(FamilyNews::getFamilyId, familyId).execute();
}
/**
* 清理旧动态保留最新100条
*/
private void cleanOldNews(Long familyId) {
try {
List<FamilyNews> allNews = query()
.eq(FamilyNews::getFamilyId, familyId)
.orderByDesc(FamilyNews::getCreateTime)
.list();
if (CollectionUtils.isEmpty(allNews) || allNews.size() <= 100) {
return;
}
List<Long> idsToDelete = allNews.stream()
.skip(100)
.map(FamilyNews::getId)
.toList();
if (CollectionUtils.isNotEmpty(idsToDelete)) {
delete().in(FamilyNews::getId, idsToDelete).execute();
}
} catch (Exception e) {
log.error("清理家族旧动态失败, familyId:{}, error:{}", familyId, e.getMessage());
}
}
}

View File

@ -0,0 +1,72 @@
package com.red.circle.other.infra.enums.family;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
* 家族动态类型枚举
*/
@Getter
@RequiredArgsConstructor
public enum FamilyNewsTypeEnum {
/**
* 成员加入家族
*/
MEMBER_JOIN("MEMBER_JOIN", "[{targetUserName}] joined the family."),
/**
* 成员被授权为管理员
*/
MEMBER_PROMOTED_ADMIN("MEMBER_PROMOTED_ADMIN", "[{targetUserName}] become an admin."),
/**
* 成员被取消管理员
*/
MEMBER_DEMOTED("MEMBER_DEMOTED", "[{targetUserName}] was removed from admin."),
/**
* 成员被族长踢出家族
*/
MEMBER_KICKED_ADMIN("MEMBER_KICKED", "[{targetUserName}] has been removed from the family by the family owner."),
/**
* 成员被管理员踢出家族
*/
MEMBER_KICKED_MANAGE("MEMBER_KICKED", "[{targetUserName}] has been removed from the family by the family owner."),
/**
* 成员主动退出
*/
MEMBER_LEFT("MEMBER_LEFT", "[{targetUserName}] has left the family."),
/**
* 家族资料修改
*/
FAMILY_INFO_EDIT("FAMILY_INFO_EDIT", "Family information has been updated."),
/**
* 家族公告修改
*/
FAMILY_NOTICE_EDIT("FAMILY_NOTICE_EDIT", "The family announcement has been updated.");
private final String code;
private final String template;
/**
* 生成动态文本
*/
public String generateContent(String targetUserName) {
if (this == FAMILY_INFO_EDIT || this == FAMILY_NOTICE_EDIT) {
return template;
}
String displayName = targetUserName;
if (targetUserName != null && targetUserName.length() > 12) {
displayName = targetUserName.substring(0, 12) + "[...]";
}
return template.replace("{targetUserName}", displayName != null ? displayName : "");
}
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.red.circle.other.infra.database.rds.dao.family.FamilyNewsDAO">
</mapper>