diff --git a/.gitignore b/.gitignore index a4baa26..b599f00 100644 --- a/.gitignore +++ b/.gitignore @@ -19,5 +19,5 @@ docker/xxljob/logs application-youlai.yml .claude CLAUDE.md -content-audit-design.md +docs .mcp.json diff --git a/src/main/java/com/youlai/boot/mini/controller/HomePageController.java b/src/main/java/com/youlai/boot/mini/controller/HomePageController.java index 5bc8304..f30a95a 100644 --- a/src/main/java/com/youlai/boot/mini/controller/HomePageController.java +++ b/src/main/java/com/youlai/boot/mini/controller/HomePageController.java @@ -1,9 +1,18 @@ package com.youlai.boot.mini.controller; +import com.youlai.boot.common.result.PageResult; import com.youlai.boot.common.result.Result; +import com.youlai.boot.framework.security.util.SecurityUtils; import com.youlai.boot.mini.model.dto.MapSearchDTO; +import com.youlai.boot.mini.model.query.StrayAnimalQuery; +import com.youlai.boot.mini.model.vo.HomeStatsVO; +import com.youlai.boot.mini.model.vo.StrayAnimalShortVO; +import com.youlai.boot.mini.model.vo.TaskVO; +import com.youlai.boot.mini.service.MiniPointRecordService; import com.youlai.boot.mini.service.StrayAnimalService; + +import java.util.List; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; @@ -16,6 +25,7 @@ import org.springframework.web.bind.annotation.*; public class HomePageController { private final StrayAnimalService strayAnimalService; + private final MiniPointRecordService miniPointRecordService; @Operation(summary = "根据地图边界获取流浪动物信息(不需要登录)") @RequestMapping(value = "/listByBounds", method = RequestMethod.GET) @@ -23,5 +33,24 @@ public class HomePageController { return Result.success(strayAnimalService.listByMapBounds(mapSearch)); } + @Operation(summary = "首页获取最新登记动物列表") + @GetMapping(value = "/listAnimal") + public PageResult listAnimal(StrayAnimalQuery queryParams) { + return PageResult.success(strayAnimalService.getHomePageList(queryParams)); + } + + @Operation(summary = "首页统计数据:已登记动物数 + 爱心用户数") + @GetMapping(value = "/stats") + public Result stats() { + return Result.success(strayAnimalService.getHomeStats()); + } + + @Operation(summary = "首页任务列表(需登录)") + @GetMapping(value = "/tasks") + public Result> tasks() { + Long userId = SecurityUtils.getUserId(); + return Result.success(miniPointRecordService.listHomeTasks(userId)); + } + } diff --git a/src/main/java/com/youlai/boot/mini/mapper/MiniStrayAnimalMapper.java b/src/main/java/com/youlai/boot/mini/mapper/MiniStrayAnimalMapper.java index 76dc804..2a87fc6 100644 --- a/src/main/java/com/youlai/boot/mini/mapper/MiniStrayAnimalMapper.java +++ b/src/main/java/com/youlai/boot/mini/mapper/MiniStrayAnimalMapper.java @@ -6,6 +6,8 @@ import com.youlai.boot.mini.model.dto.MapSearchDTO; import com.youlai.boot.mini.model.entity.MiniStrayAnimal; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.youlai.boot.mini.model.query.OwnStrayAnimalQuery; +import com.youlai.boot.mini.model.query.StrayAnimalQuery; +import com.youlai.boot.mini.model.vo.HomeStatsVO; import com.youlai.boot.mini.model.vo.StrayAnimalDetailsVO; import com.youlai.boot.mini.model.vo.StrayAnimalNearbyVO; import com.youlai.boot.mini.model.vo.AdoptedAnimalVO; @@ -28,6 +30,8 @@ public interface MiniStrayAnimalMapper extends BaseMapper { IPage getAnimalPage(Page page, @Param("queryParams") OwnStrayAnimalQuery queryParams); + IPage getHomePageList(Page page, @Param("queryParams") StrayAnimalQuery queryParams); + StrayAnimalDetailsVO getStrayAnimalDetails(@Param("animalUuid") String animalUuid, @Param("miniUserId") Long miniUserId); List listByMapBounds(MapSearchDTO mapSearch); @@ -38,4 +42,5 @@ public interface MiniStrayAnimalMapper extends BaseMapper { IPage getMyAdoptedPage(Page page, @Param("userId") Long userId); + HomeStatsVO countHomeStats(); } diff --git a/src/main/java/com/youlai/boot/mini/model/query/StrayAnimalQuery.java b/src/main/java/com/youlai/boot/mini/model/query/StrayAnimalQuery.java index e8a254d..23583a9 100644 --- a/src/main/java/com/youlai/boot/mini/model/query/StrayAnimalQuery.java +++ b/src/main/java/com/youlai/boot/mini/model/query/StrayAnimalQuery.java @@ -17,4 +17,7 @@ public class StrayAnimalQuery extends BaseQuery { @Schema(description = "截止登记时间,毫秒级时间戳", example = "1776426078459") private Long createEndTimestamp; + + @Schema(description = "可见性范围:public-公开,private-仅自己,friends-仅好友", example = "public") + private String visibility; } diff --git a/src/main/java/com/youlai/boot/mini/model/vo/HomeStatsVO.java b/src/main/java/com/youlai/boot/mini/model/vo/HomeStatsVO.java new file mode 100644 index 0000000..ea37510 --- /dev/null +++ b/src/main/java/com/youlai/boot/mini/model/vo/HomeStatsVO.java @@ -0,0 +1,15 @@ +package com.youlai.boot.mini.model.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "首页统计数据") +public class HomeStatsVO { + + @Schema(description = "已登记动物总数") + private Long animalCount; + + @Schema(description = "爱心用户数(登记过动物的去重用户数)") + private Long caringUserCount; +} diff --git a/src/main/java/com/youlai/boot/mini/model/vo/TaskVO.java b/src/main/java/com/youlai/boot/mini/model/vo/TaskVO.java new file mode 100644 index 0000000..6509930 --- /dev/null +++ b/src/main/java/com/youlai/boot/mini/model/vo/TaskVO.java @@ -0,0 +1,30 @@ +package com.youlai.boot.mini.model.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "首页任务") +public class TaskVO { + + @Schema(description = "规则编码") + private String ruleCode; + + @Schema(description = "任务名称") + private String ruleName; + + @Schema(description = "奖励积分") + private Integer points; + + @Schema(description = "限制周期") + private String limitPeriod; + + @Schema(description = "周期内限制次数") + private Integer limitCount; + + @Schema(description = "当前周期已完成次数") + private Integer currentCount; + + @Schema(description = "是否已完成") + private Boolean completed; +} diff --git a/src/main/java/com/youlai/boot/mini/service/MiniPointRecordService.java b/src/main/java/com/youlai/boot/mini/service/MiniPointRecordService.java index 4fcb6de..477069f 100644 --- a/src/main/java/com/youlai/boot/mini/service/MiniPointRecordService.java +++ b/src/main/java/com/youlai/boot/mini/service/MiniPointRecordService.java @@ -5,6 +5,9 @@ import com.baomidou.mybatisplus.extension.service.IService; import com.youlai.boot.mini.model.entity.MiniPointRecord; import com.youlai.boot.mini.model.query.MyPointRecordQuery; import com.youlai.boot.mini.model.vo.MyPointRecordVO; +import com.youlai.boot.mini.model.vo.TaskVO; + +import java.util.List; public interface MiniPointRecordService extends IService { @@ -16,4 +19,5 @@ public interface MiniPointRecordService extends IService { Integer deductPoint(Long userId, String ruleCode, String bizId); + List listHomeTasks(Long userId); } diff --git a/src/main/java/com/youlai/boot/mini/service/StrayAnimalService.java b/src/main/java/com/youlai/boot/mini/service/StrayAnimalService.java index 79d88dd..8627c1d 100644 --- a/src/main/java/com/youlai/boot/mini/service/StrayAnimalService.java +++ b/src/main/java/com/youlai/boot/mini/service/StrayAnimalService.java @@ -15,6 +15,8 @@ import com.youlai.boot.mini.model.query.OwnStrayAnimalQuery; import com.youlai.boot.mini.model.query.WaterfallQuery; import com.youlai.boot.mini.model.vo.AdoptedAnimalVO; import com.youlai.boot.mini.model.vo.WaterfallResult; +import com.youlai.boot.mini.model.query.StrayAnimalQuery; +import com.youlai.boot.mini.model.vo.HomeStatsVO; import com.youlai.boot.mini.model.vo.SaveStrayAnimalVO; import com.youlai.boot.mini.model.vo.StrayAnimalDetailsVO; import com.youlai.boot.mini.model.vo.StrayAnimalNearbyVO; @@ -64,5 +66,9 @@ public interface StrayAnimalService extends IService { void increaseNoteViewCount(String noteUuid); IPage getMyAdoptedPage(Integer pageNum, Integer pageSize); + + IPage getHomePageList(StrayAnimalQuery queryParams); + + HomeStatsVO getHomeStats(); } diff --git a/src/main/java/com/youlai/boot/mini/service/impl/MiniPointRecordServiceImpl.java b/src/main/java/com/youlai/boot/mini/service/impl/MiniPointRecordServiceImpl.java index 52719ff..ada15eb 100644 --- a/src/main/java/com/youlai/boot/mini/service/impl/MiniPointRecordServiceImpl.java +++ b/src/main/java/com/youlai/boot/mini/service/impl/MiniPointRecordServiceImpl.java @@ -15,6 +15,7 @@ import com.youlai.boot.mini.model.entity.MiniPointRule; import com.youlai.boot.admin.model.form.AdjustUserPointForm; import com.youlai.boot.mini.model.query.MyPointRecordQuery; import com.youlai.boot.mini.model.vo.MyPointRecordVO; +import com.youlai.boot.mini.model.vo.TaskVO; import com.youlai.boot.mini.service.MiniPointAccountService; import com.youlai.boot.mini.service.MiniPointRecordService; import lombok.RequiredArgsConstructor; @@ -29,6 +30,8 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.time.temporal.TemporalAdjusters; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @@ -322,4 +325,81 @@ public class MiniPointRecordServiceImpl extends ServiceImpl listHomeTasks(Long userId) { + List rules = pointManageService.list(new LambdaQueryWrapper() + .eq(MiniPointRule::getStatus, false) + .gt(MiniPointRule::getPoints, 0) + .eq(MiniPointRule::getDeleted, 0)); + + LocalDate now = LocalDate.now(); + List tasks = new ArrayList<>(); + + for (MiniPointRule rule : rules) { + TaskVO vo = new TaskVO(); + vo.setRuleCode(rule.getRuleCode()); + vo.setRuleName(rule.getRuleName()); + vo.setPoints(rule.getPoints()); + vo.setLimitPeriod(rule.getLimitPeriod()); + vo.setLimitCount(rule.getLimitCount()); + + int currentCount = getTaskProgress(rule, userId, now); + vo.setCurrentCount(currentCount); + vo.setCompleted(rule.getLimitPeriod() != null + && rule.getLimitCount() != null + && currentCount >= rule.getLimitCount()); + + tasks.add(vo); + } + return tasks; + } + + private int getTaskProgress(MiniPointRule rule, Long userId, LocalDate now) { + String ruleCode = rule.getRuleCode(); + + if ("SIGN_IN_BASE".equals(ruleCode)) { + String dayKey = String.format(CommonConstants.SIGN_DAY_KEY, userId, + now.format(DateTimeFormatter.ofPattern("yyyyMMdd"))); + return Boolean.TRUE.equals(redisTemplate.hasKey(dayKey)) ? 1 : 0; + } + + String limitPeriod = rule.getLimitPeriod(); + if (limitPeriod == null) { + return 0; + } + + String bizPrefix = ruleCode.toLowerCase(); + String periodKey; + switch (limitPeriod) { + case "ALL": + periodKey = "all"; + break; + case "DAY": + periodKey = now.format(DateTimeFormatter.ofPattern("yyyyMMdd")); + break; + case "WEEK": + LocalDate monday = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)); + periodKey = monday.format(DateTimeFormatter.ofPattern("yyyyMMdd")); + break; + case "MONTH": + periodKey = now.format(DateTimeFormatter.ofPattern("yyyyMM")); + break; + case "YEAR": + periodKey = String.valueOf(now.getYear()); + break; + default: + return 0; + } + + String countKey = String.format(CommonConstants.REWARD_COUNT_KEY, bizPrefix, + limitPeriod.toLowerCase(), userId, periodKey); + try { + String countStr = redisTemplate.opsForValue().get(countKey); + return countStr != null ? Integer.parseInt(countStr) : 0; + } catch (Exception e) { + log.warn("读取任务进度Redis失败, key={}", countKey, e); + return 0; + } + } + } diff --git a/src/main/java/com/youlai/boot/mini/service/impl/StrayAnimalServiceImpl.java b/src/main/java/com/youlai/boot/mini/service/impl/StrayAnimalServiceImpl.java index 8efcf3d..a33ad52 100644 --- a/src/main/java/com/youlai/boot/mini/service/impl/StrayAnimalServiceImpl.java +++ b/src/main/java/com/youlai/boot/mini/service/impl/StrayAnimalServiceImpl.java @@ -56,6 +56,7 @@ import com.youlai.boot.mini.model.entity.MiniStrayAnimalNoteMedia; import com.youlai.boot.mini.model.form.StrayAnimalForm; import com.youlai.boot.mini.model.query.OwnStrayAnimalQuery; import com.youlai.boot.mini.model.query.WaterfallQuery; +import com.youlai.boot.mini.model.query.StrayAnimalQuery; import com.youlai.boot.mini.model.vo.*; import com.youlai.boot.mini.service.MiniPointRecordService; import com.youlai.boot.mini.service.MiniFollowService; @@ -767,6 +768,36 @@ public class StrayAnimalServiceImpl extends ServiceImpl getHomePageList(StrayAnimalQuery queryParams) { + Page page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize()); + + IPage result = this.miniStrayAnimalMapper.getHomePageList(page, queryParams); + if (result.getTotal() > 0) { + result.getRecords().forEach(item -> { + if (StrUtil.isBlank(item.getFirstImageUrl())) { + switch (item.getAnimalType()) { + case "cat": + item.setFirstImageUrl(getDefaultCatCoverHost() + "/default_cat.png"); + break; + case "dog": + item.setFirstImageUrl(getDefaultCatCoverHost() + "/default_dog.png"); + break; + default: + item.setFirstImageUrl(getDefaultCatCoverHost() + "/default_other.png"); + break; + } + } + }); + } + return result; + } + + @Override + public HomeStatsVO getHomeStats() { + return miniStrayAnimalMapper.countHomeStats(); + } + private IPage getAnimalPage(OwnStrayAnimalQuery queryParams) { // 参数构建 int pageNum = queryParams.getPageNum(); diff --git a/src/main/resources/mapper/mini/MiniStrayAnimalMapper.xml b/src/main/resources/mapper/mini/MiniStrayAnimalMapper.xml index 80ad4b2..28ac14b 100644 --- a/src/main/resources/mapper/mini/MiniStrayAnimalMapper.xml +++ b/src/main/resources/mapper/mini/MiniStrayAnimalMapper.xml @@ -216,6 +216,82 @@ + + + +