diff --git a/backend/src/main/java/com/openisle/model/NotificationType.java b/backend/src/main/java/com/openisle/model/NotificationType.java index 74262c9b2..6bf7c0224 100644 --- a/backend/src/main/java/com/openisle/model/NotificationType.java +++ b/backend/src/main/java/com/openisle/model/NotificationType.java @@ -46,6 +46,10 @@ public enum NotificationType { POLL_RESULT_OWNER, /** A poll you participated in has concluded */ POLL_RESULT_PARTICIPANT, + /** Your category proposal has concluded */ + CATEGORY_PROPOSAL_RESULT_OWNER, + /** A category proposal you participated in has concluded */ + CATEGORY_PROPOSAL_RESULT_PARTICIPANT, /** Your post was featured */ POST_FEATURED, /** Someone donated to your post */ diff --git a/backend/src/main/java/com/openisle/service/PostService.java b/backend/src/main/java/com/openisle/service/PostService.java index 4ff13c11e..7457c947c 100644 --- a/backend/src/main/java/com/openisle/service/PostService.java +++ b/backend/src/main/java/com/openisle/service/PostService.java @@ -70,6 +70,7 @@ public class PostService { private final PointService pointService; private final PostChangeLogService postChangeLogService; private final PointHistoryRepository pointHistoryRepository; + private final CategoryService categoryService; private final ConcurrentMap> scheduledFinalizations = new ConcurrentHashMap<>(); @@ -112,7 +113,8 @@ public class PostService { PointHistoryRepository pointHistoryRepository, @Value("${app.post.publish-mode:DIRECT}") PublishMode publishMode, RedisTemplate redisTemplate, - SearchIndexEventPublisher searchIndexEventPublisher + SearchIndexEventPublisher searchIndexEventPublisher, + CategoryService categoryService ) { this.postRepository = postRepository; this.userRepository = userRepository; @@ -141,6 +143,7 @@ public class PostService { this.redisTemplate = redisTemplate; this.searchIndexEventPublisher = searchIndexEventPublisher; + this.categoryService = categoryService; } @EventListener(ApplicationReadyEvent.class) @@ -429,8 +432,11 @@ public class PostService { boolean quorumMet = totalParticipants >= cp.getQuorum(); int approvePercent = totalParticipants > 0 ? (approveVotes * 100) / totalParticipants : 0; boolean thresholdMet = approvePercent >= cp.getApproveThreshold(); + boolean approved = false; + String rejectReason = null; if (quorumMet && thresholdMet) { cp.setProposalStatus(CategoryProposalStatus.APPROVED); + approved = true; } else { cp.setProposalStatus(CategoryProposalStatus.REJECTED); String reason; @@ -442,6 +448,7 @@ public class PostService { reason = "赞成率不足"; } cp.setRejectReason(reason); + rejectReason = reason; } cp.setResultSnapshot( "approveVotes=" + @@ -452,28 +459,37 @@ public class PostService { approvePercent ); categoryProposalPostRepository.save(cp); + if (approved) { + categoryService.createCategory(cp.getProposedName(), cp.getDescription(), "star", null); + } if (cp.getAuthor() != null) { notificationService.createNotification( cp.getAuthor(), - NotificationType.POLL_RESULT_OWNER, + NotificationType.CATEGORY_PROPOSAL_RESULT_OWNER, cp, null, + approved, null, null, - null, - null + approved ? null : rejectReason ); } for (User participant : cp.getParticipants()) { + if ( + cp.getAuthor() != null && + java.util.Objects.equals(participant.getId(), cp.getAuthor().getId()) + ) { + continue; + } notificationService.createNotification( participant, - NotificationType.POLL_RESULT_PARTICIPANT, + NotificationType.CATEGORY_PROPOSAL_RESULT_PARTICIPANT, cp, null, + approved, null, null, - null, - null + approved ? null : rejectReason ); } postChangeLogService.recordVoteResult(cp); @@ -576,6 +592,9 @@ public class PostService { pollPostRepository .findById(postId) .ifPresent(pp -> { + if (pp instanceof CategoryProposalPost) { + return; + } if (pp.isResultAnnounced()) { return; } diff --git a/frontend_nuxt/pages/index.vue b/frontend_nuxt/pages/index.vue index 10e106510..78a7160a7 100644 --- a/frontend_nuxt/pages/index.vue +++ b/frontend_nuxt/pages/index.vue @@ -1,10 +1,5 @@ + + @@ -775,6 +817,10 @@ const formatType = (t) => { return '发布的投票结果已公布' case 'POLL_RESULT_PARTICIPANT': return '参与的投票结果已公布' + case 'CATEGORY_PROPOSAL_RESULT_OWNER': + return '分类提案结果已公布' + case 'CATEGORY_PROPOSAL_RESULT_PARTICIPANT': + return '参与的分类提案结果已公布' default: return t } diff --git a/frontend_nuxt/utils/notification.js b/frontend_nuxt/utils/notification.js index 9d71e2a54..c13f1d9cd 100644 --- a/frontend_nuxt/utils/notification.js +++ b/frontend_nuxt/utils/notification.js @@ -28,6 +28,8 @@ const iconMap = { POLL_VOTE: 'ChartHistogram', POLL_RESULT_OWNER: 'RankingList', POLL_RESULT_PARTICIPANT: 'ChartLine', + CATEGORY_PROPOSAL_RESULT_OWNER: 'TagOne', + CATEGORY_PROPOSAL_RESULT_PARTICIPANT: 'TagOne', MENTION: 'HashtagKey', POST_DELETED: 'ClearIcon', POST_FEATURED: 'Star', @@ -254,7 +256,9 @@ function createFetchNotifications() { } else if ( n.type === 'POLL_VOTE' || n.type === 'POLL_RESULT_OWNER' || - n.type === 'POLL_RESULT_PARTICIPANT' + n.type === 'POLL_RESULT_PARTICIPANT' || + n.type === 'CATEGORY_PROPOSAL_RESULT_OWNER' || + n.type === 'CATEGORY_PROPOSAL_RESULT_PARTICIPANT' ) { arr.push({ ...n,