feat: add community content and address APIs

This commit is contained in:
王鹏
2026-07-07 15:24:14 +08:00
parent 51e0f3a5ad
commit cad4bd3ea1
17 changed files with 1206 additions and 0 deletions

View File

@@ -0,0 +1,64 @@
package com.linhelp.notice;
import com.linhelp.common.api.ApiResponse;
import com.linhelp.common.security.AuthService;
import com.linhelp.common.security.CurrentUser;
import com.linhelp.common.security.RequireRole;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
import java.util.List;
@RestController
public class BannerController {
private final BannerService bannerService;
private final AuthService authService;
public BannerController(BannerService bannerService, AuthService authService) {
this.bannerService = bannerService;
this.authService = authService;
}
@RequireRole({"PLATFORM_ADMIN", "COMMUNITY_ADMIN"})
@GetMapping("/api/admin/banners")
public ApiResponse<List<BannerResponse>> adminList() {
CurrentUser user = authService.currentUser();
return ApiResponse.ok(bannerService.listAdmin(user.getCommunityId()));
}
@RequireRole({"PLATFORM_ADMIN", "COMMUNITY_ADMIN"})
@PostMapping("/api/admin/banners")
public ApiResponse<BannerResponse> create(@Valid @RequestBody BannerRequest request) {
CurrentUser user = authService.currentUser();
request.setTenantId(user.getTenantId());
request.setCommunityId(user.getCommunityId());
return ApiResponse.ok(bannerService.create(request));
}
@RequireRole({"PLATFORM_ADMIN", "COMMUNITY_ADMIN"})
@PutMapping("/api/admin/banners/{id}")
public ApiResponse<BannerResponse> update(@PathVariable Long id, @Valid @RequestBody BannerRequest request) {
CurrentUser user = authService.currentUser();
request.setTenantId(user.getTenantId());
request.setCommunityId(user.getCommunityId());
return ApiResponse.ok(bannerService.update(id, request));
}
@RequireRole({"PLATFORM_ADMIN", "COMMUNITY_ADMIN"})
@DeleteMapping("/api/admin/banners/{id}")
public ApiResponse<Void> delete(@PathVariable Long id) {
bannerService.delete(id);
return ApiResponse.ok();
}
@GetMapping("/api/mini/banners")
public ApiResponse<List<BannerResponse>> miniList() {
return ApiResponse.ok(bannerService.listEnabled(1L));
}
}

View File

@@ -0,0 +1,83 @@
package com.linhelp.notice;
import javax.validation.constraints.NotBlank;
public class BannerRequest {
private Long tenantId;
private Long communityId;
@NotBlank
private String title;
@NotBlank
private String imageUrl;
private String linkType;
private String linkValue;
private int sortNo;
private boolean enabled = true;
public Long getTenantId() {
return tenantId;
}
public void setTenantId(Long tenantId) {
this.tenantId = tenantId;
}
public Long getCommunityId() {
return communityId;
}
public void setCommunityId(Long communityId) {
this.communityId = communityId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getImageUrl() {
return imageUrl;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
public String getLinkType() {
return linkType;
}
public void setLinkType(String linkType) {
this.linkType = linkType;
}
public String getLinkValue() {
return linkValue;
}
public void setLinkValue(String linkValue) {
this.linkValue = linkValue;
}
public int getSortNo() {
return sortNo;
}
public void setSortNo(int sortNo) {
this.sortNo = sortNo;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}

View File

@@ -0,0 +1,85 @@
package com.linhelp.notice;
public class BannerResponse {
private Long id;
private Long tenantId;
private Long communityId;
private String title;
private String imageUrl;
private String linkType;
private String linkValue;
private int sortNo;
private boolean enabled;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getTenantId() {
return tenantId;
}
public void setTenantId(Long tenantId) {
this.tenantId = tenantId;
}
public Long getCommunityId() {
return communityId;
}
public void setCommunityId(Long communityId) {
this.communityId = communityId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getImageUrl() {
return imageUrl;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
public String getLinkType() {
return linkType;
}
public void setLinkType(String linkType) {
this.linkType = linkType;
}
public String getLinkValue() {
return linkValue;
}
public void setLinkValue(String linkValue) {
this.linkValue = linkValue;
}
public int getSortNo() {
return sortNo;
}
public void setSortNo(int sortNo) {
this.sortNo = sortNo;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}

View File

@@ -0,0 +1,81 @@
package com.linhelp.notice;
import com.linhelp.common.exception.BizException;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
@Service
public class BannerService {
private final AtomicLong ids = new AtomicLong(1L);
private final Map<Long, BannerResponse> banners = new LinkedHashMap<Long, BannerResponse>();
public synchronized BannerResponse create(BannerRequest request) {
BannerResponse banner = new BannerResponse();
banner.setId(ids.getAndIncrement());
copy(request, banner);
banners.put(banner.getId(), banner);
return banner;
}
public synchronized List<BannerResponse> listAdmin(Long communityId) {
List<BannerResponse> result = new ArrayList<BannerResponse>();
for (BannerResponse banner : banners.values()) {
if (communityId.equals(banner.getCommunityId())) {
result.add(banner);
}
}
return result;
}
public synchronized List<BannerResponse> listEnabled(Long communityId) {
List<BannerResponse> result = new ArrayList<BannerResponse>();
for (BannerResponse banner : banners.values()) {
if (communityId.equals(banner.getCommunityId()) && banner.isEnabled()) {
result.add(banner);
}
}
Collections.sort(result, new Comparator<BannerResponse>() {
@Override
public int compare(BannerResponse left, BannerResponse right) {
return Integer.compare(left.getSortNo(), right.getSortNo());
}
});
return result;
}
public synchronized BannerResponse update(Long id, BannerRequest request) {
BannerResponse banner = require(id);
copy(request, banner);
return banner;
}
public synchronized void delete(Long id) {
banners.remove(id);
}
private BannerResponse require(Long id) {
BannerResponse banner = banners.get(id);
if (banner == null) {
throw new BizException(404, "Banner不存在");
}
return banner;
}
private void copy(BannerRequest request, BannerResponse banner) {
banner.setTenantId(request.getTenantId());
banner.setCommunityId(request.getCommunityId());
banner.setTitle(request.getTitle());
banner.setImageUrl(request.getImageUrl());
banner.setLinkType(request.getLinkType());
banner.setLinkValue(request.getLinkValue());
banner.setSortNo(request.getSortNo());
banner.setEnabled(request.isEnabled());
}
}

View File

@@ -0,0 +1,79 @@
package com.linhelp.notice;
import com.linhelp.common.api.ApiResponse;
import com.linhelp.common.security.AuthService;
import com.linhelp.common.security.CurrentUser;
import com.linhelp.common.security.RequireRole;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
import java.util.List;
@RestController
public class NoticeController {
private final NoticeService noticeService;
private final AuthService authService;
public NoticeController(NoticeService noticeService, AuthService authService) {
this.noticeService = noticeService;
this.authService = authService;
}
@RequireRole({"PLATFORM_ADMIN", "COMMUNITY_ADMIN"})
@GetMapping("/api/admin/notices")
public ApiResponse<List<NoticeResponse>> adminList() {
CurrentUser user = authService.currentUser();
return ApiResponse.ok(noticeService.listAdmin(user.getCommunityId()));
}
@RequireRole({"PLATFORM_ADMIN", "COMMUNITY_ADMIN"})
@PostMapping("/api/admin/notices")
public ApiResponse<NoticeResponse> create(@Valid @RequestBody NoticeRequest request) {
CurrentUser user = authService.currentUser();
request.setTenantId(user.getTenantId());
request.setCommunityId(user.getCommunityId());
return ApiResponse.ok(noticeService.create(request));
}
@RequireRole({"PLATFORM_ADMIN", "COMMUNITY_ADMIN"})
@PutMapping("/api/admin/notices/{id}")
public ApiResponse<NoticeResponse> update(@PathVariable Long id, @Valid @RequestBody NoticeRequest request) {
return ApiResponse.ok(noticeService.update(id, request));
}
@RequireRole({"PLATFORM_ADMIN", "COMMUNITY_ADMIN"})
@PutMapping("/api/admin/notices/{id}/publish")
public ApiResponse<NoticeResponse> publish(@PathVariable Long id) {
return ApiResponse.ok(noticeService.publish(id));
}
@RequireRole({"PLATFORM_ADMIN", "COMMUNITY_ADMIN"})
@PutMapping("/api/admin/notices/{id}/offline")
public ApiResponse<NoticeResponse> offline(@PathVariable Long id) {
return ApiResponse.ok(noticeService.offline(id));
}
@RequireRole({"PLATFORM_ADMIN", "COMMUNITY_ADMIN"})
@DeleteMapping("/api/admin/notices/{id}")
public ApiResponse<Void> delete(@PathVariable Long id) {
noticeService.delete(id);
return ApiResponse.ok();
}
@GetMapping("/api/mini/notices")
public ApiResponse<List<NoticeResponse>> miniList() {
return ApiResponse.ok(noticeService.listPublished(1L));
}
@GetMapping("/api/mini/notices/{id}")
public ApiResponse<NoticeResponse> miniDetail(@PathVariable Long id) {
return ApiResponse.ok(noticeService.detail(id));
}
}

View File

@@ -0,0 +1,67 @@
package com.linhelp.notice;
import javax.validation.constraints.NotBlank;
public class NoticeRequest {
private Long tenantId;
private Long communityId;
@NotBlank
private String title;
@NotBlank
private String content;
@NotBlank
private String category;
private boolean pinned;
public Long getTenantId() {
return tenantId;
}
public void setTenantId(Long tenantId) {
this.tenantId = tenantId;
}
public Long getCommunityId() {
return communityId;
}
public void setCommunityId(Long communityId) {
this.communityId = communityId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public boolean isPinned() {
return pinned;
}
public void setPinned(boolean pinned) {
this.pinned = pinned;
}
}

View File

@@ -0,0 +1,87 @@
package com.linhelp.notice;
import java.time.LocalDateTime;
public class NoticeResponse {
private Long id;
private Long tenantId;
private Long communityId;
private String title;
private String content;
private String category;
private boolean pinned;
private String status;
private LocalDateTime publishedAt;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getTenantId() {
return tenantId;
}
public void setTenantId(Long tenantId) {
this.tenantId = tenantId;
}
public Long getCommunityId() {
return communityId;
}
public void setCommunityId(Long communityId) {
this.communityId = communityId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public boolean isPinned() {
return pinned;
}
public void setPinned(boolean pinned) {
this.pinned = pinned;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public LocalDateTime getPublishedAt() {
return publishedAt;
}
public void setPublishedAt(LocalDateTime publishedAt) {
this.publishedAt = publishedAt;
}
}

View File

@@ -0,0 +1,122 @@
package com.linhelp.notice;
import com.linhelp.common.exception.BizException;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
@Service
public class NoticeService {
public static final String STATUS_DRAFT = "DRAFT";
public static final String STATUS_PUBLISHED = "PUBLISHED";
public static final String STATUS_OFFLINE = "OFFLINE";
private final AtomicLong ids = new AtomicLong(1L);
private final Map<Long, NoticeResponse> notices = new LinkedHashMap<Long, NoticeResponse>();
public synchronized NoticeResponse create(NoticeRequest request) {
NoticeResponse notice = new NoticeResponse();
notice.setId(ids.getAndIncrement());
notice.setTenantId(request.getTenantId());
notice.setCommunityId(request.getCommunityId());
copy(request, notice);
notice.setStatus(STATUS_DRAFT);
notices.put(notice.getId(), notice);
return notice;
}
public synchronized List<NoticeResponse> listAdmin(Long communityId) {
List<NoticeResponse> result = new ArrayList<NoticeResponse>();
for (NoticeResponse notice : notices.values()) {
if (communityId.equals(notice.getCommunityId())) {
result.add(notice);
}
}
return result;
}
public synchronized NoticeResponse update(Long id, NoticeRequest request) {
NoticeResponse notice = require(id);
copy(request, notice);
return notice;
}
public synchronized NoticeResponse publish(Long id) {
NoticeResponse notice = require(id);
notice.setStatus(STATUS_PUBLISHED);
notice.setPublishedAt(LocalDateTime.now());
return notice;
}
public synchronized NoticeResponse offline(Long id) {
NoticeResponse notice = require(id);
notice.setStatus(STATUS_OFFLINE);
return notice;
}
public synchronized void delete(Long id) {
notices.remove(id);
}
public synchronized NoticeResponse detail(Long id) {
return require(id);
}
public synchronized List<NoticeResponse> listPublished(Long communityId) {
List<NoticeResponse> result = new ArrayList<NoticeResponse>();
for (NoticeResponse notice : notices.values()) {
if (communityId.equals(notice.getCommunityId()) && STATUS_PUBLISHED.equals(notice.getStatus())) {
result.add(notice);
}
}
Collections.sort(result, new Comparator<NoticeResponse>() {
@Override
public int compare(NoticeResponse left, NoticeResponse right) {
if (left.isPinned() != right.isPinned()) {
return left.isPinned() ? -1 : 1;
}
LocalDateTime leftTime = left.getPublishedAt();
LocalDateTime rightTime = right.getPublishedAt();
if (leftTime == null && rightTime == null) {
return 0;
}
if (leftTime == null) {
return 1;
}
if (rightTime == null) {
return -1;
}
return rightTime.compareTo(leftTime);
}
});
return result;
}
private NoticeResponse require(Long id) {
NoticeResponse notice = notices.get(id);
if (notice == null) {
throw new BizException(404, "公告不存在");
}
return notice;
}
private void copy(NoticeRequest request, NoticeResponse notice) {
notice.setTitle(request.getTitle());
notice.setContent(request.getContent());
notice.setCategory(request.getCategory());
notice.setPinned(request.isPinned());
if (request.getTenantId() != null) {
notice.setTenantId(request.getTenantId());
}
if (request.getCommunityId() != null) {
notice.setCommunityId(request.getCommunityId());
}
}
}