From 5563f3efbcf8104ef6056d8ab41a2f100b8683bb Mon Sep 17 00:00:00 2001 From: tianfeng <769204422@qq.com> Date: Fri, 26 Dec 2025 15:11:41 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=AE=B6=E6=97=8F=E5=8A=A8?= =?UTF-8?q?=E6=80=81=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/family/FamilyRestController.java | 8 ++ .../family/FamilyGrantUserRoleExe.java | 38 ++++++ .../app/command/family/FamilyInfoEditExe.java | 17 +++ .../family/FamilyMessageHandleExe.java | 18 +++ .../app/command/family/FamilyNewsListExe.java | 69 +++++++++++ .../command/family/FamilyRemoveUserExe.java | 29 ++++- .../app/command/family/FamilyUserExitExe.java | 20 +++ .../app/service/family/FamilyServiceImpl.java | 7 ++ .../dto/clientobject/family/FamilyNewsCO.java | 61 +++++++++ .../app/dto/cmd/family/FamilyNewsListCmd.java | 19 +++ .../app/service/family/FamilyService.java | 5 + .../common/family/FamilyNewsRecorder.java | 71 +++++++++++ .../rds/dao/family/FamilyNewsDAO.java | 11 ++ .../rds/entity/family/FamilyNews.java | 88 +++++++++++++ .../rds/service/family/FamilyNewsService.java | 40 ++++++ .../family/impl/FamilyNewsServiceImpl.java | 117 ++++++++++++++++++ .../enums/family/FamilyNewsTypeEnum.java | 72 +++++++++++ .../resources/dao/family/FamilyNewsDAO.xml | 5 + 18 files changed, 693 insertions(+), 2 deletions(-) create mode 100644 rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/family/FamilyNewsListExe.java create mode 100644 rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/family/FamilyNewsCO.java create mode 100644 rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/family/FamilyNewsListCmd.java create mode 100644 rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/common/family/FamilyNewsRecorder.java create mode 100644 rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/family/FamilyNewsDAO.java create mode 100644 rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/family/FamilyNews.java create mode 100644 rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/family/FamilyNewsService.java create mode 100644 rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/family/impl/FamilyNewsServiceImpl.java create mode 100644 rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/enums/family/FamilyNewsTypeEnum.java create mode 100644 rc-service/rc-service-other/other-infrastructure/src/main/resources/dao/family/FamilyNewsDAO.xml diff --git a/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/family/FamilyRestController.java b/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/family/FamilyRestController.java index dedf553d..7832dbf1 100644 --- a/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/family/FamilyRestController.java +++ b/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/family/FamilyRestController.java @@ -158,6 +158,14 @@ public class FamilyRestController extends BaseController { return familyService.familyHomeList(cmd); } + /** + * 家族动态列表 + */ + @GetMapping("/news/list") + public PageResult familyNewsList(FamilyNewsListCmd cmd) { + return familyService.familyNewsList(cmd); + } + /** * 家族在线房间. * diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/family/FamilyGrantUserRoleExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/family/FamilyGrantUserRoleExe.java index 85992f42..50af33c8 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/family/FamilyGrantUserRoleExe.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/family/FamilyGrantUserRoleExe.java @@ -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; } /** diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/family/FamilyInfoEditExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/family/FamilyInfoEditExe.java index 0353b669..6609d779 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/family/FamilyInfoEditExe.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/family/FamilyInfoEditExe.java @@ -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) { diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/family/FamilyMessageHandleExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/family/FamilyMessageHandleExe.java index 7fe3ae8c..e3cac6da 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/family/FamilyMessageHandleExe.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/family/FamilyMessageHandleExe.java @@ -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); } diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/family/FamilyNewsListExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/family/FamilyNewsListExe.java new file mode 100644 index 00000000..01d27d18 --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/family/FamilyNewsListExe.java @@ -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 execute(FamilyNewsListCmd cmd) { + List 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 pageResult = PageResult.newPageResult(fromIndex, toIndex, newsList.size()); + + if (fromIndex >= newsList.size()) { + return pageResult; + } + + List 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()); + } +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/family/FamilyRemoveUserExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/family/FamilyRemoveUserExe.java index 3e7ad4b8..f030992a 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/family/FamilyRemoveUserExe.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/family/FamilyRemoveUserExe.java @@ -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()); } diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/family/FamilyUserExitExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/family/FamilyUserExitExe.java index 4a00c7cd..5a70ec5f 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/family/FamilyUserExitExe.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/family/FamilyUserExitExe.java @@ -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; + /** *

* 用户退出所在家族. @@ -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) { diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/family/FamilyServiceImpl.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/family/FamilyServiceImpl.java index 453831dd..33cae890 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/family/FamilyServiceImpl.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/family/FamilyServiceImpl.java @@ -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 familyHomeList(FamilyHomeListCmd cmd) { return familyHomeListExe.execute(cmd); } + + @Override + public PageResult familyNewsList(FamilyNewsListCmd cmd) { + return familyNewsListExe.execute(cmd); + } } diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/family/FamilyNewsCO.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/family/FamilyNewsCO.java new file mode 100644 index 00000000..6a4da5ae --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/family/FamilyNewsCO.java @@ -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; + +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/family/FamilyNewsListCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/family/FamilyNewsListCmd.java new file mode 100644 index 00000000..755652eb --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/family/FamilyNewsListCmd.java @@ -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; + +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/family/FamilyService.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/family/FamilyService.java index 723a92c2..cbc8d101 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/family/FamilyService.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/family/FamilyService.java @@ -175,4 +175,9 @@ public interface FamilyService { * 家族首页列表. */ PageResult familyHomeList(FamilyHomeListCmd cmd); + + /** + * 家族动态列表. + */ + PageResult familyNewsList(FamilyNewsListCmd cmd); } diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/common/family/FamilyNewsRecorder.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/common/family/FamilyNewsRecorder.java new file mode 100644 index 00000000..45508611 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/common/family/FamilyNewsRecorder.java @@ -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()); + } + } +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/family/FamilyNewsDAO.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/family/FamilyNewsDAO.java new file mode 100644 index 00000000..2aad3721 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/family/FamilyNewsDAO.java @@ -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 { + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/family/FamilyNews.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/family/FamilyNews.java new file mode 100644 index 00000000..ec21ed5e --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/family/FamilyNews.java @@ -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; + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/family/FamilyNewsService.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/family/FamilyNewsService.java new file mode 100644 index 00000000..31c7a8dc --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/family/FamilyNewsService.java @@ -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 { + + /** + * 记录家族动态 + */ + void recordNews( + String sysOrigin, + Long familyId, + FamilyNewsTypeEnum newsType, + Long operatorId, + String operatorName, + Long targetUserId, + String targetUserName + ); + + /** + * 查询家族动态列表(最新100条) + */ + List listByFamilyId(Long familyId, Integer limit); + + /** + * 获取最新一条动态 + */ + FamilyNews getLatestNews(Long familyId); + + /** + * 删除家族所有动态 + */ + void deleteByFamilyId(Long familyId); +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/family/impl/FamilyNewsServiceImpl.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/family/impl/FamilyNewsServiceImpl.java new file mode 100644 index 00000000..d05c9f17 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/family/impl/FamilyNewsServiceImpl.java @@ -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 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 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 allNews = query() + .eq(FamilyNews::getFamilyId, familyId) + .orderByDesc(FamilyNews::getCreateTime) + .list(); + + if (CollectionUtils.isEmpty(allNews) || allNews.size() <= 100) { + return; + } + + List 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()); + } + } +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/enums/family/FamilyNewsTypeEnum.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/enums/family/FamilyNewsTypeEnum.java new file mode 100644 index 00000000..c71af50b --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/enums/family/FamilyNewsTypeEnum.java @@ -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 : ""); + } +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/resources/dao/family/FamilyNewsDAO.xml b/rc-service/rc-service-other/other-infrastructure/src/main/resources/dao/family/FamilyNewsDAO.xml new file mode 100644 index 00000000..c7c70243 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/resources/dao/family/FamilyNewsDAO.xml @@ -0,0 +1,5 @@ + + + + +