From c54540b11e666b1d315219035b1d6f029fe174aa Mon Sep 17 00:00:00 2001 From: zzy Date: Sat, 25 Apr 2026 12:23:10 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=8F=E5=8C=BA=E6=B4=BB=E5=8A=A8=E5=88=86?= =?UTF-8?q?=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../activity/CommunityActivityController.java | 229 +++++++++++ .../admin/activity/vo/ActivityPageReqVO.java | 37 ++ .../admin/activity/vo/ActivityRespVO.java | 104 +++++ .../admin/activity/vo/ActivitySaveReqVO.java | 82 ++++ .../AppCommunityActivityController.java | 187 +++++++++ .../app/activity/vo/AppActivityDetailVO.java | 78 ++++ .../activity/vo/AppActivityPageItemVO.java | 44 +++ .../app/activity/vo/AppActivityPageReqVO.java | 34 ++ .../vo/AppActivityRegistrationReqVO.java | 24 ++ .../vo/AppActivityRegistrationRespVO.java | 38 ++ .../app/activity/vo/AppActivityRespVO.java | 78 ++++ .../app/banner/AppBannerController.java | 2 + .../AppKnowledgeClassController.java | 2 + .../AppMiniAppConfigController.java | 2 + .../notice/AppCommunityNoticeController.java | 2 + .../app/post/AppCommunityPostController.java | 2 + .../activity/ActivityRegistrationDO.java | 69 ++++ .../dataobject/activity/ActivityScopeDO.java | 47 +++ .../activity/CommunityActivityDO.java | 124 ++++++ .../activity/ActivityRegistrationMapper.java | 46 +++ .../mysql/activity/ActivityScopeMapper.java | 86 +++++ .../activity/CommunityActivityMapper.java | 36 ++ .../community/enums/ErrorCodeConstants.java | 11 + .../activity/CommunityActivityService.java | 121 ++++++ .../CommunityActivityServiceImpl.java | 364 ++++++++++++++++++ 25 files changed, 1849 insertions(+) create mode 100644 fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/activity/CommunityActivityController.java create mode 100644 fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/activity/vo/ActivityPageReqVO.java create mode 100644 fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/activity/vo/ActivityRespVO.java create mode 100644 fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/activity/vo/ActivitySaveReqVO.java create mode 100644 fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/AppCommunityActivityController.java create mode 100644 fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/vo/AppActivityDetailVO.java create mode 100644 fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/vo/AppActivityPageItemVO.java create mode 100644 fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/vo/AppActivityPageReqVO.java create mode 100644 fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/vo/AppActivityRegistrationReqVO.java create mode 100644 fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/vo/AppActivityRegistrationRespVO.java create mode 100644 fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/vo/AppActivityRespVO.java create mode 100644 fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/dataobject/activity/ActivityRegistrationDO.java create mode 100644 fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/dataobject/activity/ActivityScopeDO.java create mode 100644 fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/dataobject/activity/CommunityActivityDO.java create mode 100644 fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/mysql/activity/ActivityRegistrationMapper.java create mode 100644 fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/mysql/activity/ActivityScopeMapper.java create mode 100644 fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/mysql/activity/CommunityActivityMapper.java create mode 100644 fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/service/activity/CommunityActivityService.java create mode 100644 fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/service/activity/CommunityActivityServiceImpl.java diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/activity/CommunityActivityController.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/activity/CommunityActivityController.java new file mode 100644 index 0000000..df581bb --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/activity/CommunityActivityController.java @@ -0,0 +1,229 @@ +package com.fjrcloud.community.module.community.controller.admin.activity; + +import com.fjrcloud.community.framework.apilog.core.annotation.ApiAccessLog; +import com.fjrcloud.community.framework.common.pojo.CommonResult; +import com.fjrcloud.community.framework.common.pojo.PageParam; +import com.fjrcloud.community.framework.common.pojo.PageResult; +import com.fjrcloud.community.framework.common.util.json.JsonUtils; +import com.fjrcloud.community.framework.common.util.object.BeanUtils; +import com.fjrcloud.community.framework.excel.core.util.ExcelUtils; +import com.fjrcloud.community.module.community.controller.admin.activity.vo.ActivityPageReqVO; +import com.fjrcloud.community.module.community.controller.admin.activity.vo.ActivityRespVO; +import com.fjrcloud.community.module.community.controller.admin.activity.vo.ActivitySaveReqVO; +import com.fjrcloud.community.module.community.dal.dataobject.activity.ActivityScopeDO; +import com.fjrcloud.community.module.community.dal.dataobject.activity.CommunityActivityDO; +import com.fjrcloud.community.module.community.dal.mysql.activity.ActivityScopeMapper; +import com.fjrcloud.community.module.community.service.activity.CommunityActivityService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; + +import static com.fjrcloud.community.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static com.fjrcloud.community.framework.common.pojo.CommonResult.success; + +/** + * 管理后台 - 小区活动 + * + * @author fjrcloud + */ +@Tag(name = "管理后台 - 小区活动") +@RestController +@RequestMapping("/community/activity") +@Validated +public class CommunityActivityController { + + @Resource + private CommunityActivityService communityActivityService; + + @Resource + private ActivityScopeMapper activityScopeMapper; + + @PostMapping("/create") + @Operation(summary = "创建小区活动") + @PreAuthorize("@ss.hasPermission('community:activity:create')") + public CommonResult createActivity(@Valid @RequestBody ActivitySaveReqVO createReqVO) { + return success(communityActivityService.createActivity(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新小区活动") + @PreAuthorize("@ss.hasPermission('community:activity:update')") + public CommonResult updateActivity(@Valid @RequestBody ActivitySaveReqVO updateReqVO) { + communityActivityService.updateActivity(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除小区活动") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('community:activity:delete')") + public CommonResult deleteActivity(@RequestParam("id") Long id) { + communityActivityService.deleteActivity(id); + return success(true); + } + + @DeleteMapping("/delete-list") + @Parameter(name = "ids", description = "编号", required = true) + @Operation(summary = "批量删除小区活动") + @PreAuthorize("@ss.hasPermission('community:activity:delete')") + public CommonResult deleteActivityList(@RequestParam("ids") List ids) { + communityActivityService.deleteActivityListByIds(ids); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得小区活动") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('community:activity:query')") + public CommonResult getActivity(@RequestParam("id") Long id) { + CommunityActivityDO activity = communityActivityService.getActivity(id); + ActivityRespVO respVO = BeanUtils.toBean(activity, ActivityRespVO.class); + + // 处理JSON字符串转列表 + if (activity.getBannerImages() != null) { + respVO.setBannerImages(JsonUtils.parseArray(activity.getBannerImages(), String.class)); + } + if (activity.getServiceCategories() != null) { + respVO.setServiceCategories(JsonUtils.parseArray(activity.getServiceCategories(), Integer.class)); + } + if (activity.getServiceTargets() != null) { + respVO.setServiceTargets(JsonUtils.parseArray(activity.getServiceTargets(), Integer.class)); + } + + // 查询发布范围 + List scopeList = activityScopeMapper.selectListByActivityId(id); + if (scopeList != null && !scopeList.isEmpty()) { + List communityIds = scopeList.stream() + .map(ActivityScopeDO::getCommunityId) + .collect(Collectors.toList()); + respVO.setCommunityIds(communityIds); + + List communityNames = scopeList.stream() + .map(ActivityScopeDO::getCommunityName) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + respVO.setCommunityNames(communityNames); + } + + return success(respVO); + } + + @GetMapping("/page") + @Operation(summary = "获得小区活动分页") + @PreAuthorize("@ss.hasPermission('community:activity:query')") + public CommonResult> getActivityPage(@Valid ActivityPageReqVO pageReqVO) { + PageResult pageResult = communityActivityService.getActivityPage(pageReqVO); + PageResult respVOPageResult = BeanUtils.toBean(pageResult, ActivityRespVO.class); + + List activityList = respVOPageResult.getList(); + if (activityList.isEmpty()) { + return success(respVOPageResult); + } + + // 收集所有活动ID,批量查询关联关系 + List activityIds = activityList.stream() + .map(ActivityRespVO::getId) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + // 批量查询所有活动的关联小区 + Map> activityScopeMap = new HashMap<>(); + if (!activityIds.isEmpty()) { + List allScopes = activityScopeMapper.selectListByActivityIds(activityIds); + activityScopeMap = allScopes.stream() + .collect(Collectors.groupingBy(ActivityScopeDO::getActivityId)); + } + + // 填充数据 + for (int i = 0; i < activityList.size(); i++) { + ActivityRespVO respVO = activityList.get(i); + CommunityActivityDO activity = pageResult.getList().get(i); + + try { + if (activity.getBannerImages() != null) { + respVO.setBannerImages(JsonUtils.parseArray(activity.getBannerImages(), String.class)); + } + } catch (Exception e) { + respVO.setBannerImages(new ArrayList<>()); + } + + try { + if (activity.getServiceCategories() != null) { + respVO.setServiceCategories(JsonUtils.parseArray(activity.getServiceCategories(), Integer.class)); + } + } catch (Exception e) { + respVO.setServiceCategories(new ArrayList<>()); + } + + try { + if (activity.getServiceTargets() != null) { + respVO.setServiceTargets(JsonUtils.parseArray(activity.getServiceTargets(), Integer.class)); + } + } catch (Exception e) { + respVO.setServiceTargets(new ArrayList<>()); + } + + // 从缓存的Map中获取关联小区,避免N+1查询 + List scopeList = activityScopeMap.getOrDefault(respVO.getId(), new ArrayList<>()); + if (!scopeList.isEmpty()) { + List communityIds = new ArrayList<>(scopeList.size()); + List communityNames = new ArrayList<>(scopeList.size()); + + // 一次遍历同时提取ID和名称 + for (ActivityScopeDO scope : scopeList) { + communityIds.add(scope.getCommunityId()); + if (scope.getCommunityName() != null) { + communityNames.add(scope.getCommunityName()); + } + } + + respVO.setCommunityIds(communityIds); + respVO.setCommunityNames(communityNames); + } + } + + return success(respVOPageResult); + } + + @PutMapping("/publish") + @Operation(summary = "发布活动") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('community:activity:publish')") + public CommonResult publishActivity(@RequestParam("id") Long id) { + communityActivityService.publishActivity(id); + return success(true); + } + + @PutMapping("/unpublish") + @Operation(summary = "下架活动") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('community:activity:unpublish')") + public CommonResult unpublishActivity(@RequestParam("id") Long id) { + communityActivityService.unpublishActivity(id); + return success(true); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出小区活动 Excel") + @PreAuthorize("@ss.hasPermission('community:activity:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportActivityExcel(@Valid ActivityPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = communityActivityService.getActivityPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "小区活动.xls", "数据", ActivityRespVO.class, + BeanUtils.toBean(list, ActivityRespVO.class)); + } + +} diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/activity/vo/ActivityPageReqVO.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/activity/vo/ActivityPageReqVO.java new file mode 100644 index 0000000..93e163f --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/activity/vo/ActivityPageReqVO.java @@ -0,0 +1,37 @@ +package com.fjrcloud.community.module.community.controller.admin.activity.vo; + +import com.fjrcloud.community.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static com.fjrcloud.community.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +/** + * 管理后台 - 小区活动分页 Request VO + * + * @author fjrcloud + */ +@Schema(description = "管理后台 - 小区活动分页 Request VO") +@Data +public class ActivityPageReqVO extends PageParam { + + @Schema(description = "活动标题", example = "春节联欢") + private String title; + + @Schema(description = "活动状态(0-草稿,1-报名中,2-报名截止,3-进行中,4-已结束)", example = "1") + private Integer status; + + @Schema(description = "活动开始时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] activityStartTime; + + @Schema(description = "小区ID", example = "1") + private Long communityId; + + @Schema(description = "是否显示", example = "false") + private Boolean isDisplay; + +} diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/activity/vo/ActivityRespVO.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/activity/vo/ActivityRespVO.java new file mode 100644 index 0000000..ba25b1e --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/activity/vo/ActivityRespVO.java @@ -0,0 +1,104 @@ +package com.fjrcloud.community.module.community.controller.admin.activity.vo; + +import cn.idev.excel.annotation.ExcelIgnoreUnannotated; +import cn.idev.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 管理后台 - 小区活动 Response VO + * + * @author fjrcloud + */ +@Schema(description = "管理后台 - 小区活动 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ActivityRespVO { + + @Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "活动标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "春节联欢晚会") + @ExcelProperty("活动标题") + private String title; + + @Schema(description = "活动简介(富文本)", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("活动简介") + private String content; + + @Schema(description = "封面图片URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://xxx.com/cover.jpg") + @ExcelProperty("封面图片") + private String coverImage; + + @Schema(description = "轮播图URL列表", example = "[\"https://xxx.com/banner1.jpg\"]") + private List bannerImages; + + @Schema(description = "服务类别(JSON数组)", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 2]") + private List serviceCategories; + + @Schema(description = "服务对象(JSON数组)", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 3]") + private List serviceTargets; + + @Schema(description = "报名开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("报名开始时间") + private LocalDateTime registrationStartTime; + + @Schema(description = "报名结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("报名结束时间") + private LocalDateTime registrationEndTime; + + @Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("活动开始时间") + private LocalDateTime activityStartTime; + + @Schema(description = "活动结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("活动结束时间") + private LocalDateTime activityEndTime; + + @Schema(description = "活动地点", requiredMode = Schema.RequiredMode.REQUIRED, example = "小区活动中心") + @ExcelProperty("活动地点") + private String location; + + @Schema(description = "人数上限", example = "100") + @ExcelProperty("人数上限") + private Integer maxParticipants; + + @Schema(description = "联系人", example = "张三") + @ExcelProperty("联系人") + private String contactPerson; + + @Schema(description = "联系电话", example = "13800138000") + @ExcelProperty("联系电话") + private String contactPhone; + + @Schema(description = "当前报名人数", example = "50") + @ExcelProperty("当前报名人数") + private Integer currentParticipants; + + @Schema(description = "活动状态(0-草稿,1-报名中,2-报名截止,3-进行中,4-已结束)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("活动状态") + private Integer status; + + @Schema(description = "浏览次数", example = "100") + @ExcelProperty("浏览次数") + private Integer viewCount; + + @Schema(description = "是否展示(0-隐藏,1-展示)", example = "true") + @ExcelProperty("是否展示") + private Boolean isDisplay; + + @Schema(description = "小区ID列表(发布范围)", example = "[1, 2, 3]") + private List communityIds; + + @Schema(description = "小区名称列表", example = "[\"阳光小区\", \"花园小区\"]") + private List communityNames; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/activity/vo/ActivitySaveReqVO.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/activity/vo/ActivitySaveReqVO.java new file mode 100644 index 0000000..fc851ea --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/admin/activity/vo/ActivitySaveReqVO.java @@ -0,0 +1,82 @@ +package com.fjrcloud.community.module.community.controller.admin.activity.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 管理后台 - 小区活动新增/修改 Request VO + * + * @author fjrcloud + */ +@Schema(description = "管理后台 - 小区活动新增/修改 Request VO") +@Data +public class ActivitySaveReqVO { + + @Schema(description = "活动编号", example = "1") + private Long id; + + @Schema(description = "活动标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "春节联欢晚会") + @NotEmpty(message = "活动标题不能为空") + private String title; + + @Schema(description = "活动简介(富文本)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "活动简介不能为空") + private String content; + + @Schema(description = "封面图片URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://xxx.com/cover.jpg") + @NotEmpty(message = "封面图片不能为空") + private String coverImage; + + @Schema(description = "轮播图URL列表", example = "[\"https://xxx.com/banner1.jpg\", \"https://xxx.com/banner2.jpg\"]") + private List bannerImages; + + @Schema(description = "服务类别(JSON数组,1-社区服务,2-敬老服务,3-助残服务,4-关爱儿童,5-环保宣传,6-文明礼仪,7-文化教育)", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 2]") + @NotNull(message = "服务类别不能为空") + private List serviceCategories; + + @Schema(description = "服务对象(JSON数组,1-儿童,2-孤寡老人,3-残障人士,4-优抚对象,5-其他)", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 3]") + @NotNull(message = "服务对象不能为空") + private List serviceTargets; + + @Schema(description = "报名开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "报名开始时间不能为空") + private LocalDateTime registrationStartTime; + + @Schema(description = "报名结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "报名结束时间不能为空") + private LocalDateTime registrationEndTime; + + @Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "活动开始时间不能为空") + private LocalDateTime activityStartTime; + + @Schema(description = "活动结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "活动结束时间不能为空") + private LocalDateTime activityEndTime; + + @Schema(description = "活动地点", requiredMode = Schema.RequiredMode.REQUIRED, example = "小区活动中心") + @NotEmpty(message = "活动地点不能为空") + private String location; + + @Schema(description = "人数上限", example = "100") + private Integer maxParticipants; + + @Schema(description = "联系人", example = "张三") + private String contactPerson; + + @Schema(description = "联系电话", example = "13800138000") + private String contactPhone; + + @Schema(description = "是否展示(0-隐藏,1-展示)", example = "true") + private Boolean isDisplay; + + @Schema(description = "小区ID列表(发布范围)", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 2, 3]") + @NotNull(message = "发布范围不能为空") + private List communityIds; + +} diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/AppCommunityActivityController.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/AppCommunityActivityController.java new file mode 100644 index 0000000..409332e --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/AppCommunityActivityController.java @@ -0,0 +1,187 @@ +package com.fjrcloud.community.module.community.controller.app.activity; + +import com.fjrcloud.community.framework.common.pojo.CommonResult; +import com.fjrcloud.community.framework.common.pojo.PageResult; +import com.fjrcloud.community.framework.common.util.json.JsonUtils; +import com.fjrcloud.community.framework.common.util.object.BeanUtils; +import com.fjrcloud.community.framework.security.core.util.SecurityFrameworkUtils; +import com.fjrcloud.community.module.community.controller.admin.activity.vo.ActivityPageReqVO; +import com.fjrcloud.community.module.community.controller.app.activity.vo.*; +import com.fjrcloud.community.module.community.dal.dataobject.activity.ActivityScopeDO; +import com.fjrcloud.community.module.community.dal.dataobject.activity.CommunityActivityDO; +import com.fjrcloud.community.module.community.dal.mysql.activity.ActivityScopeMapper; +import com.fjrcloud.community.module.community.service.activity.CommunityActivityService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.annotation.security.PermitAll; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import static com.fjrcloud.community.framework.common.pojo.CommonResult.success; + +/** + * 用户APP - 小区活动 + * + * @author fjrcloud + */ +@Tag(name = "用户APP - 小区活动") +@RestController +@RequestMapping("/community/activity") +@Validated +@Slf4j +public class AppCommunityActivityController { + + @Resource + private CommunityActivityService communityActivityService; + + @Resource + private ActivityScopeMapper activityScopeMapper; + + @GetMapping("/page") + @Operation(summary = "获取小区活动分页列表") + @PermitAll + public CommonResult> getActivityPage(@Validated AppActivityPageReqVO pageReqVO) { + // 复用管理后台的 PageReqVO + ActivityPageReqVO adminPageReqVO = new ActivityPageReqVO(); + adminPageReqVO.setPageNo(pageReqVO.getPageNo()); + adminPageReqVO.setPageSize(pageReqVO.getPageSize()); + adminPageReqVO.setTitle(pageReqVO.getTitle()); + adminPageReqVO.setCommunityId(pageReqVO.getCommunityId()); + adminPageReqVO.setActivityStartTime(pageReqVO.getActivityStartTime()); + // 只查询已发布且展示的活动 + adminPageReqVO.setIsDisplay(true); + + // 查询分页数据 + PageResult pageResult = communityActivityService.getActivityPage(adminPageReqVO); + return success(buildAppActivityPageResult(pageResult)); + } + + @GetMapping("/get") + @Operation(summary = "获取活动详情") + @Parameter(name = "id", description = "活动编号", required = true, example = "1024") + public CommonResult getActivity(@RequestParam("id") Long id) { + // 增加浏览次数 + communityActivityService.incrementViewCount(id); + + // 查询活动详情 + CommunityActivityDO activity = communityActivityService.getActivity(id); + return success(buildAppActivityDetailVO(activity)); + } + + @PostMapping("/registration") + @Operation(summary = "报名参加活动") + public CommonResult registerActivity(@Validated @RequestBody AppActivityRegistrationReqVO reqVO) { + Long memberId = SecurityFrameworkUtils.getLoginUserId(); + communityActivityService.registerActivity(memberId, reqVO.getActivityId(), reqVO.getRemark()); + return success(true); + } + + @GetMapping("/registration/page") + @Operation(summary = "获取我的报名记录分页") + public CommonResult> getMyRegistrationPage(@Validated AppActivityPageReqVO pageReqVO) { + Long memberId = SecurityFrameworkUtils.getLoginUserId(); + PageResult pageResult = communityActivityService.getMyRegistrationPage(memberId, pageReqVO); + return success(pageResult); + } + + @PostMapping("/registration/cancel") + @Operation(summary = "取消报名") + @Parameter(name = "id", description = "报名编号", required = true, example = "1024") + public CommonResult cancelRegistration(@RequestParam("id") Long id) { + Long memberId = SecurityFrameworkUtils.getLoginUserId(); + communityActivityService.cancelRegistration(memberId, id); + return success(true); + } + + /** + * 构建 App 端活动分页结果(精简版) + * + * @param pageResult 分页结果 + * @return App 端分页结果 + */ + private PageResult buildAppActivityPageResult(PageResult pageResult) { + // 直接转换,分页VO字段都是DO中已有的,不需要额外填充 + return BeanUtils.toBean(pageResult, AppActivityPageItemVO.class); + } + + /** + * 构建 App 端活动详情响应对象(完整版) + * + * @param activity 活动 DO + * @return App 端详情 VO + */ + private AppActivityDetailVO buildAppActivityDetailVO(CommunityActivityDO activity) { + AppActivityDetailVO respVO = BeanUtils.toBean(activity, AppActivityDetailVO.class); + fillAppActivityDetailVO(respVO, activity); + return respVO; + } + + /** + * 填充 App 端活动详情(完整版) + * + * @param respVO 响应 VO + * @param activity 活动 DO + */ + private void fillAppActivityDetailVO(AppActivityDetailVO respVO, CommunityActivityDO activity) { + // 处理JSON字符串转列表 + try { + if (activity.getBannerImages() != null) { + respVO.setBannerImages(JsonUtils.parseArray(activity.getBannerImages(), String.class)); + } else { + respVO.setBannerImages(new ArrayList<>()); + } + } catch (Exception e) { + log.error("[fillAppActivityDetailVO] 解析轮播图失败, activityId: {}", activity.getId(), e); + respVO.setBannerImages(new ArrayList<>()); + } + + try { + if (activity.getServiceCategories() != null) { + respVO.setServiceCategories(JsonUtils.parseArray(activity.getServiceCategories(), Integer.class)); + } else { + respVO.setServiceCategories(new ArrayList<>()); + } + } catch (Exception e) { + log.error("[fillAppActivityDetailVO] 解析服务类别失败, activityId: {}", activity.getId(), e); + respVO.setServiceCategories(new ArrayList<>()); + } + + try { + if (activity.getServiceTargets() != null) { + respVO.setServiceTargets(JsonUtils.parseArray(activity.getServiceTargets(), Integer.class)); + } else { + respVO.setServiceTargets(new ArrayList<>()); + } + } catch (Exception e) { + log.error("[fillAppActivityDetailVO] 解析服务对象失败, activityId: {}", activity.getId(), e); + respVO.setServiceTargets(new ArrayList<>()); + } + + // 查询发布范围 + List scopeList = activityScopeMapper.selectListByActivityId(respVO.getId()); + if (scopeList != null && !scopeList.isEmpty()) { + List communityNames = scopeList.stream() + .map(ActivityScopeDO::getCommunityName) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + respVO.setCommunityNames(communityNames); + } + + // 查询当前用户是否已报名 + Long memberId = SecurityFrameworkUtils.getLoginUserId(); + if (memberId != null) { + respVO.setHasRegistered(communityActivityService.isUserRegistered(memberId, respVO.getId())); + } else { + respVO.setHasRegistered(false); + } + } + +} \ No newline at end of file diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/vo/AppActivityDetailVO.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/vo/AppActivityDetailVO.java new file mode 100644 index 0000000..91289c4 --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/vo/AppActivityDetailVO.java @@ -0,0 +1,78 @@ +package com.fjrcloud.community.module.community.controller.app.activity.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 用户APP - 小区活动详情 Response VO + * + * @author fjrcloud + */ +@Schema(description = "用户APP - 小区活动详情 Response VO") +@Data +public class AppActivityDetailVO { + + @Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "活动标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "春节联欢晚会") + private String title; + + @Schema(description = "活动简介(富文本)", requiredMode = Schema.RequiredMode.REQUIRED) + private String content; + + @Schema(description = "封面图片URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://xxx.com/cover.jpg") + private String coverImage; + + @Schema(description = "轮播图URL列表", example = "[\"https://xxx.com/banner1.jpg\", \"https://xxx.com/banner2.jpg\"]") + private List bannerImages; + + @Schema(description = "服务类别(JSON数组,1-社区服务,2-敬老服务,3-助残服务,4-关爱儿童,5-环保宣传,6-文明礼仪,7-文化教育)", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 2]") + private List serviceCategories; + + @Schema(description = "服务对象(JSON数组,1-儿童,2-孤寡老人,3-残障人士,4-优抚对象,5-其他)", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 3]") + private List serviceTargets; + + @Schema(description = "报名开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime registrationStartTime; + + @Schema(description = "报名结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime registrationEndTime; + + @Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime activityStartTime; + + @Schema(description = "活动结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime activityEndTime; + + @Schema(description = "活动地点", requiredMode = Schema.RequiredMode.REQUIRED, example = "小区活动中心") + private String location; + + @Schema(description = "人数上限", example = "100") + private Integer maxParticipants; + + @Schema(description = "当前报名人数", example = "50") + private Integer currentParticipants; + + @Schema(description = "联系人", example = "张三") + private String contactPerson; + + @Schema(description = "联系电话", example = "13800138000") + private String contactPhone; + + @Schema(description = "活动状态(0-草稿,1-报名中,2-报名截止,3-进行中,4-已结束,5-已撤回)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "浏览次数", example = "100") + private Integer viewCount; + + @Schema(description = "小区名称列表", example = "[\"阳光小区\", \"花园小区\"]") + private List communityNames; + + @Schema(description = "是否已报名", example = "false") + private Boolean hasRegistered; + +} \ No newline at end of file diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/vo/AppActivityPageItemVO.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/vo/AppActivityPageItemVO.java new file mode 100644 index 0000000..c15a313 --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/vo/AppActivityPageItemVO.java @@ -0,0 +1,44 @@ +package com.fjrcloud.community.module.community.controller.app.activity.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 用户APP - 小区活动分页列表 Response VO + * + * @author fjrcloud + */ +@Schema(description = "用户APP - 小区活动分页列表 Response VO") +@Data +public class AppActivityPageItemVO { + + @Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "活动标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "春节联欢晚会") + private String title; + + @Schema(description = "封面图片URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://xxx.com/cover.jpg") + private String coverImage; + + @Schema(description = "报名开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime registrationStartTime; + + @Schema(description = "报名结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime registrationEndTime; + + @Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime activityStartTime; + + @Schema(description = "活动结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime activityEndTime; + + @Schema(description = "活动地点", requiredMode = Schema.RequiredMode.REQUIRED, example = "小区活动中心") + private String location; + + @Schema(description = "活动状态(0-草稿,1-报名中,2-报名截止,3-进行中,4-已结束,5-已撤回)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + +} \ No newline at end of file diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/vo/AppActivityPageReqVO.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/vo/AppActivityPageReqVO.java new file mode 100644 index 0000000..4ab2577 --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/vo/AppActivityPageReqVO.java @@ -0,0 +1,34 @@ +package com.fjrcloud.community.module.community.controller.app.activity.vo; + +import com.fjrcloud.community.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static com.fjrcloud.community.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +/** + * 用户APP - 小区活动分页 Request VO + * + * @author fjrcloud + */ +@Schema(description = "用户APP - 小区活动分页 Request VO") +@Data +public class AppActivityPageReqVO extends PageParam { + + @Schema(description = "活动标题", example = "春节联欢晚会") + private String title; + + @Schema(description = "小区ID", example = "1") + private Long communityId; + + @Schema(description = "服务类别", example = "1") + private Integer serviceCategory; + + @Schema(description = "活动开始时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] activityStartTime; + +} \ No newline at end of file diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/vo/AppActivityRegistrationReqVO.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/vo/AppActivityRegistrationReqVO.java new file mode 100644 index 0000000..f9d0936 --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/vo/AppActivityRegistrationReqVO.java @@ -0,0 +1,24 @@ +package com.fjrcloud.community.module.community.controller.app.activity.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 用户APP - 活动报名 Request VO + * + * @author fjrcloud + */ +@Schema(description = "用户APP - 活动报名 Request VO") +@Data +public class AppActivityRegistrationReqVO { + + @Schema(description = "活动ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "活动ID不能为空") + private Long activityId; + + @Schema(description = "备注", example = "希望参加") + private String remark; + +} \ No newline at end of file diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/vo/AppActivityRegistrationRespVO.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/vo/AppActivityRegistrationRespVO.java new file mode 100644 index 0000000..a995d12 --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/vo/AppActivityRegistrationRespVO.java @@ -0,0 +1,38 @@ +package com.fjrcloud.community.module.community.controller.app.activity.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 用户APP - 活动报名记录 Response VO + * + * @author fjrcloud + */ +@Schema(description = "用户APP - 活动报名记录 Response VO") +@Data +public class AppActivityRegistrationRespVO { + + @Schema(description = "报名编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "活动ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long activityId; + + @Schema(description = "活动标题", example = "春节联欢晚会") + private String activityTitle; + + @Schema(description = "活动封面图片", example = "https://xxx.com/cover.jpg") + private String activityCoverImage; + + @Schema(description = "报名状态(0-待审核,1-已通过,2-已拒绝,3-已取消)", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + private Integer status; + + @Schema(description = "报名时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime registrationTime; + + @Schema(description = "备注", example = "希望参加") + private String remark; + +} \ No newline at end of file diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/vo/AppActivityRespVO.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/vo/AppActivityRespVO.java new file mode 100644 index 0000000..6a39372 --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/activity/vo/AppActivityRespVO.java @@ -0,0 +1,78 @@ +package com.fjrcloud.community.module.community.controller.app.activity.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 用户APP - 小区活动 Response VO + * + * @author fjrcloud + */ +@Schema(description = "用户APP - 小区活动 Response VO") +@Data +public class AppActivityRespVO { + + @Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "活动标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "春节联欢晚会") + private String title; + + @Schema(description = "活动简介(富文本)", requiredMode = Schema.RequiredMode.REQUIRED) + private String content; + + @Schema(description = "封面图片URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://xxx.com/cover.jpg") + private String coverImage; + + @Schema(description = "轮播图URL列表", example = "[\"https://xxx.com/banner1.jpg\", \"https://xxx.com/banner2.jpg\"]") + private List bannerImages; + + @Schema(description = "服务类别(JSON数组,1-社区服务,2-敬老服务,3-助残服务,4-关爱儿童,5-环保宣传,6-文明礼仪,7-文化教育)", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 2]") + private List serviceCategories; + + @Schema(description = "服务对象(JSON数组,1-儿童,2-孤寡老人,3-残障人士,4-优抚对象,5-其他)", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 3]") + private List serviceTargets; + + @Schema(description = "报名开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime registrationStartTime; + + @Schema(description = "报名结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime registrationEndTime; + + @Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime activityStartTime; + + @Schema(description = "活动结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime activityEndTime; + + @Schema(description = "活动地点", requiredMode = Schema.RequiredMode.REQUIRED, example = "小区活动中心") + private String location; + + @Schema(description = "人数上限", example = "100") + private Integer maxParticipants; + + @Schema(description = "当前报名人数", example = "50") + private Integer currentParticipants; + + @Schema(description = "联系人", example = "张三") + private String contactPerson; + + @Schema(description = "联系电话", example = "13800138000") + private String contactPhone; + + @Schema(description = "活动状态(0-草稿,1-报名中,2-报名截止,3-进行中,4-已结束,5-已撤回)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "浏览次数", example = "100") + private Integer viewCount; + + @Schema(description = "小区名称列表", example = "[\"阳光小区\", \"花园小区\"]") + private List communityNames; + + @Schema(description = "是否已报名", example = "false") + private Boolean hasRegistered; + +} \ No newline at end of file diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/banner/AppBannerController.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/banner/AppBannerController.java index 86e4030..0f6afd6 100644 --- a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/banner/AppBannerController.java +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/banner/AppBannerController.java @@ -16,6 +16,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; +import javax.annotation.security.PermitAll; import java.util.List; import static com.fjrcloud.community.framework.common.pojo.CommonResult.success; @@ -32,6 +33,7 @@ public class AppBannerController { @GetMapping("/list") @Operation(summary = "获取Banner列表") + @PermitAll @Parameter(name = "position", description = "显示位置(1-首页,2-个人中心,3-好房出租)", example = "1") public CommonResult> getBannerList(@RequestParam(value = "position", required = false) Integer position) { List list = bannerService.getBannerListByPosition(position); diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/knowledgeclass/AppKnowledgeClassController.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/knowledgeclass/AppKnowledgeClassController.java index 737ed7d..348e35a 100644 --- a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/knowledgeclass/AppKnowledgeClassController.java +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/knowledgeclass/AppKnowledgeClassController.java @@ -17,6 +17,7 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; +import javax.annotation.security.PermitAll; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -41,6 +42,7 @@ public class AppKnowledgeClassController { private KnowledgeScopeMapper knowledgeScopeMapper; @GetMapping("/page") + @PermitAll @Operation(summary = "获取知识课堂分页列表") public CommonResult> getKnowledgeClassPage(@Validated AppKnowledgeClassPageReqVO pageReqVO) { KnowledgeClassPageReqVO adminPageReqVO = new KnowledgeClassPageReqVO(); diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/miniappconfig/AppMiniAppConfigController.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/miniappconfig/AppMiniAppConfigController.java index dbaac83..129aa7f 100644 --- a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/miniappconfig/AppMiniAppConfigController.java +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/miniappconfig/AppMiniAppConfigController.java @@ -16,6 +16,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; +import javax.annotation.security.PermitAll; import java.util.List; import static com.fjrcloud.community.framework.common.pojo.CommonResult.success; @@ -32,6 +33,7 @@ public class AppMiniAppConfigController { @GetMapping("/list") @Operation(summary = "获取小程序配置列表") + @PermitAll @Parameter(name = "position", description = "显示位置(1-首页,2-更多服务)", example = "1") public CommonResult> getMiniAppConfigList( @RequestParam(value = "position", required = false) Integer position) { diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/notice/AppCommunityNoticeController.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/notice/AppCommunityNoticeController.java index 5686ab0..1965286 100644 --- a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/notice/AppCommunityNoticeController.java +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/notice/AppCommunityNoticeController.java @@ -23,6 +23,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; +import javax.annotation.security.PermitAll; import java.net.URLDecoder; import java.util.ArrayList; import java.util.List; @@ -51,6 +52,7 @@ public class AppCommunityNoticeController { @GetMapping("/page") @Operation(summary = "获取通知分页列表") + @PermitAll public CommonResult> getNoticePage(@Validated AppNoticePageReqVO pageReqVO) { // 复用管理后台的 PageReqVO NoticePageReqVO adminPageReqVO = new NoticePageReqVO(); diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/post/AppCommunityPostController.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/post/AppCommunityPostController.java index 19b1ed9..3168b4b 100644 --- a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/post/AppCommunityPostController.java +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/controller/app/post/AppCommunityPostController.java @@ -20,6 +20,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; +import javax.annotation.security.PermitAll; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -45,6 +46,7 @@ public class AppCommunityPostController { private PostScopeMapper postScopeMapper; @GetMapping("/page") + @PermitAll @Operation(summary = "获取社区动态分页列表") public CommonResult> getCommunityPostPage(@Validated AppCommunityPostPageReqVO pageReqVO) { // 复用管理后台的 PageReqVO diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/dataobject/activity/ActivityRegistrationDO.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/dataobject/activity/ActivityRegistrationDO.java new file mode 100644 index 0000000..7ea2ff0 --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/dataobject/activity/ActivityRegistrationDO.java @@ -0,0 +1,69 @@ +package com.fjrcloud.community.module.community.dal.dataobject.activity; + +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fjrcloud.community.framework.mybatis.core.dataobject.BaseDO; +import com.fjrcloud.community.framework.tenant.core.aop.TenantIgnore; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 小区活动报名 DO + * + * @author fjrcloud + */ +@TableName("comm_activity_registration") +@KeySequence("comm_activity_registration_seq") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +@TenantIgnore +public class ActivityRegistrationDO extends BaseDO { + + /** + * 报名编号 + */ + @TableId + private Long id; + + /** + * 活动ID + */ + private Long activityId; + + /** + * 会员ID + */ + private Long memberId; + + /** + * 会员姓名 + */ + private String memberName; + + /** + * 会员手机号 + */ + private String memberPhone; + + /** + * 报名时间 + */ + private LocalDateTime registrationTime; + + /** + * 报名状态(0-待审核,1-已通过,2-已拒绝,3-已取消) + */ + private Integer status; + + /** + * 备注 + */ + private String remark; + +} diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/dataobject/activity/ActivityScopeDO.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/dataobject/activity/ActivityScopeDO.java new file mode 100644 index 0000000..8285740 --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/dataobject/activity/ActivityScopeDO.java @@ -0,0 +1,47 @@ +package com.fjrcloud.community.module.community.dal.dataobject.activity; + +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fjrcloud.community.framework.mybatis.core.dataobject.BaseDO; +import com.fjrcloud.community.framework.tenant.core.aop.TenantIgnore; +import lombok.*; + +/** + * 小区活动小区关联 DO + * + * @author fjrcloud + */ +@TableName("comm_activity_scope") +@KeySequence("comm_activity_scope_seq") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +@TenantIgnore +public class ActivityScopeDO extends BaseDO { + + /** + * 关联编号 + */ + @TableId + private Long id; + + /** + * 活动ID + */ + private Long activityId; + + /** + * 小区ID + */ + private Long communityId; + + /** + * 小区名称 + */ + private String communityName; + +} diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/dataobject/activity/CommunityActivityDO.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/dataobject/activity/CommunityActivityDO.java new file mode 100644 index 0000000..659bf87 --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/dataobject/activity/CommunityActivityDO.java @@ -0,0 +1,124 @@ +package com.fjrcloud.community.module.community.dal.dataobject.activity; + +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fjrcloud.community.framework.mybatis.core.dataobject.BaseDO; +import com.fjrcloud.community.framework.tenant.core.aop.TenantIgnore; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * 小区活动 DO + * + * @author fjrcloud + */ +@TableName("comm_activity") +@KeySequence("comm_activity_seq") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +@TenantIgnore +public class CommunityActivityDO extends BaseDO { + + /** + * 活动编号 + */ + @TableId + private Long id; + + /** + * 活动标题 + */ + private String title; + + /** + * 活动简介(富文本) + */ + private String content; + + /** + * 封面图片URL + */ + private String coverImage; + + /** + * 轮播图URL列表(JSON数组格式) + */ + private String bannerImages; + + /** + * 服务类别(JSON数组格式,1-社区服务,2-敬老服务,3-...) + */ + private String serviceCategories; + + /** + * 服务对象(JSON数组格式,1-儿童,2-孤寡老人,3-残障...) + */ + private String serviceTargets; + + /** + * 报名开始时间 + */ + private LocalDateTime registrationStartTime; + + /** + * 报名结束时间 + */ + private LocalDateTime registrationEndTime; + + /** + * 活动开始时间 + */ + private LocalDateTime activityStartTime; + + /** + * 活动结束时间 + */ + private LocalDateTime activityEndTime; + + /** + * 活动地点 + */ + private String location; + + /** + * 人数上限 + */ + private Integer maxParticipants; + + /** + * 联系人 + */ + private String contactPerson; + + /** + * 联系电话 + */ + private String contactPhone; + + /** + * 当前报名人数 + */ + private Integer currentParticipants; + + /** + * 活动状态(0-草稿,1-报名中,2-报名截止,3-进行中,4-已结束) + */ + private Integer status; + + /** + * 浏览次数 + */ + private Integer viewCount; + + /** + * 是否展示(0-隐藏,1-展示) + */ + private Boolean isDisplay; + +} diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/mysql/activity/ActivityRegistrationMapper.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/mysql/activity/ActivityRegistrationMapper.java new file mode 100644 index 0000000..893c8cf --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/mysql/activity/ActivityRegistrationMapper.java @@ -0,0 +1,46 @@ +package com.fjrcloud.community.module.community.dal.mysql.activity; + +import com.fjrcloud.community.framework.common.pojo.PageParam; +import com.fjrcloud.community.framework.common.pojo.PageResult; +import com.fjrcloud.community.framework.mybatis.core.mapper.BaseMapperX; +import com.fjrcloud.community.framework.mybatis.core.query.LambdaQueryWrapperX; +import com.fjrcloud.community.module.community.dal.dataobject.activity.ActivityRegistrationDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 小区活动报名 Mapper + * + * @author fjrcloud + */ +@Mapper +public interface ActivityRegistrationMapper extends BaseMapperX { + + /** + * 根据会员ID和活动ID查询报名数量 + * + * @param memberId 会员ID + * @param activityId 活动ID + * @return 报名数量 + */ + default Long selectCountByMemberIdAndActivityId(Long memberId, Long activityId) { + return selectCount(new LambdaQueryWrapperX() + .eq(ActivityRegistrationDO::getMemberId, memberId) + .eq(ActivityRegistrationDO::getActivityId, activityId) + .ne(ActivityRegistrationDO::getStatus, 3)); + } + + /** + * 根据会员ID分页查询报名记录 + * + * @param memberId 会员ID + * @param pageParam 分页参数 + * @return 报名记录分页 + */ + default PageResult selectPageByMemberId(Long memberId, PageParam pageParam) { + return selectPage(pageParam, new LambdaQueryWrapperX() + .eq(ActivityRegistrationDO::getMemberId, memberId) + .ne(ActivityRegistrationDO::getStatus, 3) + .orderByDesc(ActivityRegistrationDO::getRegistrationTime)); + } + +} diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/mysql/activity/ActivityScopeMapper.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/mysql/activity/ActivityScopeMapper.java new file mode 100644 index 0000000..cbc8b4b --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/mysql/activity/ActivityScopeMapper.java @@ -0,0 +1,86 @@ +package com.fjrcloud.community.module.community.dal.mysql.activity; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.fjrcloud.community.framework.mybatis.core.mapper.BaseMapperX; +import com.fjrcloud.community.module.community.dal.dataobject.activity.ActivityScopeDO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.ArrayList; +import java.util.List; + +/** + * 小区活动小区关联 Mapper + * + * @author fjrcloud + */ +@Mapper +public interface ActivityScopeMapper extends BaseMapperX { + + /** + * 根据活动ID查询小区关联列表 + * + * @param activityId 活动ID + * @return 小区关联列表 + */ + default List selectListByActivityId(Long activityId) { + return selectList(ActivityScopeDO::getActivityId, activityId); + } + + /** + * 根据活动ID物理删除关联(真删除) + * + * @param activityId 活动ID + * @return 删除数量 + */ + default int deleteByActivityId(Long activityId) { + List list = selectList(ActivityScopeDO::getActivityId, activityId); + if (list == null || list.isEmpty()) { + return 0; + } + + int count = 0; + for (ActivityScopeDO scope : list) { + count += deleteAbsoluteById(scope.getId()); + } + return count; + } + + /** + * 批量插入活动小区关联 + * + * @param activityId 活动ID + * @param communityIds 小区ID列表 + * @param communityNames 小区名称列表 + */ + default void insertBatch(@Param("activityId") Long activityId, + @Param("communityIds") List communityIds, + @Param("communityNames") List communityNames) { + List list = new java.util.ArrayList<>(); + for (int i = 0; i < communityIds.size(); i++) { + ActivityScopeDO scopeDO = new ActivityScopeDO(); + scopeDO.setActivityId(activityId); + scopeDO.setCommunityId(communityIds.get(i)); + if (communityNames != null && i < communityNames.size()) { + scopeDO.setCommunityName(communityNames.get(i)); + } + list.add(scopeDO); + } + insertBatch(list); + } + + /** + * 根据活动ID列表批量查询关联关系 + * + * @param activityIds 活动ID列表 + * @return 关联关系列表 + */ + default List selectListByActivityIds(List activityIds) { + if (activityIds == null || activityIds.isEmpty()) { + return new ArrayList<>(); + } + return selectList(new LambdaQueryWrapper() + .in(ActivityScopeDO::getActivityId, activityIds)); + } + +} diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/mysql/activity/CommunityActivityMapper.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/mysql/activity/CommunityActivityMapper.java new file mode 100644 index 0000000..f4dffc7 --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/dal/mysql/activity/CommunityActivityMapper.java @@ -0,0 +1,36 @@ +package com.fjrcloud.community.module.community.dal.mysql.activity; + +import com.fjrcloud.community.framework.common.pojo.PageResult; +import com.fjrcloud.community.framework.mybatis.core.mapper.BaseMapperX; +import com.fjrcloud.community.framework.mybatis.core.query.LambdaQueryWrapperX; +import com.fjrcloud.community.module.community.controller.admin.activity.vo.ActivityPageReqVO; +import com.fjrcloud.community.module.community.dal.dataobject.activity.CommunityActivityDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 小区活动 Mapper + * + * @author fjrcloud + */ +@Mapper +public interface CommunityActivityMapper extends BaseMapperX { + + /** + * 分页查询活动列表 + * + * @param reqVO 分页查询条件 + * @return 分页结果 + */ + default PageResult selectPage(ActivityPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(CommunityActivityDO::getTitle, reqVO.getTitle()) + .eqIfPresent(CommunityActivityDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(CommunityActivityDO::getActivityStartTime, reqVO.getActivityStartTime()) + .eqIfPresent(CommunityActivityDO::getIsDisplay, reqVO.getIsDisplay()) + .apply(reqVO.getCommunityId() != null, + "EXISTS (SELECT 1 FROM comm_activity_scope WHERE activity_id = comm_activity.id AND community_id = {0})", + reqVO.getCommunityId()) + .orderByDesc(CommunityActivityDO::getCreateTime)); + } + +} diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/enums/ErrorCodeConstants.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/enums/ErrorCodeConstants.java index 36a093c..eb29b0c 100644 --- a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/enums/ErrorCodeConstants.java +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/enums/ErrorCodeConstants.java @@ -49,5 +49,16 @@ public interface ErrorCodeConstants { ErrorCode KNOWLEDGE_ALREADY_LIKED = new ErrorCode(2_006_000_001, "已经点赞过了"); ErrorCode KNOWLEDGE_NOT_LIKED = new ErrorCode(2_006_000_002, "还未点赞"); + // ========== 小区活动 1-005-000-000 ========== + ErrorCode ACTIVITY_NOT_EXISTS = new ErrorCode(1_002_001_001, "活动不存在"); + ErrorCode ACTIVITY_STATUS_ERROR = new ErrorCode(1_002_001_002, "活动状态不正确"); + ErrorCode ACTIVITY_STATUS_NOT_REGISTRATION = new ErrorCode(1_002_001_003, "活动不在报名中"); + ErrorCode ACTIVITY_REGISTRATION_NOT_STARTED = new ErrorCode(1_002_001_004, "活动报名未开始"); + ErrorCode ACTIVITY_REGISTRATION_ENDED = new ErrorCode(1_002_001_005, "活动报名已结束"); + ErrorCode ACTIVITY_ALREADY_REGISTERED = new ErrorCode(1_002_001_006, "您已报名该活动"); + ErrorCode ACTIVITY_PARTICIPANTS_FULL = new ErrorCode(1_002_001_007, "活动报名人数已满"); + ErrorCode ACTIVITY_REGISTRATION_NOT_EXISTS = new ErrorCode(1_002_001_008, "报名记录不存在"); + ErrorCode ACTIVITY_REGISTRATION_NOT_OWNER = new ErrorCode(1_002_001_009, "无权操作该报名记录"); + ErrorCode ACTIVITY_REGISTRATION_STATUS_ERROR = new ErrorCode(1_002_001_010, "报名状态不允许取消"); } diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/service/activity/CommunityActivityService.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/service/activity/CommunityActivityService.java new file mode 100644 index 0000000..8f56636 --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/service/activity/CommunityActivityService.java @@ -0,0 +1,121 @@ +package com.fjrcloud.community.module.community.service.activity; + +import com.fjrcloud.community.framework.common.pojo.PageParam; +import com.fjrcloud.community.framework.common.pojo.PageResult; +import com.fjrcloud.community.module.community.controller.admin.activity.vo.ActivityPageReqVO; +import com.fjrcloud.community.module.community.controller.admin.activity.vo.ActivitySaveReqVO; +import com.fjrcloud.community.module.community.controller.app.activity.vo.AppActivityRegistrationRespVO; +import com.fjrcloud.community.module.community.dal.dataobject.activity.CommunityActivityDO; + +import javax.validation.Valid; +import java.util.List; + +/** + * 小区活动 Service 接口 + * + * @author fjrcloud + */ +public interface CommunityActivityService { + + /** + * 创建小区活动 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createActivity(@Valid ActivitySaveReqVO createReqVO); + + /** + * 更新小区活动 + * + * @param updateReqVO 更新信息 + */ + void updateActivity(@Valid ActivitySaveReqVO updateReqVO); + + /** + * 删除小区活动 + * + * @param id 编号 + */ + void deleteActivity(Long id); + + /** + * 批量删除小区活动 + * + * @param ids 编号列表 + */ + void deleteActivityListByIds(List ids); + + /** + * 获得小区活动 + * + * @param id 编号 + * @return 小区活动 + */ + CommunityActivityDO getActivity(Long id); + + /** + * 获得小区活动分页 + * + * @param pageReqVO 分页查询 + * @return 小区活动分页 + */ + PageResult getActivityPage(ActivityPageReqVO pageReqVO); + + /** + * 发布活动 + * + * @param id 活动ID + */ + void publishActivity(Long id); + + /** + * 下架活动 + * + * @param id 活动ID + */ + void unpublishActivity(Long id); + + /** + * 增加活动浏览次数 + * + * @param id 活动ID + */ + void incrementViewCount(Long id); + + /** + * 报名参加活动 + * + * @param memberId 会员ID + * @param activityId 活动ID + * @param remark 备注 + */ + void registerActivity(Long memberId, Long activityId, String remark); + + /** + * 获取我的报名记录分页 + * + * @param memberId 会员ID + * @param pageParam 分页参数 + * @return 报名记录分页 + */ + PageResult getMyRegistrationPage(Long memberId, PageParam pageParam); + + /** + * 取消报名 + * + * @param memberId 会员ID + * @param registrationId 报名记录ID + */ + void cancelRegistration(Long memberId, Long registrationId); + + /** + * 查询用户是否已报名活动 + * + * @param memberId 会员ID + * @param activityId 活动ID + * @return 是否已报名 + */ + boolean isUserRegistered(Long memberId, Long activityId); + +} diff --git a/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/service/activity/CommunityActivityServiceImpl.java b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/service/activity/CommunityActivityServiceImpl.java new file mode 100644 index 0000000..4d33568 --- /dev/null +++ b/fjrcloud-module-community/src/main/java/com/fjrcloud/community/module/community/service/activity/CommunityActivityServiceImpl.java @@ -0,0 +1,364 @@ +package com.fjrcloud.community.module.community.service.activity; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.fjrcloud.community.framework.common.pojo.PageParam; +import com.fjrcloud.community.framework.common.pojo.PageResult; +import com.fjrcloud.community.framework.common.util.json.JsonUtils; +import com.fjrcloud.community.framework.common.util.object.BeanUtils; +import com.fjrcloud.community.framework.tenant.core.context.TenantContextHolder; +import com.fjrcloud.community.framework.tenant.core.util.TenantUtils; +import com.fjrcloud.community.module.community.controller.admin.activity.vo.ActivityPageReqVO; +import com.fjrcloud.community.module.community.controller.admin.activity.vo.ActivitySaveReqVO; +import com.fjrcloud.community.module.community.controller.app.activity.vo.AppActivityRegistrationRespVO; +import com.fjrcloud.community.module.community.dal.dataobject.activity.ActivityRegistrationDO; +import com.fjrcloud.community.module.community.dal.dataobject.activity.CommunityActivityDO; +import com.fjrcloud.community.module.community.dal.dataobject.community.CommunityDO; +import com.fjrcloud.community.module.community.dal.mysql.activity.ActivityRegistrationMapper; +import com.fjrcloud.community.module.community.dal.mysql.activity.ActivityScopeMapper; +import com.fjrcloud.community.module.community.dal.mysql.activity.CommunityActivityMapper; +import com.fjrcloud.community.module.community.service.community.CommunityService; +import com.fjrcloud.community.module.member.api.user.MemberUserApi; +import com.fjrcloud.community.module.member.api.user.dto.MemberUserRespDTO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static com.fjrcloud.community.framework.common.exception.util.ServiceExceptionUtil.exception; +import static com.fjrcloud.community.framework.tenant.core.security.TenantSecurityWebFilter.SYSTEM_TENANT_ID; +import static com.fjrcloud.community.module.community.enums.ErrorCodeConstants.*; +import static com.fjrcloud.community.module.member.enums.ErrorCodeConstants.USER_NOT_EXISTS; + +/** + * 小区活动 Service 实现类 + * + * @author fjrcloud + */ +@Service +@Validated +public class CommunityActivityServiceImpl implements CommunityActivityService { + + @Resource + private CommunityActivityMapper communityActivityMapper; + + @Resource + private ActivityRegistrationMapper activityRegistrationMapper; + + @Resource + private ActivityScopeMapper activityScopeMapper; + + @Resource + private CommunityService communityService; + + @Resource + private MemberUserApi memberUserApi; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createActivity(ActivitySaveReqVO createReqVO) { + // 插入活动 + CommunityActivityDO activity = BeanUtils.toBean(createReqVO, CommunityActivityDO.class); + activity.setBannerImages(JsonUtils.toJsonString(createReqVO.getBannerImages())); + activity.setServiceCategories(JsonUtils.toJsonString(createReqVO.getServiceCategories())); + activity.setServiceTargets(JsonUtils.toJsonString(createReqVO.getServiceTargets())); + activity.setStatus(0); + activity.setViewCount(0); + activity.setCurrentParticipants(0); + activity.setIsDisplay(false); + communityActivityMapper.insert(activity); + + // 插入活动小区关联 + insertActivityScope(activity.getId(), createReqVO.getCommunityIds()); + + // 返回 + return activity.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateActivity(ActivitySaveReqVO updateReqVO) { + // 校验存在 + validateActivityExists(updateReqVO.getId()); + + // 更新活动 + CommunityActivityDO updateObj = BeanUtils.toBean(updateReqVO, CommunityActivityDO.class); + updateObj.setBannerImages(JsonUtils.toJsonString(updateReqVO.getBannerImages())); + updateObj.setServiceCategories(JsonUtils.toJsonString(updateReqVO.getServiceCategories())); + updateObj.setServiceTargets(JsonUtils.toJsonString(updateReqVO.getServiceTargets())); + communityActivityMapper.updateById(updateObj); + + // 更新活动小区关联 + activityScopeMapper.deleteByActivityId(updateReqVO.getId()); + insertActivityScope(updateReqVO.getId(), updateReqVO.getCommunityIds()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteActivity(Long id) { + // 校验存在 + validateActivityExists(id); + + // 删除活动小区关联 + activityScopeMapper.deleteByActivityId(id); + + // 删除活动 + communityActivityMapper.deleteById(id); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteActivityListByIds(List ids) { + // 删除活动小区关联 + for (Long id : ids) { + activityScopeMapper.deleteByActivityId(id); + } + + // 删除活动 + communityActivityMapper.deleteByIds(ids); + } + + @Override + public CommunityActivityDO getActivity(Long id) { + return communityActivityMapper.selectById(id); + } + + @Override + public PageResult getActivityPage(ActivityPageReqVO pageReqVO) { + // 获取当前租户ID + Long tenantId = TenantContextHolder.getTenantId(); + + // 如果没有指定小区ID,则根据租户类型确定 + if (pageReqVO.getCommunityId() == null) { + // 超级管理员租户查询所有活动,忽略租户隔离 + if (SYSTEM_TENANT_ID.equals(tenantId)) { + return TenantUtils.executeIgnore(() -> communityActivityMapper.selectPage(pageReqVO)); + } + // 普通租户:租户ID即小区ID + pageReqVO.setCommunityId(tenantId); + } + + // 使用 EXISTS 子查询 + return communityActivityMapper.selectPage(pageReqVO); + } + + @Override + public void publishActivity(Long id) { + // 校验存在 + CommunityActivityDO activity = validateActivityExists(id); + + // 校验状态 + if (activity.getStatus() != 0) { + throw exception(ACTIVITY_STATUS_ERROR); + } + + // 更新状态为报名中 + CommunityActivityDO updateObj = new CommunityActivityDO(); + updateObj.setId(id); + updateObj.setStatus(1); + updateObj.setIsDisplay(true); + communityActivityMapper.updateById(updateObj); + } + + @Override + public void unpublishActivity(Long id) { + // 校验存在 + CommunityActivityDO activity = validateActivityExists(id); + + // 更新状态为草稿 + CommunityActivityDO updateObj = new CommunityActivityDO(); + updateObj.setId(id); + updateObj.setStatus(0); + updateObj.setIsDisplay(false); + communityActivityMapper.updateById(updateObj); + } + + @Override + public void incrementViewCount(Long id) { + CommunityActivityDO activity = communityActivityMapper.selectById(id); + if (activity != null) { + CommunityActivityDO updateObj = new CommunityActivityDO(); + updateObj.setId(id); + updateObj.setViewCount(activity.getViewCount() + 1); + communityActivityMapper.updateById(updateObj); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void registerActivity(Long memberId, Long activityId, String remark) { + // 校验活动是否存在 + CommunityActivityDO activity = validateActivityExists(activityId); + + // 校验活动状态是否为报名中 + if (activity.getStatus() != 1) { + throw exception(ACTIVITY_STATUS_NOT_REGISTRATION); + } + + // 校验是否已过报名时间 + LocalDateTime now = LocalDateTime.now(); + if (now.isBefore(activity.getRegistrationStartTime())) { + throw exception(ACTIVITY_REGISTRATION_NOT_STARTED); + } + if (now.isAfter(activity.getRegistrationEndTime())) { + throw exception(ACTIVITY_REGISTRATION_ENDED); + } + + // 校验是否已报名 + Long count = activityRegistrationMapper.selectCountByMemberIdAndActivityId(memberId, activityId); + if (count > 0) { + throw exception(ACTIVITY_ALREADY_REGISTERED); + } + + // 校验人数上限 + if (activity.getMaxParticipants() != null && activity.getCurrentParticipants() >= activity.getMaxParticipants()) { + throw exception(ACTIVITY_PARTICIPANTS_FULL); + } + + // 获取会员信息 + MemberUserRespDTO memberUser = memberUserApi.getUser(memberId); + if (memberUser == null) { + throw exception(USER_NOT_EXISTS); + } + + // 创建报名记录 + ActivityRegistrationDO registration = ActivityRegistrationDO.builder() + .activityId(activityId) + .memberId(memberId) + .memberName(memberUser.getNickname()) + .memberPhone(memberUser.getMobile()) + .registrationTime(LocalDateTime.now()) + .status(0) + .remark(remark) + .build(); + activityRegistrationMapper.insert(registration); + + // 更新活动当前报名人数 + CommunityActivityDO updateObj = new CommunityActivityDO(); + updateObj.setId(activityId); + updateObj.setCurrentParticipants(activity.getCurrentParticipants() + 1); + communityActivityMapper.updateById(updateObj); + } + + @Override + public PageResult getMyRegistrationPage(Long memberId, PageParam pageParam) { + // 查询报名记录分页 + PageResult pageResult = activityRegistrationMapper.selectPageByMemberId(memberId, pageParam); + if (CollUtil.isEmpty(pageResult.getList())) { + return PageResult.empty(pageResult.getTotal()); + } + + // 转换为响应VO + PageResult respVOPageResult = BeanUtils.toBean(pageResult, AppActivityRegistrationRespVO.class); + + // 批量查询活动信息 + List activityIds = pageResult.getList().stream() + .map(ActivityRegistrationDO::getActivityId) + .collect(Collectors.toList()); + List activities = communityActivityMapper.selectByIds(activityIds); + Map activityMap = activities.stream() + .collect(Collectors.toMap(CommunityActivityDO::getId, activity -> activity)); + + // 填充活动标题和封面 + for (int i = 0; i < respVOPageResult.getList().size(); i++) { + AppActivityRegistrationRespVO respVO = respVOPageResult.getList().get(i); + ActivityRegistrationDO registration = pageResult.getList().get(i); + CommunityActivityDO activity = activityMap.get(registration.getActivityId()); + if (activity != null) { + respVO.setActivityTitle(activity.getTitle()); + respVO.setActivityCoverImage(activity.getCoverImage()); + } + } + + return respVOPageResult; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void cancelRegistration(Long memberId, Long registrationId) { + // 查询报名记录 + ActivityRegistrationDO registration = activityRegistrationMapper.selectById(registrationId); + if (registration == null) { + throw exception(ACTIVITY_REGISTRATION_NOT_EXISTS); + } + + // 校验是否为本人报名 + if (!registration.getMemberId().equals(memberId)) { + throw exception(ACTIVITY_REGISTRATION_NOT_OWNER); + } + + // 校验报名状态,只有待审核和已通过的可以取消 + if (registration.getStatus() != 0 && registration.getStatus() != 1) { + throw exception(ACTIVITY_REGISTRATION_STATUS_ERROR); + } + + // 更新报名状态为已取消 + ActivityRegistrationDO updateObj = new ActivityRegistrationDO(); + updateObj.setId(registrationId); + updateObj.setStatus(3); + activityRegistrationMapper.updateById(updateObj); + + // 减少活动当前报名人数 + CommunityActivityDO activity = communityActivityMapper.selectById(registration.getActivityId()); + if (activity != null && activity.getCurrentParticipants() > 0) { + CommunityActivityDO activityUpdateObj = new CommunityActivityDO(); + activityUpdateObj.setId(registration.getActivityId()); + activityUpdateObj.setCurrentParticipants(activity.getCurrentParticipants() - 1); + communityActivityMapper.updateById(activityUpdateObj); + } + } + + @Override + public boolean isUserRegistered(Long memberId, Long activityId) { + Long count = activityRegistrationMapper.selectCountByMemberIdAndActivityId(memberId, activityId); + return count != null && count > 0; + } + + /** + * 插入活动小区关联 + * + * @param activityId 活动ID + * @param communityIds 小区ID列表 + */ + private void insertActivityScope(Long activityId, List communityIds) { + if (CollUtil.isEmpty(communityIds)) { + return; + } + + // 获取小区名称 + List communityNames = communityIds.stream() + .map(communityId -> { + try { + CommunityDO community = communityService.getCommunity(communityId); + return community != null ? community.getCommunityName() : null; + } catch (Exception e) { + return null; + } + }) + .filter(StrUtil::isNotBlank) + .collect(Collectors.toList()); + + // 批量插入 + activityScopeMapper.insertBatch(activityId, communityIds, communityNames); + } + + /** + * 校验活动是否存在 + * + * @param id 活动ID + * @return 活动信息 + */ + private CommunityActivityDO validateActivityExists(Long id) { + CommunityActivityDO activity = communityActivityMapper.selectById(id); + if (activity == null) { + throw exception(ACTIVITY_NOT_EXISTS); + } + return activity; + } + +}