feat: 新增后台管理业务模块heritage-admin

- 新增用户管理:用户列表、详情、禁用启用等功能
- 新增新闻管理:新闻的增删改查、发布撤回等功能
- 新增活动管理:活动的增删改查、发布管理、报名管理等功能
- 新增非遗项目管理:项目的增删改查、审核上架等功能
- 新增传承人管理:传承人的增删改查、认证管理等功能
- 新增评论管理:评论审核、删除等功能
- 新增数据统计:平台数据统计、排行榜、趋势分析等功能
- 所有接口均配置Sa-Token权限验证和Swagger接口文档
This commit is contained in:
Leo 2025-10-15 22:30:46 +08:00
parent 9a9a279a39
commit 0f9a58b085
22 changed files with 3639 additions and 0 deletions

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.leocoder.heritage</groupId>
<artifactId>heritage-backend</artifactId>
<version>${revision}</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<name>heritage-admin</name>
<artifactId>heritage-admin</artifactId>
<description>后台管理模块</description>
<dependencies>
<!-- 公共模块 -->
<dependency>
<groupId>org.leocoder.heritage</groupId>
<artifactId>heritage-common</artifactId>
<version>${revision}</version>
</dependency>
<!-- 数据统一返回、全局异常以及限流、数据脱敏、重复提交等插件 -->
<dependency>
<groupId>org.leocoder.heritage</groupId>
<artifactId>heritage-resultex</artifactId>
<version>${revision}</version>
</dependency>
<!-- Sa-Token组件 -->
<dependency>
<groupId>org.leocoder.heritage</groupId>
<artifactId>heritage-sa-token</artifactId>
<version>${revision}</version>
</dependency>
<!-- 操作日志组件 -->
<dependency>
<groupId>org.leocoder.heritage</groupId>
<artifactId>heritage-oper-logs</artifactId>
<version>${revision}</version>
</dependency>
<!-- OSS存储组件 -->
<dependency>
<groupId>org.leocoder.heritage</groupId>
<artifactId>heritage-oss</artifactId>
<version>${revision}</version>
</dependency>
<!-- SpringDoc OpenAPI 3.0 -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,111 @@
package org.leocoder.heritage.admin.controller.comment;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.leocoder.heritage.admin.service.comment.HrtCommentAdminService;
import org.leocoder.heritage.domain.model.bo.admin.HrtCommentAdminBo;
import org.leocoder.heritage.domain.model.bo.admin.HrtCommentAdminQueryBo;
import org.leocoder.heritage.domain.model.vo.admin.HrtCommentAdminDetailVo;
import org.leocoder.heritage.domain.model.vo.admin.HrtCommentAdminVo;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author Leocoder
* @description [后台评论管理控制器]
*/
@Tag(name = "后台评论管理", description = "评论审核、删除、查询等管理功能")
@Validated
@RequestMapping("/coder/admin/comment")
@RequiredArgsConstructor
@RestController
public class HrtCommentAdminController {
private final HrtCommentAdminService commentAdminService;
/**
* @description [分页查询评论列表]
* @author Leocoder
*/
@Operation(summary = "分页查询评论列表", description = "根据查询条件分页获取评论列表,支持多条件筛选")
@SaCheckPermission("heritage:comment:list")
@GetMapping("/listPage")
public IPage<HrtCommentAdminVo> listPage(@Validated HrtCommentAdminQueryBo bo) {
return commentAdminService.listPage(bo);
}
/**
* @description [查看评论详情]
* @author Leocoder
*/
@Operation(summary = "查看评论详情", description = "根据评论ID获取评论的完整详细信息")
@SaCheckPermission("heritage:comment:detail")
@GetMapping("/detail/{id}")
public HrtCommentAdminDetailVo detail(@Parameter(description = "评论ID") @PathVariable Long id) {
return commentAdminService.getDetail(id);
}
/**
* @description [审核评论]
* @author Leocoder
*/
@Operation(summary = "审核评论", description = "审核评论(批准或拒绝)")
@SaCheckPermission("heritage:comment:audit")
@PutMapping("/audit")
public Boolean audit(@Validated @RequestBody HrtCommentAdminBo bo) {
return commentAdminService.auditComment(bo);
}
/**
* @description [批量审核评论]
* @author Leocoder
*/
@Operation(summary = "批量审核评论", description = "批量审核多个评论")
@SaCheckPermission("heritage:comment:audit")
@PutMapping("/batchAudit")
public Boolean batchAudit(
@Parameter(description = "评论ID列表") @RequestBody List<Long> ids,
@Parameter(description = "审核状态0-待审核1-已通过2-已拒绝") @RequestParam Integer status) {
return commentAdminService.batchAudit(ids, status);
}
/**
* @description [删除评论]
* @author Leocoder
*/
@Operation(summary = "删除评论", description = "删除指定评论,同时会删除该评论下的所有回复")
@SaCheckPermission("heritage:comment:delete")
@DeleteMapping("/delete/{id}")
public Boolean delete(@Parameter(description = "评论ID") @PathVariable Long id) {
return commentAdminService.deleteComment(id);
}
/**
* @description [批量删除评论]
* @author Leocoder
*/
@Operation(summary = "批量删除评论", description = "批量删除多个评论")
@SaCheckPermission("heritage:comment:delete")
@DeleteMapping("/batchDelete")
public Boolean batchDelete(@Parameter(description = "评论ID列表") @RequestBody List<Long> ids) {
return commentAdminService.batchDelete(ids);
}
/**
* @description [获取待审核评论数量]
* @author Leocoder
*/
@Operation(summary = "获取待审核评论数量", description = "获取待审核评论的数量")
@SaCheckPermission("heritage:comment:list")
@GetMapping("/pendingCount")
public Long getPendingCount() {
return commentAdminService.getPendingCount();
}
}

View File

@ -0,0 +1,124 @@
package org.leocoder.heritage.admin.controller.event;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.leocoder.heritage.admin.service.event.HrtEventAdminService;
import org.leocoder.heritage.domain.model.bo.admin.HrtEventAdminBo;
import org.leocoder.heritage.domain.model.bo.admin.HrtEventAdminQueryBo;
import org.leocoder.heritage.domain.model.vo.admin.HrtEventAdminDetailVo;
import org.leocoder.heritage.domain.model.vo.admin.HrtEventAdminVo;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author Leocoder
* @description [活动管理控制器]
*/
@Tag(name = "活动管理", description = "非遗活动的增删改查、状态管理和发布控制")
@Validated
@RequestMapping("/coder/admin/event")
@RequiredArgsConstructor
@RestController
public class HrtEventAdminController {
private final HrtEventAdminService eventAdminService;
/**
* @description [分页查询活动列表]
* @author Leocoder
*/
@Operation(summary = "分页查询活动列表", description = "根据查询条件分页获取活动列表,支持标题、地点、状态等多条件筛选")
@SaCheckPermission("heritage:event:list")
@GetMapping("/listPage")
public IPage<HrtEventAdminVo> listPage(@Validated HrtEventAdminQueryBo bo) {
return eventAdminService.listPage(bo);
}
/**
* @description [查看活动详情]
* @author Leocoder
*/
@Operation(summary = "查看活动详情", description = "根据活动ID获取活动的完整详细信息")
@SaCheckPermission("heritage:event:detail")
@GetMapping("/detail/{id}")
public HrtEventAdminDetailVo detail(@Parameter(description = "活动ID") @PathVariable Long id) {
return eventAdminService.getDetail(id);
}
/**
* @description [新增活动]
* @author Leocoder
*/
@Operation(summary = "新增活动", description = "创建新的非遗活动,包括活动信息、时间安排和报名设置")
@SaCheckPermission("heritage:event:add")
@PostMapping("/add")
public Long add(@Validated @RequestBody HrtEventAdminBo bo) {
return eventAdminService.addEvent(bo);
}
/**
* @description [编辑活动]
* @author Leocoder
*/
@Operation(summary = "编辑活动", description = "修改已存在活动的信息")
@SaCheckPermission("heritage:event:edit")
@PutMapping("/edit")
public Boolean edit(@Validated @RequestBody HrtEventAdminBo bo) {
return eventAdminService.editEvent(bo);
}
/**
* @description [删除活动]
* @author Leocoder
*/
@Operation(summary = "删除活动", description = "根据ID删除指定活动已有报名的活动不可删除")
@SaCheckPermission("heritage:event:delete")
@DeleteMapping("/delete/{id}")
public Boolean delete(@Parameter(description = "活动ID") @PathVariable Long id) {
return eventAdminService.deleteEvent(id);
}
/**
* @description [批量删除活动]
* @author Leocoder
*/
@Operation(summary = "批量删除活动", description = "批量删除多个活动(已有报名的活动不可删除)")
@SaCheckPermission("heritage:event:delete")
@DeleteMapping("/batchDelete")
public Boolean batchDelete(@Parameter(description = "活动ID列表") @RequestBody List<Long> ids) {
return eventAdminService.batchDelete(ids);
}
/**
* @description [修改发布状态]
* @author Leocoder
*/
@Operation(summary = "修改发布状态", description = "修改活动的发布状态0-草稿1-已发布)")
@SaCheckPermission("heritage:event:status")
@PutMapping("/changePublishStatus")
public Boolean changePublishStatus(
@Parameter(description = "活动ID") @RequestParam Long id,
@Parameter(description = "发布状态0-草稿1-已发布") @RequestParam Integer publishStatus) {
return eventAdminService.changePublishStatus(id, publishStatus);
}
/**
* @description [修改活动状态]
* @author Leocoder
*/
@Operation(summary = "修改活动状态", description = "修改活动的状态upcoming-即将开始、ongoing-进行中、finished-已结束、cancelled-已取消)")
@SaCheckPermission("heritage:event:status")
@PutMapping("/changeEventStatus")
public Boolean changeEventStatus(
@Parameter(description = "活动ID") @RequestParam Long id,
@Parameter(description = "活动状态upcoming、ongoing、finished、cancelled") @RequestParam String status) {
return eventAdminService.changeEventStatus(id, status);
}
}

View File

@ -0,0 +1,124 @@
package org.leocoder.heritage.admin.controller.heritage;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.leocoder.heritage.admin.service.heritage.HrtHeritageAdminService;
import org.leocoder.heritage.domain.model.bo.admin.HrtHeritageAdminBo;
import org.leocoder.heritage.domain.model.bo.admin.HrtHeritageAdminQueryBo;
import org.leocoder.heritage.domain.model.vo.admin.HrtHeritageAdminDetailVo;
import org.leocoder.heritage.domain.model.vo.admin.HrtHeritageAdminVo;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author Leocoder
* @description [非遗项目管理控制器]
*/
@Tag(name = "非遗项目管理", description = "后台管理非遗项目的增删改查、审核、发布等功能")
@Validated
@RequestMapping("/coder/admin/heritage")
@RequiredArgsConstructor
@RestController
public class HrtHeritageAdminController {
private final HrtHeritageAdminService hrtHeritageAdminService;
/**
* @description [分页查询非遗项目列表]
* @author Leocoder
*/
@Operation(summary = "分页查询非遗项目列表", description = "支持多条件筛选和关键词搜索,包含草稿和已发布的项目")
@SaCheckPermission("heritage:items:list")
@GetMapping("/listPage")
public IPage<HrtHeritageAdminVo> listPage(@Validated HrtHeritageAdminQueryBo bo) {
return hrtHeritageAdminService.listPage(bo);
}
/**
* @description [查看非遗项目详情]
* @author Leocoder
*/
@Operation(summary = "查看非遗项目详情", description = "根据ID查看非遗项目的完整详细信息")
@SaCheckPermission("heritage:items:detail")
@GetMapping("/detail/{id}")
public HrtHeritageAdminDetailVo detail(@Parameter(description = "非遗项目ID") @PathVariable Long id) {
return hrtHeritageAdminService.getDetail(id);
}
/**
* @description [新增非遗项目]
* @author Leocoder
*/
@Operation(summary = "新增非遗项目", description = "新增一个非遗项目返回新增项目的ID")
@SaCheckPermission("heritage:items:add")
@PostMapping("/add")
public Long add(@Validated @RequestBody HrtHeritageAdminBo bo) {
return hrtHeritageAdminService.addHeritage(bo);
}
/**
* @description [编辑非遗项目]
* @author Leocoder
*/
@Operation(summary = "编辑非遗项目", description = "根据ID编辑非遗项目信息")
@SaCheckPermission("heritage:items:edit")
@PutMapping("/edit")
public Boolean edit(@Validated @RequestBody HrtHeritageAdminBo bo) {
return hrtHeritageAdminService.editHeritage(bo);
}
/**
* @description [删除非遗项目]
* @author Leocoder
*/
@Operation(summary = "删除非遗项目", description = "根据ID逻辑删除非遗项目")
@SaCheckPermission("heritage:items:delete")
@DeleteMapping("/delete/{id}")
public Boolean delete(@Parameter(description = "非遗项目ID") @PathVariable Long id) {
return hrtHeritageAdminService.deleteHeritage(id);
}
/**
* @description [批量删除非遗项目]
* @author Leocoder
*/
@Operation(summary = "批量删除非遗项目", description = "根据ID列表批量逻辑删除非遗项目")
@SaCheckPermission("heritage:items:delete")
@DeleteMapping("/batchDelete")
public Boolean batchDelete(@Parameter(description = "非遗项目ID列表") @RequestBody List<Long> ids) {
return hrtHeritageAdminService.batchDelete(ids);
}
/**
* @description [修改发布状态]
* @author Leocoder
*/
@Operation(summary = "修改发布状态", description = "修改非遗项目的发布状态0-草稿1-已发布)")
@SaCheckPermission("heritage:items:status")
@PutMapping("/changePublishStatus")
public Boolean changePublishStatus(
@Parameter(description = "非遗项目ID") @RequestParam Long id,
@Parameter(description = "发布状态0-草稿1-已发布") @RequestParam Integer publishStatus) {
return hrtHeritageAdminService.changePublishStatus(id, publishStatus);
}
/**
* @description [设置精选状态]
* @author Leocoder
*/
@Operation(summary = "设置精选状态", description = "设置非遗项目是否为精选项目0-否1-是)")
@SaCheckPermission("heritage:items:status")
@PutMapping("/setFeatured")
public Boolean setFeatured(
@Parameter(description = "非遗项目ID") @RequestParam Long id,
@Parameter(description = "精选状态0-否1-是") @RequestParam Integer isFeatured) {
return hrtHeritageAdminService.setFeatured(id, isFeatured);
}
}

View File

@ -0,0 +1,124 @@
package org.leocoder.heritage.admin.controller.inheritor;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.leocoder.heritage.admin.service.inheritor.HrtInheritorAdminService;
import org.leocoder.heritage.domain.model.bo.admin.HrtInheritorAdminBo;
import org.leocoder.heritage.domain.model.bo.admin.HrtInheritorAdminQueryBo;
import org.leocoder.heritage.domain.model.vo.admin.HrtInheritorAdminDetailVo;
import org.leocoder.heritage.domain.model.vo.admin.HrtInheritorAdminVo;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author Leocoder
* @description [传承人管理控制器]
*/
@Tag(name = "传承人管理", description = "后台管理传承人的增删改查、审核、发布等功能")
@Validated
@RequestMapping("/coder/admin/inheritor")
@RequiredArgsConstructor
@RestController
public class HrtInheritorAdminController {
private final HrtInheritorAdminService hrtInheritorAdminService;
/**
* @description [分页查询传承人列表]
* @author Leocoder
*/
@Operation(summary = "分页查询传承人列表", description = "支持多条件筛选和关键词搜索,包含草稿和已发布的传承人")
@SaCheckPermission("heritage:inheritors:list")
@GetMapping("/listPage")
public IPage<HrtInheritorAdminVo> listPage(@Validated HrtInheritorAdminQueryBo bo) {
return hrtInheritorAdminService.listPage(bo);
}
/**
* @description [查看传承人详情]
* @author Leocoder
*/
@Operation(summary = "查看传承人详情", description = "根据ID查看传承人的完整详细信息")
@SaCheckPermission("heritage:inheritors:detail")
@GetMapping("/detail/{id}")
public HrtInheritorAdminDetailVo detail(@Parameter(description = "传承人ID") @PathVariable Long id) {
return hrtInheritorAdminService.getDetail(id);
}
/**
* @description [新增传承人]
* @author Leocoder
*/
@Operation(summary = "新增传承人", description = "新增一个传承人返回新增传承人的ID")
@SaCheckPermission("heritage:inheritors:add")
@PostMapping("/add")
public Long add(@Validated @RequestBody HrtInheritorAdminBo bo) {
return hrtInheritorAdminService.addInheritor(bo);
}
/**
* @description [编辑传承人]
* @author Leocoder
*/
@Operation(summary = "编辑传承人", description = "根据ID编辑传承人信息")
@SaCheckPermission("heritage:inheritors:edit")
@PutMapping("/edit")
public Boolean edit(@Validated @RequestBody HrtInheritorAdminBo bo) {
return hrtInheritorAdminService.editInheritor(bo);
}
/**
* @description [删除传承人]
* @author Leocoder
*/
@Operation(summary = "删除传承人", description = "根据ID逻辑删除传承人")
@SaCheckPermission("heritage:inheritors:delete")
@DeleteMapping("/delete/{id}")
public Boolean delete(@Parameter(description = "传承人ID") @PathVariable Long id) {
return hrtInheritorAdminService.deleteInheritor(id);
}
/**
* @description [批量删除传承人]
* @author Leocoder
*/
@Operation(summary = "批量删除传承人", description = "根据ID列表批量逻辑删除传承人")
@SaCheckPermission("heritage:inheritors:delete")
@DeleteMapping("/batchDelete")
public Boolean batchDelete(@Parameter(description = "传承人ID列表") @RequestBody List<Long> ids) {
return hrtInheritorAdminService.batchDelete(ids);
}
/**
* @description [修改发布状态]
* @author Leocoder
*/
@Operation(summary = "修改发布状态", description = "修改传承人的发布状态0-草稿1-已发布)")
@SaCheckPermission("heritage:inheritors:status")
@PutMapping("/changePublishStatus")
public Boolean changePublishStatus(
@Parameter(description = "传承人ID") @RequestParam Long id,
@Parameter(description = "发布状态0-草稿1-已发布") @RequestParam Integer publishStatus) {
return hrtInheritorAdminService.changePublishStatus(id, publishStatus);
}
/**
* @description [设置精选状态]
* @author Leocoder
*/
@Operation(summary = "设置精选状态", description = "设置传承人是否为精选传承人0-否1-是)")
@SaCheckPermission("heritage:inheritors:status")
@PutMapping("/setFeatured")
public Boolean setFeatured(
@Parameter(description = "传承人ID") @RequestParam Long id,
@Parameter(description = "精选状态0-否1-是") @RequestParam Integer isFeatured) {
return hrtInheritorAdminService.setFeatured(id, isFeatured);
}
}

View File

@ -0,0 +1,124 @@
package org.leocoder.heritage.admin.controller.news;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.leocoder.heritage.admin.service.news.HrtNewsAdminService;
import org.leocoder.heritage.domain.model.bo.admin.HrtNewsAdminBo;
import org.leocoder.heritage.domain.model.bo.admin.HrtNewsAdminQueryBo;
import org.leocoder.heritage.domain.model.vo.admin.HrtNewsAdminDetailVo;
import org.leocoder.heritage.domain.model.vo.admin.HrtNewsAdminVo;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author Leocoder
* @description [新闻资讯管理控制器]
*/
@Tag(name = "新闻资讯管理", description = "后台管理新闻资讯的增删改查、审核、发布等功能")
@Validated
@RequestMapping("/coder/admin/news")
@RequiredArgsConstructor
@RestController
public class HrtNewsAdminController {
private final HrtNewsAdminService hrtNewsAdminService;
/**
* @description [分页查询新闻资讯列表]
* @author Leocoder
*/
@Operation(summary = "分页查询新闻资讯列表", description = "支持多条件筛选和关键词搜索,包含草稿和已发布的新闻")
@SaCheckPermission("heritage:news:list")
@GetMapping("/listPage")
public IPage<HrtNewsAdminVo> listPage(@Validated HrtNewsAdminQueryBo bo) {
return hrtNewsAdminService.listPage(bo);
}
/**
* @description [查看新闻资讯详情]
* @author Leocoder
*/
@Operation(summary = "查看新闻资讯详情", description = "根据ID查看新闻资讯的完整详细信息")
@SaCheckPermission("heritage:news:detail")
@GetMapping("/detail/{id}")
public HrtNewsAdminDetailVo detail(@Parameter(description = "新闻资讯ID") @PathVariable Long id) {
return hrtNewsAdminService.getDetail(id);
}
/**
* @description [新增新闻资讯]
* @author Leocoder
*/
@Operation(summary = "新增新闻资讯", description = "新增一条新闻资讯返回新增新闻的ID")
@SaCheckPermission("heritage:news:add")
@PostMapping("/add")
public Long add(@Validated @RequestBody HrtNewsAdminBo bo) {
return hrtNewsAdminService.addNews(bo);
}
/**
* @description [编辑新闻资讯]
* @author Leocoder
*/
@Operation(summary = "编辑新闻资讯", description = "根据ID编辑新闻资讯信息")
@SaCheckPermission("heritage:news:edit")
@PutMapping("/edit")
public Boolean edit(@Validated @RequestBody HrtNewsAdminBo bo) {
return hrtNewsAdminService.editNews(bo);
}
/**
* @description [删除新闻资讯]
* @author Leocoder
*/
@Operation(summary = "删除新闻资讯", description = "根据ID逻辑删除新闻资讯")
@SaCheckPermission("heritage:news:delete")
@DeleteMapping("/delete/{id}")
public Boolean delete(@Parameter(description = "新闻资讯ID") @PathVariable Long id) {
return hrtNewsAdminService.deleteNews(id);
}
/**
* @description [批量删除新闻资讯]
* @author Leocoder
*/
@Operation(summary = "批量删除新闻资讯", description = "根据ID列表批量逻辑删除新闻资讯")
@SaCheckPermission("heritage:news:delete")
@DeleteMapping("/batchDelete")
public Boolean batchDelete(@Parameter(description = "新闻资讯ID列表") @RequestBody List<Long> ids) {
return hrtNewsAdminService.batchDelete(ids);
}
/**
* @description [修改发布状态]
* @author Leocoder
*/
@Operation(summary = "修改发布状态", description = "修改新闻资讯的发布状态0-草稿1-已发布)")
@SaCheckPermission("heritage:news:status")
@PutMapping("/changePublishStatus")
public Boolean changePublishStatus(
@Parameter(description = "新闻资讯ID") @RequestParam Long id,
@Parameter(description = "发布状态0-草稿1-已发布") @RequestParam Integer publishStatus) {
return hrtNewsAdminService.changePublishStatus(id, publishStatus);
}
/**
* @description [设置置顶状态]
* @author Leocoder
*/
@Operation(summary = "设置置顶状态", description = "设置新闻资讯是否置顶显示0-否1-是)")
@SaCheckPermission("heritage:news:status")
@PutMapping("/setTop")
public Boolean setTop(
@Parameter(description = "新闻资讯ID") @RequestParam Long id,
@Parameter(description = "置顶状态0-否1-是") @RequestParam Integer isTop) {
return hrtNewsAdminService.setTop(id, isTop);
}
}

View File

@ -0,0 +1,90 @@
package org.leocoder.heritage.admin.controller.statistics;
import cn.dev33.satoken.annotation.SaCheckPermission;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.leocoder.heritage.admin.service.statistics.HrtStatisticsService;
import org.leocoder.heritage.domain.model.vo.admin.HrtRankingVo;
import org.leocoder.heritage.domain.model.vo.admin.HrtStatisticsVo;
import org.leocoder.heritage.domain.model.vo.admin.HrtTrendVo;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author Leocoder
* @description [统计分析控制器]
*/
@Tag(name = "统计分析管理", description = "平台数据统计、趋势分析和排行榜功能")
@Validated
@RequestMapping("/coder/admin/statistics")
@RequiredArgsConstructor
@RestController
public class HrtStatisticsController {
private final HrtStatisticsService statisticsService;
/**
* @description [获取核心统计数据]
* @author Leocoder
*/
@Operation(summary = "获取核心统计数据", description = "获取平台核心数据统计,包括非遗项目、用户、评论、点赞、收藏等数据")
@SaCheckPermission("heritage:statistics:view")
@GetMapping("/core")
public HrtStatisticsVo getStatistics() {
return statisticsService.getStatistics();
}
/**
* @description [获取用户增长趋势]
* @author Leocoder
*/
@Operation(summary = "获取用户增长趋势", description = "获取最近7天或30天的用户注册增长趋势数据")
@SaCheckPermission("heritage:statistics:view")
@GetMapping("/userTrend")
public List<HrtTrendVo> getUserTrend(
@Parameter(description = "天数7或30") @RequestParam(defaultValue = "7") Integer days) {
return statisticsService.getUserTrend(days);
}
/**
* @description [获取内容发布趋势]
* @author Leocoder
*/
@Operation(summary = "获取内容发布趋势", description = "获取最近7天或30天的内容发布趋势数据非遗项目+新闻+活动)")
@SaCheckPermission("heritage:statistics:view")
@GetMapping("/contentTrend")
public List<HrtTrendVo> getContentTrend(
@Parameter(description = "天数7或30") @RequestParam(defaultValue = "7") Integer days) {
return statisticsService.getContentTrend(days);
}
/**
* @description [获取热门非遗项目排行榜]
* @author Leocoder
*/
@Operation(summary = "获取热门非遗项目排行榜", description = "获取热门非遗项目TOP榜单支持按浏览量或收藏数排序")
@SaCheckPermission("heritage:statistics:view")
@GetMapping("/heritageRanking")
public List<HrtRankingVo> getHeritageRanking(
@Parameter(description = "排序类型view-浏览量favorite-收藏数") @RequestParam(defaultValue = "view") String type,
@Parameter(description = "返回数量") @RequestParam(defaultValue = "10") Integer limit) {
return statisticsService.getHeritageRanking(type, limit);
}
/**
* @description [获取活跃用户排行榜]
* @author Leocoder
*/
@Operation(summary = "获取活跃用户排行榜", description = "获取活跃用户TOP榜单根据评论、点赞、收藏等行为综合计算")
@SaCheckPermission("heritage:statistics:view")
@GetMapping("/activeUserRanking")
public List<HrtRankingVo> getActiveUserRanking(
@Parameter(description = "返回数量") @RequestParam(defaultValue = "10") Integer limit) {
return statisticsService.getActiveUserRanking(limit);
}
}

View File

@ -0,0 +1,124 @@
package org.leocoder.heritage.admin.controller.user;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.leocoder.heritage.admin.service.user.HrtUserAdminService;
import org.leocoder.heritage.domain.model.bo.admin.HrtUserAdminBo;
import org.leocoder.heritage.domain.model.bo.admin.HrtUserAdminQueryBo;
import org.leocoder.heritage.domain.model.vo.admin.HrtUserAdminDetailVo;
import org.leocoder.heritage.domain.model.vo.admin.HrtUserAdminVo;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author Leocoder
* @description [前台用户管理控制器]
*/
@Tag(name = "前台用户管理", description = "前台用户的增删改查、状态管理和密码重置")
@Validated
@RequestMapping("/coder/admin/user")
@RequiredArgsConstructor
@RestController
public class HrtUserAdminController {
private final HrtUserAdminService userAdminService;
/**
* @description [分页查询用户列表]
* @author Leocoder
*/
@Operation(summary = "分页查询用户列表", description = "根据查询条件分页获取前台用户列表,支持用户名、昵称、手机号等多条件筛选")
@SaCheckPermission("heritage:user:list")
@GetMapping("/listPage")
public IPage<HrtUserAdminVo> listPage(@Validated HrtUserAdminQueryBo bo) {
return userAdminService.listPage(bo);
}
/**
* @description [查看用户详情]
* @author Leocoder
*/
@Operation(summary = "查看用户详情", description = "根据用户ID获取用户的完整详细信息")
@SaCheckPermission("heritage:user:detail")
@GetMapping("/detail/{id}")
public HrtUserAdminDetailVo detail(@Parameter(description = "用户ID") @PathVariable Long id) {
return userAdminService.getDetail(id);
}
/**
* @description [新增用户]
* @author Leocoder
*/
@Operation(summary = "新增用户", description = "创建新的前台用户,包括用户基本信息和初始密码设置")
@SaCheckPermission("heritage:user:add")
@PostMapping("/add")
public Long add(@Validated @RequestBody HrtUserAdminBo bo) {
return userAdminService.addUser(bo);
}
/**
* @description [编辑用户]
* @author Leocoder
*/
@Operation(summary = "编辑用户", description = "修改已存在用户的信息,可选择性更新密码")
@SaCheckPermission("heritage:user:edit")
@PutMapping("/edit")
public Boolean edit(@Validated @RequestBody HrtUserAdminBo bo) {
return userAdminService.editUser(bo);
}
/**
* @description [删除用户]
* @author Leocoder
*/
@Operation(summary = "删除用户", description = "根据ID删除指定用户")
@SaCheckPermission("heritage:user:delete")
@DeleteMapping("/delete/{id}")
public Boolean delete(@Parameter(description = "用户ID") @PathVariable Long id) {
return userAdminService.deleteUser(id);
}
/**
* @description [批量删除用户]
* @author Leocoder
*/
@Operation(summary = "批量删除用户", description = "批量删除多个用户")
@SaCheckPermission("heritage:user:delete")
@DeleteMapping("/batchDelete")
public Boolean batchDelete(@Parameter(description = "用户ID列表") @RequestBody List<Long> ids) {
return userAdminService.batchDelete(ids);
}
/**
* @description [修改用户状态]
* @author Leocoder
*/
@Operation(summary = "修改用户状态", description = "修改用户的启用/禁用状态0-禁用1-正常)")
@SaCheckPermission("heritage:user:status")
@PutMapping("/changeStatus")
public Boolean changeStatus(
@Parameter(description = "用户ID") @RequestParam Long id,
@Parameter(description = "用户状态0-禁用1-正常") @RequestParam Integer status) {
return userAdminService.changeStatus(id, status);
}
/**
* @description [重置用户密码]
* @author Leocoder
*/
@Operation(summary = "重置用户密码", description = "管理员重置指定用户的登录密码")
@SaCheckPermission("heritage:user:edit")
@PutMapping("/resetPassword")
public Boolean resetPassword(
@Parameter(description = "用户ID") @RequestParam Long id,
@Parameter(description = "新密码") @RequestParam String newPassword) {
return userAdminService.resetPassword(id, newPassword);
}
}

View File

@ -0,0 +1,59 @@
package org.leocoder.heritage.admin.service.comment;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.leocoder.heritage.domain.model.bo.admin.HrtCommentAdminBo;
import org.leocoder.heritage.domain.model.bo.admin.HrtCommentAdminQueryBo;
import org.leocoder.heritage.domain.model.vo.admin.HrtCommentAdminDetailVo;
import org.leocoder.heritage.domain.model.vo.admin.HrtCommentAdminVo;
import java.util.List;
/**
* @author Leocoder
* @description [后台评论管理服务接口]
*/
public interface HrtCommentAdminService {
/**
* @description [分页查询评论列表]
* @author Leocoder
*/
IPage<HrtCommentAdminVo> listPage(HrtCommentAdminQueryBo bo);
/**
* @description [查看评论详情]
* @author Leocoder
*/
HrtCommentAdminDetailVo getDetail(Long id);
/**
* @description [审核评论]
* @author Leocoder
*/
Boolean auditComment(HrtCommentAdminBo bo);
/**
* @description [批量审核评论]
* @author Leocoder
*/
Boolean batchAudit(List<Long> ids, Integer status);
/**
* @description [删除评论]
* @author Leocoder
*/
Boolean deleteComment(Long id);
/**
* @description [批量删除评论]
* @author Leocoder
*/
Boolean batchDelete(List<Long> ids);
/**
* @description [获取待审核评论数量]
* @author Leocoder
*/
Long getPendingCount();
}

View File

@ -0,0 +1,293 @@
package org.leocoder.heritage.admin.service.comment;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.leocoder.heritage.common.exception.BusinessException;
import org.leocoder.heritage.domain.model.bo.admin.HrtCommentAdminBo;
import org.leocoder.heritage.domain.model.bo.admin.HrtCommentAdminQueryBo;
import org.leocoder.heritage.domain.model.vo.admin.HrtCommentAdminDetailVo;
import org.leocoder.heritage.domain.model.vo.admin.HrtCommentAdminVo;
import org.leocoder.heritage.domain.pojo.portal.*;
import org.leocoder.heritage.mybatisplus.mapper.portal.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Objects;
/**
* @author Leocoder
* @description [后台评论管理服务实现类]
*/
@Service
@RequiredArgsConstructor
public class HrtCommentAdminServiceImpl implements HrtCommentAdminService {
private final HrtCommentMapper commentMapper;
private final HrtUserMapper userMapper;
private final HrtHeritageMapper heritageMapper;
private final HrtInheritorMapper inheritorMapper;
private final HrtNewsMapper newsMapper;
private final HrtEventMapper eventMapper;
/**
* @description [分页查询评论列表]
* @author Leocoder
*/
@Override
public IPage<HrtCommentAdminVo> listPage(HrtCommentAdminQueryBo bo) {
Page<HrtComment> page = new Page<>(bo.getPageNum(), bo.getPageSize());
LambdaQueryWrapper<HrtComment> wrapper = new LambdaQueryWrapper<>();
// 用户ID查询
wrapper.eq(Objects.nonNull(bo.getUserId()), HrtComment::getUserId, bo.getUserId());
// 目标类型查询
wrapper.eq(StrUtil.isNotEmpty(bo.getTargetType()), HrtComment::getTargetType, bo.getTargetType());
// 目标ID查询
wrapper.eq(Objects.nonNull(bo.getTargetId()), HrtComment::getTargetId, bo.getTargetId());
// 评论内容模糊查询
wrapper.like(StrUtil.isNotEmpty(bo.getContent()), HrtComment::getContent, bo.getContent());
// 状态查询
wrapper.eq(Objects.nonNull(bo.getStatus()), HrtComment::getStatus, bo.getStatus());
// 时间范围查询
if (StrUtil.isNotEmpty(bo.getStartTime())) {
LocalDateTime startDateTime = LocalDate.parse(bo.getStartTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd"))
.atStartOfDay();
wrapper.ge(HrtComment::getCreateTime, startDateTime);
}
if (StrUtil.isNotEmpty(bo.getEndTime())) {
LocalDateTime endDateTime = LocalDate.parse(bo.getEndTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd"))
.atTime(LocalTime.MAX);
wrapper.le(HrtComment::getCreateTime, endDateTime);
}
// 按创建时间倒序排序
wrapper.orderByDesc(HrtComment::getCreateTime);
IPage<HrtComment> commentPage = commentMapper.selectPage(page, wrapper);
// 转换为VO并补充用户信息和目标信息
return commentPage.convert(comment -> {
HrtCommentAdminVo vo = BeanUtil.copyProperties(comment, HrtCommentAdminVo.class);
// 补充用户信息
HrtUser user = userMapper.selectById(comment.getUserId());
if (user != null) {
vo.setUsername(user.getUsername());
vo.setNickname(user.getNickname());
vo.setAvatar(user.getAvatar());
}
// 补充目标信息
fillTargetInfo(vo, comment.getTargetType(), comment.getTargetId());
return vo;
});
}
/**
* @description [查看评论详情]
* @author Leocoder
*/
@Override
public HrtCommentAdminDetailVo getDetail(Long id) {
HrtComment comment = commentMapper.selectById(id);
if (comment == null) {
throw new BusinessException(404, "评论不存在");
}
HrtCommentAdminDetailVo vo = BeanUtil.copyProperties(comment, HrtCommentAdminDetailVo.class);
// 补充用户详细信息
HrtUser user = userMapper.selectById(comment.getUserId());
if (user != null) {
vo.setUsername(user.getUsername());
vo.setNickname(user.getNickname());
vo.setAvatar(user.getAvatar());
vo.setPhone(user.getPhone());
vo.setEmail(user.getEmail());
}
// 补充目标信息
fillTargetInfo(vo, comment.getTargetType(), comment.getTargetId());
// 补充父评论信息
if (comment.getParentId() != null && comment.getParentId() > 0) {
HrtComment parentComment = commentMapper.selectById(comment.getParentId());
if (parentComment != null) {
vo.setParentContent(parentComment.getContent());
// 获取父评论用户昵称
HrtUser parentUser = userMapper.selectById(parentComment.getUserId());
if (parentUser != null) {
vo.setParentUserNickname(parentUser.getNickname());
}
}
}
// 查询回复数量
LambdaQueryWrapper<HrtComment> replyWrapper = new LambdaQueryWrapper<>();
replyWrapper.eq(HrtComment::getParentId, id);
Long replyCount = commentMapper.selectCount(replyWrapper);
vo.setReplyCount(replyCount.intValue());
return vo;
}
/**
* @description [审核评论]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean auditComment(HrtCommentAdminBo bo) {
HrtComment comment = commentMapper.selectById(bo.getId());
if (comment == null) {
throw new BusinessException(404, "评论不存在");
}
if (bo.getStatus() == null || (bo.getStatus() != 0 && bo.getStatus() != 1 && bo.getStatus() != 2)) {
throw new BusinessException(400, "审核状态参数错误");
}
HrtComment updateComment = new HrtComment();
updateComment.setId(bo.getId());
updateComment.setStatus(bo.getStatus());
int result = commentMapper.updateById(updateComment);
return result > 0;
}
/**
* @description [批量审核评论]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean batchAudit(List<Long> ids, Integer status) {
if (ids == null || ids.isEmpty()) {
throw new BusinessException(400, "请选择要审核的评论");
}
if (status == null || (status != 0 && status != 1 && status != 2)) {
throw new BusinessException(400, "审核状态参数错误");
}
for (Long id : ids) {
HrtComment updateComment = new HrtComment();
updateComment.setId(id);
updateComment.setStatus(status);
commentMapper.updateById(updateComment);
}
return true;
}
/**
* @description [删除评论]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean deleteComment(Long id) {
HrtComment comment = commentMapper.selectById(id);
if (comment == null) {
throw new BusinessException(404, "评论不存在");
}
// 删除该评论的所有回复
LambdaQueryWrapper<HrtComment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(HrtComment::getParentId, id);
commentMapper.delete(wrapper);
// 删除评论本身
int result = commentMapper.deleteById(id);
return result > 0;
}
/**
* @description [批量删除评论]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean batchDelete(List<Long> ids) {
if (ids == null || ids.isEmpty()) {
throw new BusinessException(400, "请选择要删除的评论");
}
for (Long id : ids) {
deleteComment(id);
}
return true;
}
/**
* @description [获取待审核评论数量]
* @author Leocoder
*/
@Override
public Long getPendingCount() {
LambdaQueryWrapper<HrtComment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(HrtComment::getStatus, 0);
return commentMapper.selectCount(wrapper);
}
/**
* @description [补充目标信息]
* @author Leocoder
*/
private void fillTargetInfo(Object vo, String targetType, Long targetId) {
String targetTitle = null;
switch (targetType) {
case "heritage":
HrtHeritage heritage = heritageMapper.selectById(targetId);
if (heritage != null) {
targetTitle = heritage.getName();
}
break;
case "inheritor":
HrtInheritor inheritor = inheritorMapper.selectById(targetId);
if (inheritor != null) {
targetTitle = inheritor.getName();
}
break;
case "news":
HrtNews news = newsMapper.selectById(targetId);
if (news != null) {
targetTitle = news.getTitle();
}
break;
case "event":
HrtEvent event = eventMapper.selectById(targetId);
if (event != null) {
targetTitle = event.getTitle();
}
break;
}
// 使用反射设置targetTitle
if (vo instanceof HrtCommentAdminVo) {
((HrtCommentAdminVo) vo).setTargetTitle(targetTitle);
} else if (vo instanceof HrtCommentAdminDetailVo) {
((HrtCommentAdminDetailVo) vo).setTargetTitle(targetTitle);
}
}
}

View File

@ -0,0 +1,65 @@
package org.leocoder.heritage.admin.service.event;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.leocoder.heritage.domain.model.bo.admin.HrtEventAdminBo;
import org.leocoder.heritage.domain.model.bo.admin.HrtEventAdminQueryBo;
import org.leocoder.heritage.domain.model.vo.admin.HrtEventAdminDetailVo;
import org.leocoder.heritage.domain.model.vo.admin.HrtEventAdminVo;
import java.util.List;
/**
* @author Leocoder
* @description [活动管理服务接口]
*/
public interface HrtEventAdminService {
/**
* @description [分页查询活动列表后台管理]
* @author Leocoder
*/
IPage<HrtEventAdminVo> listPage(HrtEventAdminQueryBo bo);
/**
* @description [查看活动详情后台管理]
* @author Leocoder
*/
HrtEventAdminDetailVo getDetail(Long id);
/**
* @description [新增活动]
* @author Leocoder
*/
Long addEvent(HrtEventAdminBo bo);
/**
* @description [编辑活动]
* @author Leocoder
*/
Boolean editEvent(HrtEventAdminBo bo);
/**
* @description [删除活动]
* @author Leocoder
*/
Boolean deleteEvent(Long id);
/**
* @description [批量删除活动]
* @author Leocoder
*/
Boolean batchDelete(List<Long> ids);
/**
* @description [修改发布状态]
* @author Leocoder
*/
Boolean changePublishStatus(Long id, Integer publishStatus);
/**
* @description [修改活动状态]
* @author Leocoder
*/
Boolean changeEventStatus(Long id, String status);
}

View File

@ -0,0 +1,307 @@
package org.leocoder.heritage.admin.service.event;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.leocoder.heritage.common.exception.BusinessException;
import org.leocoder.heritage.domain.model.bo.admin.HrtEventAdminBo;
import org.leocoder.heritage.domain.model.bo.admin.HrtEventAdminQueryBo;
import org.leocoder.heritage.domain.pojo.portal.HrtEvent;
import org.leocoder.heritage.domain.model.vo.admin.HrtEventAdminDetailVo;
import org.leocoder.heritage.domain.model.vo.admin.HrtEventAdminVo;
import org.leocoder.heritage.mybatisplus.mapper.portal.HrtEventMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
/**
* @author Leocoder
* @description [活动管理服务实现类]
*/
@Service
@RequiredArgsConstructor
public class HrtEventAdminServiceImpl implements HrtEventAdminService {
private final HrtEventMapper eventMapper;
/**
* @description [分页查询活动列表后台管理]
* @author Leocoder
*/
@Override
public IPage<HrtEventAdminVo> listPage(HrtEventAdminQueryBo bo) {
Page<HrtEvent> page = new Page<>(bo.getPageNum(), bo.getPageSize());
LambdaQueryWrapper<HrtEvent> wrapper = new LambdaQueryWrapper<>();
// 标题模糊查询
wrapper.like(StrUtil.isNotEmpty(bo.getTitle()), HrtEvent::getTitle, bo.getTitle());
// 地点模糊查询
wrapper.like(StrUtil.isNotEmpty(bo.getLocation()), HrtEvent::getLocation, bo.getLocation());
// 状态精确查询
wrapper.eq(StrUtil.isNotEmpty(bo.getStatus()), HrtEvent::getStatus, bo.getStatus());
// 发布状态查询
wrapper.eq(Objects.nonNull(bo.getPublishStatus()), HrtEvent::getPublishStatus, bo.getPublishStatus());
// 关键词搜索标题摘要内容
if (StrUtil.isNotEmpty(bo.getKeyword())) {
wrapper.and(w -> w
.like(HrtEvent::getTitle, bo.getKeyword())
.or()
.like(HrtEvent::getSummary, bo.getKeyword())
.or()
.like(HrtEvent::getContent, bo.getKeyword())
);
}
// 活动开始时间范围查询
wrapper.ge(Objects.nonNull(bo.getStartTimeBegin()), HrtEvent::getStartTime, bo.getStartTimeBegin());
wrapper.le(Objects.nonNull(bo.getStartTimeEnd()), HrtEvent::getStartTime, bo.getStartTimeEnd());
// 排序处理
if ("asc".equalsIgnoreCase(bo.getSortOrder())) {
switch (bo.getSortField()) {
case "view_count" -> wrapper.orderByAsc(HrtEvent::getViewCount);
case "start_time" -> wrapper.orderByAsc(HrtEvent::getStartTime);
case "current_participants" -> wrapper.orderByAsc(HrtEvent::getCurrentParticipants);
default -> wrapper.orderByAsc(HrtEvent::getCreateTime);
}
} else {
switch (bo.getSortField()) {
case "view_count" -> wrapper.orderByDesc(HrtEvent::getViewCount);
case "start_time" -> wrapper.orderByDesc(HrtEvent::getStartTime);
case "current_participants" -> wrapper.orderByDesc(HrtEvent::getCurrentParticipants);
default -> wrapper.orderByDesc(HrtEvent::getCreateTime);
}
}
IPage<HrtEvent> eventPage = eventMapper.selectPage(page, wrapper);
return eventPage.convert(event -> BeanUtil.copyProperties(event, HrtEventAdminVo.class));
}
/**
* @description [查看活动详情后台管理]
* @author Leocoder
*/
@Override
public HrtEventAdminDetailVo getDetail(Long id) {
HrtEvent event = eventMapper.selectById(id);
if (event == null) {
throw new BusinessException(404, "活动不存在");
}
return BeanUtil.copyProperties(event, HrtEventAdminDetailVo.class);
}
/**
* @description [新增活动]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Long addEvent(HrtEventAdminBo bo) {
// 验证时间合理性
validateEventTimes(bo);
HrtEvent event = BeanUtil.copyProperties(bo, HrtEvent.class);
// 初始化当前参与人数为0
event.setCurrentParticipants(0);
// 初始化浏览量为0
event.setViewCount(0);
// 设置创建人
event.setCreateBy(StpUtil.getLoginIdAsString());
int result = eventMapper.insert(event);
if (result <= 0) {
throw new BusinessException(500, "新增活动失败");
}
return event.getId();
}
/**
* @description [编辑活动]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean editEvent(HrtEventAdminBo bo) {
if (bo.getId() == null) {
throw new BusinessException(400, "活动ID不能为空");
}
// 检查活动是否存在
HrtEvent existEvent = eventMapper.selectById(bo.getId());
if (existEvent == null) {
throw new BusinessException(404, "活动不存在");
}
// 验证时间合理性
validateEventTimes(bo);
HrtEvent event = BeanUtil.copyProperties(bo, HrtEvent.class);
// 设置更新人
event.setUpdateBy(StpUtil.getLoginIdAsString());
int result = eventMapper.updateById(event);
return result > 0;
}
/**
* @description [删除活动]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean deleteEvent(Long id) {
// 检查活动是否存在
HrtEvent event = eventMapper.selectById(id);
if (event == null) {
throw new BusinessException(404, "活动不存在");
}
// 检查是否有用户报名如果已有报名不允许删除
if (event.getCurrentParticipants() != null && event.getCurrentParticipants() > 0) {
throw new BusinessException(400, "该活动已有用户报名,无法删除");
}
int result = eventMapper.deleteById(id);
return result > 0;
}
/**
* @description [批量删除活动]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean batchDelete(List<Long> ids) {
if (ids == null || ids.isEmpty()) {
throw new BusinessException(400, "请选择要删除的活动");
}
// 检查是否有活动已有报名
LambdaQueryWrapper<HrtEvent> wrapper = new LambdaQueryWrapper<>();
wrapper.in(HrtEvent::getId, ids);
wrapper.gt(HrtEvent::getCurrentParticipants, 0);
Long count = eventMapper.selectCount(wrapper);
if (count > 0) {
throw new BusinessException(400, "选中的活动中有已报名的活动,无法删除");
}
int result = eventMapper.deleteBatchIds(ids);
return result > 0;
}
/**
* @description [修改发布状态]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean changePublishStatus(Long id, Integer publishStatus) {
// 检查活动是否存在
HrtEvent event = eventMapper.selectById(id);
if (event == null) {
throw new BusinessException(404, "活动不存在");
}
if (publishStatus == null || (publishStatus != 0 && publishStatus != 1)) {
throw new BusinessException(400, "发布状态参数错误");
}
HrtEvent updateEvent = new HrtEvent();
updateEvent.setId(id);
updateEvent.setPublishStatus(publishStatus);
updateEvent.setUpdateBy(StpUtil.getLoginIdAsString());
int result = eventMapper.updateById(updateEvent);
return result > 0;
}
/**
* @description [修改活动状态]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean changeEventStatus(Long id, String status) {
// 检查活动是否存在
HrtEvent event = eventMapper.selectById(id);
if (event == null) {
throw new BusinessException(404, "活动不存在");
}
// 验证状态值
if (StrUtil.isEmpty(status)) {
throw new BusinessException(400, "活动状态不能为空");
}
if (!isValidEventStatus(status)) {
throw new BusinessException(400, "活动状态参数错误只能是upcoming、ongoing、finished、cancelled");
}
HrtEvent updateEvent = new HrtEvent();
updateEvent.setId(id);
updateEvent.setStatus(status);
updateEvent.setUpdateBy(StpUtil.getLoginIdAsString());
int result = eventMapper.updateById(updateEvent);
return result > 0;
}
/**
* @description [验证活动时间的合理性]
* @author Leocoder
*/
private void validateEventTimes(HrtEventAdminBo bo) {
LocalDateTime now = LocalDateTime.now();
// 验证活动时间
if (bo.getStartTime() != null && bo.getEndTime() != null) {
if (bo.getEndTime().isBefore(bo.getStartTime())) {
throw new BusinessException(400, "活动结束时间不能早于开始时间");
}
}
// 验证报名时间
if (bo.getRegistrationStart() != null && bo.getRegistrationEnd() != null) {
if (bo.getRegistrationEnd().isBefore(bo.getRegistrationStart())) {
throw new BusinessException(400, "报名结束时间不能早于报名开始时间");
}
}
// 验证报名时间与活动时间的关系
if (bo.getRegistrationEnd() != null && bo.getStartTime() != null) {
if (bo.getRegistrationEnd().isAfter(bo.getStartTime())) {
throw new BusinessException(400, "报名结束时间不能晚于活动开始时间");
}
}
}
/**
* @description [验证活动状态是否合法]
* @author Leocoder
*/
private boolean isValidEventStatus(String status) {
return "upcoming".equals(status)
|| "ongoing".equals(status)
|| "finished".equals(status)
|| "cancelled".equals(status);
}
}

View File

@ -0,0 +1,65 @@
package org.leocoder.heritage.admin.service.heritage;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.leocoder.heritage.domain.model.bo.admin.HrtHeritageAdminBo;
import org.leocoder.heritage.domain.model.bo.admin.HrtHeritageAdminQueryBo;
import org.leocoder.heritage.domain.model.vo.admin.HrtHeritageAdminDetailVo;
import org.leocoder.heritage.domain.model.vo.admin.HrtHeritageAdminVo;
import java.util.List;
/**
* @author Leocoder
* @description [非遗项目管理服务接口]
*/
public interface HrtHeritageAdminService {
/**
* @description [分页查询非遗项目列表后台管理]
* @author Leocoder
*/
IPage<HrtHeritageAdminVo> listPage(HrtHeritageAdminQueryBo bo);
/**
* @description [查看非遗项目详情后台管理]
* @author Leocoder
*/
HrtHeritageAdminDetailVo getDetail(Long id);
/**
* @description [新增非遗项目]
* @author Leocoder
*/
Long addHeritage(HrtHeritageAdminBo bo);
/**
* @description [编辑非遗项目]
* @author Leocoder
*/
Boolean editHeritage(HrtHeritageAdminBo bo);
/**
* @description [删除非遗项目]
* @author Leocoder
*/
Boolean deleteHeritage(Long id);
/**
* @description [批量删除非遗项目]
* @author Leocoder
*/
Boolean batchDelete(List<Long> ids);
/**
* @description [修改发布状态]
* @author Leocoder
*/
Boolean changePublishStatus(Long id, Integer publishStatus);
/**
* @description [设置精选状态]
* @author Leocoder
*/
Boolean setFeatured(Long id, Integer isFeatured);
}

View File

@ -0,0 +1,327 @@
package org.leocoder.heritage.admin.service.heritage;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.leocoder.heritage.common.exception.BusinessException;
import org.leocoder.heritage.domain.model.bo.admin.HrtHeritageAdminBo;
import org.leocoder.heritage.domain.model.bo.admin.HrtHeritageAdminQueryBo;
import org.leocoder.heritage.domain.model.vo.admin.HrtHeritageAdminDetailVo;
import org.leocoder.heritage.domain.model.vo.admin.HrtHeritageAdminVo;
import org.leocoder.heritage.domain.pojo.portal.HrtHeritage;
import org.leocoder.heritage.mybatisplus.mapper.portal.HrtHeritageMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* @author Leocoder
* @description [非遗项目管理服务实现类]
*/
@Service
@RequiredArgsConstructor
public class HrtHeritageAdminServiceImpl implements HrtHeritageAdminService {
private final HrtHeritageMapper hrtHeritageMapper;
/**
* @description [分页查询非遗项目列表后台管理]
* @author Leocoder
*/
@Override
public IPage<HrtHeritageAdminVo> listPage(HrtHeritageAdminQueryBo bo) {
Page<HrtHeritage> page = new Page<>(bo.getPageNum(), bo.getPageSize());
LambdaQueryWrapper<HrtHeritage> wrapper = buildQueryWrapper(bo);
// 排序
applySorting(wrapper, bo.getSortField(), bo.getSortOrder());
IPage<HrtHeritage> heritagePageResult = hrtHeritageMapper.selectPage(page, wrapper);
// 转换为VO
return heritagePageResult.convert(heritage -> BeanUtil.copyProperties(heritage, HrtHeritageAdminVo.class));
}
/**
* @description [查看非遗项目详情后台管理]
* @author Leocoder
*/
@Override
public HrtHeritageAdminDetailVo getDetail(Long id) {
HrtHeritage heritage = hrtHeritageMapper.selectById(id);
if (heritage == null) {
throw new BusinessException(404, "非遗项目不存在");
}
// 转换为详情VO
return BeanUtil.copyProperties(heritage, HrtHeritageAdminDetailVo.class);
}
/**
* @description [新增非遗项目]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Long addHeritage(HrtHeritageAdminBo bo) {
// 转换为实体
HrtHeritage heritage = BeanUtil.copyProperties(bo, HrtHeritage.class);
// 设置创建人
heritage.setCreateBy(StpUtil.getLoginIdAsString());
// 初始化统计数据
heritage.setViewCount(0);
heritage.setLikeCount(0);
heritage.setFavoriteCount(0);
heritage.setCommentCount(0);
// 设置默认值
if (heritage.getIsFeatured() == null) {
heritage.setIsFeatured(0);
}
if (heritage.getPublishStatus() == null) {
heritage.setPublishStatus(0);
}
if (heritage.getSortOrder() == null) {
heritage.setSortOrder(0);
}
// 插入数据库
int result = hrtHeritageMapper.insert(heritage);
if (result <= 0) {
throw new BusinessException(500, "新增非遗项目失败");
}
return heritage.getId();
}
/**
* @description [编辑非遗项目]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean editHeritage(HrtHeritageAdminBo bo) {
// 验证ID
if (bo.getId() == null) {
throw new BusinessException(400, "非遗项目ID不能为空");
}
// 验证是否存在
HrtHeritage existHeritage = hrtHeritageMapper.selectById(bo.getId());
if (existHeritage == null) {
throw new BusinessException(404, "非遗项目不存在");
}
// 转换为实体
HrtHeritage heritage = BeanUtil.copyProperties(bo, HrtHeritage.class);
// 设置更新人
heritage.setUpdateBy(StpUtil.getLoginIdAsString());
// 更新数据库
int result = hrtHeritageMapper.updateById(heritage);
if (result <= 0) {
throw new BusinessException(500, "编辑非遗项目失败");
}
return true;
}
/**
* @description [删除非遗项目]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean deleteHeritage(Long id) {
// 验证是否存在
HrtHeritage heritage = hrtHeritageMapper.selectById(id);
if (heritage == null) {
throw new BusinessException(404, "非遗项目不存在");
}
// 逻辑删除
int result = hrtHeritageMapper.deleteById(id);
if (result <= 0) {
throw new BusinessException(500, "删除非遗项目失败");
}
return true;
}
/**
* @description [批量删除非遗项目]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean batchDelete(List<Long> ids) {
if (ids == null || ids.isEmpty()) {
throw new BusinessException(400, "删除的ID列表不能为空");
}
// 批量逻辑删除
int result = hrtHeritageMapper.deleteBatchIds(ids);
if (result <= 0) {
throw new BusinessException(500, "批量删除非遗项目失败");
}
return true;
}
/**
* @description [修改发布状态]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean changePublishStatus(Long id, Integer publishStatus) {
// 验证参数
if (publishStatus == null || (publishStatus != 0 && publishStatus != 1)) {
throw new BusinessException(400, "发布状态参数错误必须为0或1");
}
// 验证是否存在
HrtHeritage heritage = hrtHeritageMapper.selectById(id);
if (heritage == null) {
throw new BusinessException(404, "非遗项目不存在");
}
// 更新发布状态
HrtHeritage updateHeritage = new HrtHeritage();
updateHeritage.setId(id);
updateHeritage.setPublishStatus(publishStatus);
updateHeritage.setUpdateBy(StpUtil.getLoginIdAsString());
int result = hrtHeritageMapper.updateById(updateHeritage);
if (result <= 0) {
throw new BusinessException(500, "修改发布状态失败");
}
return true;
}
/**
* @description [设置精选状态]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean setFeatured(Long id, Integer isFeatured) {
// 验证参数
if (isFeatured == null || (isFeatured != 0 && isFeatured != 1)) {
throw new BusinessException(400, "精选状态参数错误必须为0或1");
}
// 验证是否存在
HrtHeritage heritage = hrtHeritageMapper.selectById(id);
if (heritage == null) {
throw new BusinessException(404, "非遗项目不存在");
}
// 更新精选状态
HrtHeritage updateHeritage = new HrtHeritage();
updateHeritage.setId(id);
updateHeritage.setIsFeatured(isFeatured);
updateHeritage.setUpdateBy(StpUtil.getLoginIdAsString());
int result = hrtHeritageMapper.updateById(updateHeritage);
if (result <= 0) {
throw new BusinessException(500, "设置精选状态失败");
}
return true;
}
/**
* @description [构建查询条件]
* @author Leocoder
*/
private LambdaQueryWrapper<HrtHeritage> buildQueryWrapper(HrtHeritageAdminQueryBo bo) {
LambdaQueryWrapper<HrtHeritage> wrapper = new LambdaQueryWrapper<>();
// 关键词搜索搜索名称英文名称描述
if (StrUtil.isNotBlank(bo.getKeyword())) {
wrapper.and(w -> w
.like(HrtHeritage::getName, bo.getKeyword())
.or().like(HrtHeritage::getNameEn, bo.getKeyword())
.or().like(HrtHeritage::getDescription, bo.getKeyword())
);
}
// 名称模糊查询
wrapper.like(StrUtil.isNotBlank(bo.getName()), HrtHeritage::getName, bo.getName());
// 英文名称模糊查询
wrapper.like(StrUtil.isNotBlank(bo.getNameEn()), HrtHeritage::getNameEn, bo.getNameEn());
// 分类
wrapper.eq(StrUtil.isNotBlank(bo.getCategory()), HrtHeritage::getCategory, bo.getCategory());
// 级别
wrapper.eq(StrUtil.isNotBlank(bo.getLevel()), HrtHeritage::getLevel, bo.getLevel());
// 省份
wrapper.eq(StrUtil.isNotBlank(bo.getProvince()), HrtHeritage::getProvince, bo.getProvince());
// 城市
wrapper.eq(StrUtil.isNotBlank(bo.getCity()), HrtHeritage::getCity, bo.getCity());
// 状态
wrapper.eq(StrUtil.isNotBlank(bo.getStatus()), HrtHeritage::getStatus, bo.getStatus());
// 标签模糊匹配
wrapper.like(StrUtil.isNotBlank(bo.getTag()), HrtHeritage::getTags, bo.getTag());
// 发布状态
wrapper.eq(bo.getPublishStatus() != null, HrtHeritage::getPublishStatus, bo.getPublishStatus());
// 是否精选
wrapper.eq(bo.getIsFeatured() != null, HrtHeritage::getIsFeatured, bo.getIsFeatured());
return wrapper;
}
/**
* @description [应用排序规则]
* @author Leocoder
*/
private void applySorting(LambdaQueryWrapper<HrtHeritage> wrapper, String sortField, String sortOrder) {
boolean isAsc = "asc".equalsIgnoreCase(sortOrder);
switch (sortField) {
case "view_count":
wrapper.orderBy(true, isAsc, HrtHeritage::getViewCount);
break;
case "like_count":
wrapper.orderBy(true, isAsc, HrtHeritage::getLikeCount);
break;
case "favorite_count":
wrapper.orderBy(true, isAsc, HrtHeritage::getFavoriteCount);
break;
case "sort_order":
wrapper.orderBy(true, isAsc, HrtHeritage::getSortOrder);
break;
case "create_time":
default:
wrapper.orderBy(true, isAsc, HrtHeritage::getCreateTime);
break;
}
}
}

View File

@ -0,0 +1,65 @@
package org.leocoder.heritage.admin.service.inheritor;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.leocoder.heritage.domain.model.bo.admin.HrtInheritorAdminBo;
import org.leocoder.heritage.domain.model.bo.admin.HrtInheritorAdminQueryBo;
import org.leocoder.heritage.domain.model.vo.admin.HrtInheritorAdminDetailVo;
import org.leocoder.heritage.domain.model.vo.admin.HrtInheritorAdminVo;
import java.util.List;
/**
* @author Leocoder
* @description [传承人管理服务接口]
*/
public interface HrtInheritorAdminService {
/**
* @description [分页查询传承人列表后台管理]
* @author Leocoder
*/
IPage<HrtInheritorAdminVo> listPage(HrtInheritorAdminQueryBo bo);
/**
* @description [查看传承人详情后台管理]
* @author Leocoder
*/
HrtInheritorAdminDetailVo getDetail(Long id);
/**
* @description [新增传承人]
* @author Leocoder
*/
Long addInheritor(HrtInheritorAdminBo bo);
/**
* @description [编辑传承人]
* @author Leocoder
*/
Boolean editInheritor(HrtInheritorAdminBo bo);
/**
* @description [删除传承人]
* @author Leocoder
*/
Boolean deleteInheritor(Long id);
/**
* @description [批量删除传承人]
* @author Leocoder
*/
Boolean batchDelete(List<Long> ids);
/**
* @description [修改发布状态]
* @author Leocoder
*/
Boolean changePublishStatus(Long id, Integer publishStatus);
/**
* @description [设置精选状态]
* @author Leocoder
*/
Boolean setFeatured(Long id, Integer isFeatured);
}

View File

@ -0,0 +1,323 @@
package org.leocoder.heritage.admin.service.inheritor;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.leocoder.heritage.common.exception.BusinessException;
import org.leocoder.heritage.domain.model.bo.admin.HrtInheritorAdminBo;
import org.leocoder.heritage.domain.model.bo.admin.HrtInheritorAdminQueryBo;
import org.leocoder.heritage.domain.model.vo.admin.HrtInheritorAdminDetailVo;
import org.leocoder.heritage.domain.model.vo.admin.HrtInheritorAdminVo;
import org.leocoder.heritage.domain.pojo.portal.HrtInheritor;
import org.leocoder.heritage.mybatisplus.mapper.portal.HrtInheritorMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* @author Leocoder
* @description [传承人管理服务实现类]
*/
@Service
@RequiredArgsConstructor
public class HrtInheritorAdminServiceImpl implements HrtInheritorAdminService {
private final HrtInheritorMapper hrtInheritorMapper;
/**
* @description [分页查询传承人列表后台管理]
* @author Leocoder
*/
@Override
public IPage<HrtInheritorAdminVo> listPage(HrtInheritorAdminQueryBo bo) {
Page<HrtInheritor> page = new Page<>(bo.getPageNum(), bo.getPageSize());
LambdaQueryWrapper<HrtInheritor> wrapper = buildQueryWrapper(bo);
// 排序
applySorting(wrapper, bo.getSortField(), bo.getSortOrder());
IPage<HrtInheritor> inheritorPageResult = hrtInheritorMapper.selectPage(page, wrapper);
// 转换为VO
return inheritorPageResult.convert(inheritor -> BeanUtil.copyProperties(inheritor, HrtInheritorAdminVo.class));
}
/**
* @description [查看传承人详情后台管理]
* @author Leocoder
*/
@Override
public HrtInheritorAdminDetailVo getDetail(Long id) {
HrtInheritor inheritor = hrtInheritorMapper.selectById(id);
if (inheritor == null) {
throw new BusinessException(404, "传承人不存在");
}
// 转换为详情VO
return BeanUtil.copyProperties(inheritor, HrtInheritorAdminDetailVo.class);
}
/**
* @description [新增传承人]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Long addInheritor(HrtInheritorAdminBo bo) {
// 转换为实体
HrtInheritor inheritor = BeanUtil.copyProperties(bo, HrtInheritor.class);
// 设置创建人
inheritor.setCreateBy(StpUtil.getLoginIdAsString());
// 初始化统计数据
inheritor.setViewCount(0);
inheritor.setLikeCount(0);
// 设置默认值
if (inheritor.getIsFeatured() == null) {
inheritor.setIsFeatured(0);
}
if (inheritor.getPublishStatus() == null) {
inheritor.setPublishStatus(0);
}
if (inheritor.getSortOrder() == null) {
inheritor.setSortOrder(0);
}
// 插入数据库
int result = hrtInheritorMapper.insert(inheritor);
if (result <= 0) {
throw new BusinessException(500, "新增传承人失败");
}
return inheritor.getId();
}
/**
* @description [编辑传承人]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean editInheritor(HrtInheritorAdminBo bo) {
// 验证ID
if (bo.getId() == null) {
throw new BusinessException(400, "传承人ID不能为空");
}
// 验证是否存在
HrtInheritor existInheritor = hrtInheritorMapper.selectById(bo.getId());
if (existInheritor == null) {
throw new BusinessException(404, "传承人不存在");
}
// 转换为实体
HrtInheritor inheritor = BeanUtil.copyProperties(bo, HrtInheritor.class);
// 设置更新人
inheritor.setUpdateBy(StpUtil.getLoginIdAsString());
// 更新数据库
int result = hrtInheritorMapper.updateById(inheritor);
if (result <= 0) {
throw new BusinessException(500, "编辑传承人失败");
}
return true;
}
/**
* @description [删除传承人]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean deleteInheritor(Long id) {
// 验证是否存在
HrtInheritor inheritor = hrtInheritorMapper.selectById(id);
if (inheritor == null) {
throw new BusinessException(404, "传承人不存在");
}
// 逻辑删除
int result = hrtInheritorMapper.deleteById(id);
if (result <= 0) {
throw new BusinessException(500, "删除传承人失败");
}
return true;
}
/**
* @description [批量删除传承人]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean batchDelete(List<Long> ids) {
if (ids == null || ids.isEmpty()) {
throw new BusinessException(400, "删除的ID列表不能为空");
}
// 批量逻辑删除
int result = hrtInheritorMapper.deleteBatchIds(ids);
if (result <= 0) {
throw new BusinessException(500, "批量删除传承人失败");
}
return true;
}
/**
* @description [修改发布状态]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean changePublishStatus(Long id, Integer publishStatus) {
// 验证参数
if (publishStatus == null || (publishStatus != 0 && publishStatus != 1)) {
throw new BusinessException(400, "发布状态参数错误必须为0或1");
}
// 验证是否存在
HrtInheritor inheritor = hrtInheritorMapper.selectById(id);
if (inheritor == null) {
throw new BusinessException(404, "传承人不存在");
}
// 更新发布状态
HrtInheritor updateInheritor = new HrtInheritor();
updateInheritor.setId(id);
updateInheritor.setPublishStatus(publishStatus);
updateInheritor.setUpdateBy(StpUtil.getLoginIdAsString());
int result = hrtInheritorMapper.updateById(updateInheritor);
if (result <= 0) {
throw new BusinessException(500, "修改发布状态失败");
}
return true;
}
/**
* @description [设置精选状态]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean setFeatured(Long id, Integer isFeatured) {
// 验证参数
if (isFeatured == null || (isFeatured != 0 && isFeatured != 1)) {
throw new BusinessException(400, "精选状态参数错误必须为0或1");
}
// 验证是否存在
HrtInheritor inheritor = hrtInheritorMapper.selectById(id);
if (inheritor == null) {
throw new BusinessException(404, "传承人不存在");
}
// 更新精选状态
HrtInheritor updateInheritor = new HrtInheritor();
updateInheritor.setId(id);
updateInheritor.setIsFeatured(isFeatured);
updateInheritor.setUpdateBy(StpUtil.getLoginIdAsString());
int result = hrtInheritorMapper.updateById(updateInheritor);
if (result <= 0) {
throw new BusinessException(500, "设置精选状态失败");
}
return true;
}
/**
* @description [构建查询条件]
* @author Leocoder
*/
private LambdaQueryWrapper<HrtInheritor> buildQueryWrapper(HrtInheritorAdminQueryBo bo) {
LambdaQueryWrapper<HrtInheritor> wrapper = new LambdaQueryWrapper<>();
// 关键词搜索搜索姓名简介故事等字段
if (StrUtil.isNotBlank(bo.getKeyword())) {
wrapper.and(w -> w
.like(HrtInheritor::getName, bo.getKeyword())
.or().like(HrtInheritor::getNameEn, bo.getKeyword())
.or().like(HrtInheritor::getIntroduction, bo.getKeyword())
.or().like(HrtInheritor::getStory, bo.getKeyword())
);
}
// 姓名模糊查询
wrapper.like(StrUtil.isNotBlank(bo.getName()), HrtInheritor::getName, bo.getName());
// 英文名模糊查询
wrapper.like(StrUtil.isNotBlank(bo.getNameEn()), HrtInheritor::getNameEn, bo.getNameEn());
// 性别
wrapper.eq(bo.getGender() != null, HrtInheritor::getGender, bo.getGender());
// 关联非遗项目ID
wrapper.eq(bo.getHeritageId() != null, HrtInheritor::getHeritageId, bo.getHeritageId());
// 传承项目名称模糊查询
wrapper.like(StrUtil.isNotBlank(bo.getHeritageName()), HrtInheritor::getHeritageName, bo.getHeritageName());
// 传承人级别
wrapper.eq(StrUtil.isNotBlank(bo.getLevel()), HrtInheritor::getLevel, bo.getLevel());
// 省份
wrapper.eq(StrUtil.isNotBlank(bo.getProvince()), HrtInheritor::getProvince, bo.getProvince());
// 城市
wrapper.eq(StrUtil.isNotBlank(bo.getCity()), HrtInheritor::getCity, bo.getCity());
// 发布状态
wrapper.eq(bo.getPublishStatus() != null, HrtInheritor::getPublishStatus, bo.getPublishStatus());
// 是否精选
wrapper.eq(bo.getIsFeatured() != null, HrtInheritor::getIsFeatured, bo.getIsFeatured());
return wrapper;
}
/**
* @description [应用排序规则]
* @author Leocoder
*/
private void applySorting(LambdaQueryWrapper<HrtInheritor> wrapper, String sortField, String sortOrder) {
boolean isAsc = "asc".equalsIgnoreCase(sortOrder);
switch (sortField) {
case "view_count":
wrapper.orderBy(true, isAsc, HrtInheritor::getViewCount);
break;
case "like_count":
wrapper.orderBy(true, isAsc, HrtInheritor::getLikeCount);
break;
case "sort_order":
wrapper.orderBy(true, isAsc, HrtInheritor::getSortOrder);
break;
case "create_time":
default:
wrapper.orderBy(true, isAsc, HrtInheritor::getCreateTime);
break;
}
}
}

View File

@ -0,0 +1,65 @@
package org.leocoder.heritage.admin.service.news;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.leocoder.heritage.domain.model.bo.admin.HrtNewsAdminBo;
import org.leocoder.heritage.domain.model.bo.admin.HrtNewsAdminQueryBo;
import org.leocoder.heritage.domain.model.vo.admin.HrtNewsAdminDetailVo;
import org.leocoder.heritage.domain.model.vo.admin.HrtNewsAdminVo;
import java.util.List;
/**
* @author Leocoder
* @description [新闻资讯管理服务接口]
*/
public interface HrtNewsAdminService {
/**
* @description [分页查询新闻资讯列表后台管理]
* @author Leocoder
*/
IPage<HrtNewsAdminVo> listPage(HrtNewsAdminQueryBo bo);
/**
* @description [查看新闻资讯详情后台管理]
* @author Leocoder
*/
HrtNewsAdminDetailVo getDetail(Long id);
/**
* @description [新增新闻资讯]
* @author Leocoder
*/
Long addNews(HrtNewsAdminBo bo);
/**
* @description [编辑新闻资讯]
* @author Leocoder
*/
Boolean editNews(HrtNewsAdminBo bo);
/**
* @description [删除新闻资讯]
* @author Leocoder
*/
Boolean deleteNews(Long id);
/**
* @description [批量删除新闻资讯]
* @author Leocoder
*/
Boolean batchDelete(List<Long> ids);
/**
* @description [修改发布状态]
* @author Leocoder
*/
Boolean changePublishStatus(Long id, Integer publishStatus);
/**
* @description [设置置顶状态]
* @author Leocoder
*/
Boolean setTop(Long id, Integer isTop);
}

View File

@ -0,0 +1,334 @@
package org.leocoder.heritage.admin.service.news;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.leocoder.heritage.common.exception.BusinessException;
import org.leocoder.heritage.domain.model.bo.admin.HrtNewsAdminBo;
import org.leocoder.heritage.domain.model.bo.admin.HrtNewsAdminQueryBo;
import org.leocoder.heritage.domain.model.vo.admin.HrtNewsAdminDetailVo;
import org.leocoder.heritage.domain.model.vo.admin.HrtNewsAdminVo;
import org.leocoder.heritage.domain.pojo.portal.HrtNews;
import org.leocoder.heritage.mybatisplus.mapper.portal.HrtNewsMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
/**
* @author Leocoder
* @description [新闻资讯管理服务实现类]
*/
@Service
@RequiredArgsConstructor
public class HrtNewsAdminServiceImpl implements HrtNewsAdminService {
private final HrtNewsMapper hrtNewsMapper;
/**
* @description [分页查询新闻资讯列表后台管理]
* @author Leocoder
*/
@Override
public IPage<HrtNewsAdminVo> listPage(HrtNewsAdminQueryBo bo) {
Page<HrtNews> page = new Page<>(bo.getPageNum(), bo.getPageSize());
LambdaQueryWrapper<HrtNews> wrapper = buildQueryWrapper(bo);
// 排序
applySorting(wrapper, bo.getSortField(), bo.getSortOrder());
IPage<HrtNews> newsPageResult = hrtNewsMapper.selectPage(page, wrapper);
// 转换为VO
return newsPageResult.convert(news -> BeanUtil.copyProperties(news, HrtNewsAdminVo.class));
}
/**
* @description [查看新闻资讯详情后台管理]
* @author Leocoder
*/
@Override
public HrtNewsAdminDetailVo getDetail(Long id) {
HrtNews news = hrtNewsMapper.selectById(id);
if (news == null) {
throw new BusinessException(404, "新闻资讯不存在");
}
// 转换为详情VO
return BeanUtil.copyProperties(news, HrtNewsAdminDetailVo.class);
}
/**
* @description [新增新闻资讯]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Long addNews(HrtNewsAdminBo bo) {
// 转换为实体
HrtNews news = BeanUtil.copyProperties(bo, HrtNews.class);
// 设置创建人
news.setCreateBy(StpUtil.getLoginIdAsString());
// 初始化统计数据
news.setViewCount(0);
news.setLikeCount(0);
// 设置默认值
if (news.getIsTop() == null) {
news.setIsTop(0);
}
if (news.getPublishStatus() == null) {
news.setPublishStatus(0);
}
// 如果发布状态为1且未设置发布时间则设置为当前时间
if (news.getPublishStatus() == 1 && news.getPublishTime() == null) {
news.setPublishTime(LocalDateTime.now());
}
// 插入数据库
int result = hrtNewsMapper.insert(news);
if (result <= 0) {
throw new BusinessException(500, "新增新闻资讯失败");
}
return news.getId();
}
/**
* @description [编辑新闻资讯]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean editNews(HrtNewsAdminBo bo) {
// 验证ID
if (bo.getId() == null) {
throw new BusinessException(400, "新闻资讯ID不能为空");
}
// 验证是否存在
HrtNews existNews = hrtNewsMapper.selectById(bo.getId());
if (existNews == null) {
throw new BusinessException(404, "新闻资讯不存在");
}
// 转换为实体
HrtNews news = BeanUtil.copyProperties(bo, HrtNews.class);
// 设置更新人
news.setUpdateBy(StpUtil.getLoginIdAsString());
// 如果发布状态从草稿变为已发布且未设置发布时间则设置为当前时间
if (news.getPublishStatus() != null && news.getPublishStatus() == 1
&& existNews.getPublishStatus() == 0 && news.getPublishTime() == null) {
news.setPublishTime(LocalDateTime.now());
}
// 更新数据库
int result = hrtNewsMapper.updateById(news);
if (result <= 0) {
throw new BusinessException(500, "编辑新闻资讯失败");
}
return true;
}
/**
* @description [删除新闻资讯]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean deleteNews(Long id) {
// 验证是否存在
HrtNews news = hrtNewsMapper.selectById(id);
if (news == null) {
throw new BusinessException(404, "新闻资讯不存在");
}
// 逻辑删除
int result = hrtNewsMapper.deleteById(id);
if (result <= 0) {
throw new BusinessException(500, "删除新闻资讯失败");
}
return true;
}
/**
* @description [批量删除新闻资讯]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean batchDelete(List<Long> ids) {
if (ids == null || ids.isEmpty()) {
throw new BusinessException(400, "删除的ID列表不能为空");
}
// 批量逻辑删除
int result = hrtNewsMapper.deleteBatchIds(ids);
if (result <= 0) {
throw new BusinessException(500, "批量删除新闻资讯失败");
}
return true;
}
/**
* @description [修改发布状态]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean changePublishStatus(Long id, Integer publishStatus) {
// 验证参数
if (publishStatus == null || (publishStatus != 0 && publishStatus != 1)) {
throw new BusinessException(400, "发布状态参数错误必须为0或1");
}
// 验证是否存在
HrtNews news = hrtNewsMapper.selectById(id);
if (news == null) {
throw new BusinessException(404, "新闻资讯不存在");
}
// 更新发布状态
HrtNews updateNews = new HrtNews();
updateNews.setId(id);
updateNews.setPublishStatus(publishStatus);
updateNews.setUpdateBy(StpUtil.getLoginIdAsString());
// 如果从草稿变为已发布且未设置发布时间则设置为当前时间
if (publishStatus == 1 && news.getPublishStatus() == 0 && news.getPublishTime() == null) {
updateNews.setPublishTime(LocalDateTime.now());
}
int result = hrtNewsMapper.updateById(updateNews);
if (result <= 0) {
throw new BusinessException(500, "修改发布状态失败");
}
return true;
}
/**
* @description [设置置顶状态]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean setTop(Long id, Integer isTop) {
// 验证参数
if (isTop == null || (isTop != 0 && isTop != 1)) {
throw new BusinessException(400, "置顶状态参数错误必须为0或1");
}
// 验证是否存在
HrtNews news = hrtNewsMapper.selectById(id);
if (news == null) {
throw new BusinessException(404, "新闻资讯不存在");
}
// 更新置顶状态
HrtNews updateNews = new HrtNews();
updateNews.setId(id);
updateNews.setIsTop(isTop);
updateNews.setUpdateBy(StpUtil.getLoginIdAsString());
int result = hrtNewsMapper.updateById(updateNews);
if (result <= 0) {
throw new BusinessException(500, "设置置顶状态失败");
}
return true;
}
/**
* @description [构建查询条件]
* @author Leocoder
*/
private LambdaQueryWrapper<HrtNews> buildQueryWrapper(HrtNewsAdminQueryBo bo) {
LambdaQueryWrapper<HrtNews> wrapper = new LambdaQueryWrapper<>();
// 关键词搜索搜索标题摘要内容等字段
if (StrUtil.isNotBlank(bo.getKeyword())) {
wrapper.and(w -> w
.like(HrtNews::getTitle, bo.getKeyword())
.or().like(HrtNews::getSummary, bo.getKeyword())
.or().like(HrtNews::getContent, bo.getKeyword())
);
}
// 标题模糊查询
wrapper.like(StrUtil.isNotBlank(bo.getTitle()), HrtNews::getTitle, bo.getTitle());
// 作者模糊查询
wrapper.like(StrUtil.isNotBlank(bo.getAuthor()), HrtNews::getAuthor, bo.getAuthor());
// 来源模糊查询
wrapper.like(StrUtil.isNotBlank(bo.getSource()), HrtNews::getSource, bo.getSource());
// 分类
wrapper.eq(StrUtil.isNotBlank(bo.getCategory()), HrtNews::getCategory, bo.getCategory());
// 标签模糊匹配
wrapper.like(StrUtil.isNotBlank(bo.getTag()), HrtNews::getTags, bo.getTag());
// 是否置顶
wrapper.eq(bo.getIsTop() != null, HrtNews::getIsTop, bo.getIsTop());
// 发布状态
wrapper.eq(bo.getPublishStatus() != null, HrtNews::getPublishStatus, bo.getPublishStatus());
// 发布时间范围查询
wrapper.ge(bo.getPublishTimeStart() != null, HrtNews::getPublishTime, bo.getPublishTimeStart());
wrapper.le(bo.getPublishTimeEnd() != null, HrtNews::getPublishTime, bo.getPublishTimeEnd());
return wrapper;
}
/**
* @description [应用排序规则]
* @author Leocoder
*/
private void applySorting(LambdaQueryWrapper<HrtNews> wrapper, String sortField, String sortOrder) {
boolean isAsc = "asc".equalsIgnoreCase(sortOrder);
switch (sortField) {
case "view_count":
wrapper.orderBy(true, isAsc, HrtNews::getViewCount);
break;
case "like_count":
wrapper.orderBy(true, isAsc, HrtNews::getLikeCount);
break;
case "publish_time":
wrapper.orderBy(true, isAsc, HrtNews::getPublishTime);
break;
case "create_time":
default:
wrapper.orderBy(true, isAsc, HrtNews::getCreateTime);
break;
}
// 置顶的新闻始终排在前面
wrapper.orderByDesc(HrtNews::getIsTop);
}
}

View File

@ -0,0 +1,50 @@
package org.leocoder.heritage.admin.service.statistics;
import org.leocoder.heritage.domain.model.vo.admin.HrtRankingVo;
import org.leocoder.heritage.domain.model.vo.admin.HrtStatisticsVo;
import org.leocoder.heritage.domain.model.vo.admin.HrtTrendVo;
import java.util.List;
/**
* @author Leocoder
* @description [统计分析服务接口]
*/
public interface HrtStatisticsService {
/**
* @description [获取核心统计数据]
* @author Leocoder
*/
HrtStatisticsVo getStatistics();
/**
* @description [获取用户增长趋势]
* @author Leocoder
* @param days 天数(7或30)
*/
List<HrtTrendVo> getUserTrend(Integer days);
/**
* @description [获取内容发布趋势]
* @author Leocoder
* @param days 天数(7或30)
*/
List<HrtTrendVo> getContentTrend(Integer days);
/**
* @description [获取热门非遗项目排行榜]
* @author Leocoder
* @param type 排序类型view-浏览量favorite-收藏数
* @param limit 返回数量默认10
*/
List<HrtRankingVo> getHeritageRanking(String type, Integer limit);
/**
* @description [获取活跃用户排行榜]
* @author Leocoder
* @param limit 返回数量默认10
*/
List<HrtRankingVo> getActiveUserRanking(Integer limit);
}

View File

@ -0,0 +1,393 @@
package org.leocoder.heritage.admin.service.statistics;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import org.leocoder.heritage.domain.model.vo.admin.HrtRankingVo;
import org.leocoder.heritage.domain.model.vo.admin.HrtStatisticsVo;
import org.leocoder.heritage.domain.model.vo.admin.HrtTrendVo;
import org.leocoder.heritage.domain.pojo.portal.*;
import org.leocoder.heritage.mybatisplus.mapper.portal.*;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author Leocoder
* @description [统计分析服务实现类]
*/
@Service
@RequiredArgsConstructor
public class HrtStatisticsServiceImpl implements HrtStatisticsService {
private final HrtHeritageMapper heritageMapper;
private final HrtInheritorMapper inheritorMapper;
private final HrtUserMapper userMapper;
private final HrtEventMapper eventMapper;
private final HrtNewsMapper newsMapper;
private final HrtCommentMapper commentMapper;
private final HrtLikeMapper likeMapper;
private final HrtFavoriteMapper favoriteMapper;
private final HrtViewHistoryMapper viewHistoryMapper;
private final HrtEventRegistrationMapper registrationMapper;
/**
* @description [获取核心统计数据]
* @author Leocoder
*/
@Override
public HrtStatisticsVo getStatistics() {
HrtStatisticsVo vo = new HrtStatisticsVo();
// 获取今日开始时间
LocalDateTime todayStart = LocalDate.now().atStartOfDay();
// ===== 核心数据统计 =====
// 非遗项目统计
vo.setHeritageTotal(heritageMapper.selectCount(null));
vo.setHeritageTodayCount(countTodayRecords(heritageMapper, todayStart));
// 传承人统计
vo.setInheritorTotal(inheritorMapper.selectCount(null));
vo.setInheritorTodayCount(countTodayRecords(inheritorMapper, todayStart));
// 用户统计
vo.setUserTotal(userMapper.selectCount(null));
vo.setUserTodayCount(countTodayRecords(userMapper, todayStart));
// 活动统计
vo.setEventTotal(eventMapper.selectCount(null));
vo.setEventTodayCount(countTodayRecords(eventMapper, todayStart));
// 新闻统计
vo.setNewsTotal(newsMapper.selectCount(null));
vo.setNewsTodayCount(countTodayRecords(newsMapper, todayStart));
// ===== 用户行为统计 =====
// 评论统计
vo.setCommentTotal(commentMapper.selectCount(null));
vo.setCommentTodayCount(countTodayRecords(commentMapper, todayStart));
// 待审核评论数
LambdaQueryWrapper<HrtComment> pendingWrapper = new LambdaQueryWrapper<>();
pendingWrapper.eq(HrtComment::getStatus, 0);
vo.setCommentPendingCount(commentMapper.selectCount(pendingWrapper));
// 点赞统计
vo.setLikeTotal(likeMapper.selectCount(null));
vo.setLikeTodayCount(countTodayRecords(likeMapper, todayStart));
// 收藏统计
vo.setFavoriteTotal(favoriteMapper.selectCount(null));
vo.setFavoriteTodayCount(countTodayRecords(favoriteMapper, todayStart));
// 浏览统计
vo.setViewTotal(viewHistoryMapper.selectCount(null));
vo.setViewTodayCount(countTodayRecords(viewHistoryMapper, todayStart));
// 活动报名统计
vo.setRegistrationTotal(registrationMapper.selectCount(null));
vo.setRegistrationTodayCount(countTodayRecords(registrationMapper, todayStart));
return vo;
}
/**
* @description [获取用户增长趋势]
* @author Leocoder
*/
@Override
public List<HrtTrendVo> getUserTrend(Integer days) {
if (days == null || (days != 7 && days != 30)) {
days = 7;
}
List<HrtTrendVo> trendList = new ArrayList<>();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
for (int i = days - 1; i >= 0; i--) {
LocalDate date = LocalDate.now().minusDays(i);
LocalDateTime startTime = date.atStartOfDay();
LocalDateTime endTime = date.atTime(LocalTime.MAX);
LambdaQueryWrapper<HrtUser> wrapper = new LambdaQueryWrapper<>();
wrapper.ge(HrtUser::getCreateTime, startTime);
wrapper.le(HrtUser::getCreateTime, endTime);
Long count = userMapper.selectCount(wrapper);
HrtTrendVo trendVo = new HrtTrendVo();
trendVo.setDate(date.format(formatter));
trendVo.setValue(count);
trendList.add(trendVo);
}
return trendList;
}
/**
* @description [获取内容发布趋势]
* @author Leocoder
*/
@Override
public List<HrtTrendVo> getContentTrend(Integer days) {
if (days == null || (days != 7 && days != 30)) {
days = 7;
}
List<HrtTrendVo> trendList = new ArrayList<>();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
for (int i = days - 1; i >= 0; i--) {
LocalDate date = LocalDate.now().minusDays(i);
LocalDateTime startTime = date.atStartOfDay();
LocalDateTime endTime = date.atTime(LocalTime.MAX);
// 统计当天发布的内容总数(非遗项目+新闻+活动)
Long heritageCount = countByDateRange(heritageMapper, startTime, endTime);
Long newsCount = countByDateRange(newsMapper, startTime, endTime);
Long eventCount = countByDateRange(eventMapper, startTime, endTime);
Long totalCount = heritageCount + newsCount + eventCount;
HrtTrendVo trendVo = new HrtTrendVo();
trendVo.setDate(date.format(formatter));
trendVo.setValue(totalCount);
trendList.add(trendVo);
}
return trendList;
}
/**
* @description [获取热门非遗项目排行榜]
* @author Leocoder
*/
@Override
public List<HrtRankingVo> getHeritageRanking(String type, Integer limit) {
if (limit == null || limit <= 0) {
limit = 10;
}
LambdaQueryWrapper<HrtHeritage> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(HrtHeritage::getPublishStatus, 1);
// 根据类型排序
if ("favorite".equals(type)) {
wrapper.orderByDesc(HrtHeritage::getFavoriteCount);
} else {
// 默认按浏览量排序
wrapper.orderByDesc(HrtHeritage::getViewCount);
}
wrapper.last("LIMIT " + limit);
List<HrtHeritage> heritageList = heritageMapper.selectList(wrapper);
return heritageList.stream().map(heritage -> {
HrtRankingVo vo = new HrtRankingVo();
vo.setId(heritage.getId());
vo.setTitle(heritage.getName());
vo.setType("heritage");
vo.setCoverImage(heritage.getCoverImage());
vo.setValue("favorite".equals(type) ? heritage.getFavoriteCount().longValue() : heritage.getViewCount().longValue());
vo.setValueType("favorite".equals(type) ? "收藏数" : "浏览量");
return vo;
}).collect(Collectors.toList());
}
/**
* @description [获取活跃用户排行榜]
* @author Leocoder
*/
@Override
public List<HrtRankingVo> getActiveUserRanking(Integer limit) {
if (limit == null || limit <= 0) {
limit = 10;
}
// 根据用户的评论数点赞数收藏数综合计算活跃度
List<HrtUser> allUsers = userMapper.selectList(null);
List<HrtRankingVo> rankingList = allUsers.stream().map(user -> {
// 统计用户的评论数
LambdaQueryWrapper<HrtComment> commentWrapper = new LambdaQueryWrapper<>();
commentWrapper.eq(HrtComment::getUserId, user.getId());
Long commentCount = commentMapper.selectCount(commentWrapper);
// 统计用户的点赞数
LambdaQueryWrapper<HrtLike> likeWrapper = new LambdaQueryWrapper<>();
likeWrapper.eq(HrtLike::getUserId, user.getId());
Long likeCount = likeMapper.selectCount(likeWrapper);
// 统计用户的收藏数
LambdaQueryWrapper<HrtFavorite> favoriteWrapper = new LambdaQueryWrapper<>();
favoriteWrapper.eq(HrtFavorite::getUserId, user.getId());
Long favoriteCount = favoriteMapper.selectCount(favoriteWrapper);
// 计算活跃度分数(评论权重3点赞权重1收藏权重2)
Long activityScore = commentCount * 3 + likeCount + favoriteCount * 2;
HrtRankingVo vo = new HrtRankingVo();
vo.setId(user.getId());
vo.setTitle(user.getNickname() != null ? user.getNickname() : user.getUsername());
vo.setType("user");
vo.setCoverImage(user.getAvatar());
vo.setValue(activityScore);
vo.setValueType("活跃度");
return vo;
})
.sorted(Comparator.comparing(HrtRankingVo::getValue).reversed())
.limit(limit)
.collect(Collectors.toList());
// 设置排名
for (int i = 0; i < rankingList.size(); i++) {
rankingList.get(i).setRank(i + 1);
}
return rankingList;
}
/**
* @description [统计今日新增非遗项目]
* @author Leocoder
*/
private Long countTodayRecords(HrtHeritageMapper mapper, LocalDateTime todayStart) {
LambdaQueryWrapper<HrtHeritage> wrapper = new LambdaQueryWrapper<>();
wrapper.ge(HrtHeritage::getCreateTime, todayStart);
return mapper.selectCount(wrapper);
}
/**
* @description [统计今日新增传承人]
* @author Leocoder
*/
private Long countTodayRecords(HrtInheritorMapper mapper, LocalDateTime todayStart) {
LambdaQueryWrapper<HrtInheritor> wrapper = new LambdaQueryWrapper<>();
wrapper.ge(HrtInheritor::getCreateTime, todayStart);
return mapper.selectCount(wrapper);
}
/**
* @description [统计今日新增用户]
* @author Leocoder
*/
private Long countTodayRecords(HrtUserMapper mapper, LocalDateTime todayStart) {
LambdaQueryWrapper<HrtUser> wrapper = new LambdaQueryWrapper<>();
wrapper.ge(HrtUser::getCreateTime, todayStart);
return mapper.selectCount(wrapper);
}
/**
* @description [统计今日新增活动]
* @author Leocoder
*/
private Long countTodayRecords(HrtEventMapper mapper, LocalDateTime todayStart) {
LambdaQueryWrapper<HrtEvent> wrapper = new LambdaQueryWrapper<>();
wrapper.ge(HrtEvent::getCreateTime, todayStart);
return mapper.selectCount(wrapper);
}
/**
* @description [统计今日新增新闻]
* @author Leocoder
*/
private Long countTodayRecords(HrtNewsMapper mapper, LocalDateTime todayStart) {
LambdaQueryWrapper<HrtNews> wrapper = new LambdaQueryWrapper<>();
wrapper.ge(HrtNews::getCreateTime, todayStart);
return mapper.selectCount(wrapper);
}
/**
* @description [统计今日新增评论]
* @author Leocoder
*/
private Long countTodayRecords(HrtCommentMapper mapper, LocalDateTime todayStart) {
LambdaQueryWrapper<HrtComment> wrapper = new LambdaQueryWrapper<>();
wrapper.ge(HrtComment::getCreateTime, todayStart);
return mapper.selectCount(wrapper);
}
/**
* @description [统计今日新增点赞]
* @author Leocoder
*/
private Long countTodayRecords(HrtLikeMapper mapper, LocalDateTime todayStart) {
LambdaQueryWrapper<HrtLike> wrapper = new LambdaQueryWrapper<>();
wrapper.ge(HrtLike::getCreateTime, todayStart);
return mapper.selectCount(wrapper);
}
/**
* @description [统计今日新增收藏]
* @author Leocoder
*/
private Long countTodayRecords(HrtFavoriteMapper mapper, LocalDateTime todayStart) {
LambdaQueryWrapper<HrtFavorite> wrapper = new LambdaQueryWrapper<>();
wrapper.ge(HrtFavorite::getCreateTime, todayStart);
return mapper.selectCount(wrapper);
}
/**
* @description [统计今日新增浏览]
* @author Leocoder
*/
private Long countTodayRecords(HrtViewHistoryMapper mapper, LocalDateTime todayStart) {
LambdaQueryWrapper<HrtViewHistory> wrapper = new LambdaQueryWrapper<>();
wrapper.ge(HrtViewHistory::getCreateTime, todayStart);
return mapper.selectCount(wrapper);
}
/**
* @description [统计今日新增报名]
* @author Leocoder
*/
private Long countTodayRecords(HrtEventRegistrationMapper mapper, LocalDateTime todayStart) {
LambdaQueryWrapper<HrtEventRegistration> wrapper = new LambdaQueryWrapper<>();
wrapper.ge(HrtEventRegistration::getCreateTime, todayStart);
return mapper.selectCount(wrapper);
}
/**
* @description [按日期范围统计非遗项目]
* @author Leocoder
*/
private Long countByDateRange(HrtHeritageMapper mapper, LocalDateTime startTime, LocalDateTime endTime) {
LambdaQueryWrapper<HrtHeritage> wrapper = new LambdaQueryWrapper<>();
wrapper.ge(HrtHeritage::getCreateTime, startTime);
wrapper.le(HrtHeritage::getCreateTime, endTime);
return mapper.selectCount(wrapper);
}
/**
* @description [按日期范围统计新闻]
* @author Leocoder
*/
private Long countByDateRange(HrtNewsMapper mapper, LocalDateTime startTime, LocalDateTime endTime) {
LambdaQueryWrapper<HrtNews> wrapper = new LambdaQueryWrapper<>();
wrapper.ge(HrtNews::getCreateTime, startTime);
wrapper.le(HrtNews::getCreateTime, endTime);
return mapper.selectCount(wrapper);
}
/**
* @description [按日期范围统计活动]
* @author Leocoder
*/
private Long countByDateRange(HrtEventMapper mapper, LocalDateTime startTime, LocalDateTime endTime) {
LambdaQueryWrapper<HrtEvent> wrapper = new LambdaQueryWrapper<>();
wrapper.ge(HrtEvent::getCreateTime, startTime);
wrapper.le(HrtEvent::getCreateTime, endTime);
return mapper.selectCount(wrapper);
}
}

View File

@ -0,0 +1,65 @@
package org.leocoder.heritage.admin.service.user;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.leocoder.heritage.domain.model.bo.admin.HrtUserAdminBo;
import org.leocoder.heritage.domain.model.bo.admin.HrtUserAdminQueryBo;
import org.leocoder.heritage.domain.model.vo.admin.HrtUserAdminDetailVo;
import org.leocoder.heritage.domain.model.vo.admin.HrtUserAdminVo;
import java.util.List;
/**
* @author Leocoder
* @description [前台用户管理服务接口]
*/
public interface HrtUserAdminService {
/**
* @description [分页查询用户列表后台管理]
* @author Leocoder
*/
IPage<HrtUserAdminVo> listPage(HrtUserAdminQueryBo bo);
/**
* @description [查看用户详情后台管理]
* @author Leocoder
*/
HrtUserAdminDetailVo getDetail(Long id);
/**
* @description [新增用户]
* @author Leocoder
*/
Long addUser(HrtUserAdminBo bo);
/**
* @description [编辑用户]
* @author Leocoder
*/
Boolean editUser(HrtUserAdminBo bo);
/**
* @description [删除用户]
* @author Leocoder
*/
Boolean deleteUser(Long id);
/**
* @description [批量删除用户]
* @author Leocoder
*/
Boolean batchDelete(List<Long> ids);
/**
* @description [修改用户状态]
* @author Leocoder
*/
Boolean changeStatus(Long id, Integer status);
/**
* @description [重置用户密码]
* @author Leocoder
*/
Boolean resetPassword(Long id, String newPassword);
}

View File

@ -0,0 +1,351 @@
package org.leocoder.heritage.admin.service.user;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.leocoder.heritage.common.exception.BusinessException;
import org.leocoder.heritage.domain.model.bo.admin.HrtUserAdminBo;
import org.leocoder.heritage.satoken.config.CoderSaTokenPasswordUtil;
import org.leocoder.heritage.domain.model.bo.admin.HrtUserAdminQueryBo;
import org.leocoder.heritage.domain.model.vo.admin.HrtUserAdminDetailVo;
import org.leocoder.heritage.domain.model.vo.admin.HrtUserAdminVo;
import org.leocoder.heritage.domain.pojo.portal.HrtUser;
import org.leocoder.heritage.mybatisplus.mapper.portal.HrtUserMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Objects;
/**
* @author Leocoder
* @description [前台用户管理服务实现类]
*/
@Service
@RequiredArgsConstructor
public class HrtUserAdminServiceImpl implements HrtUserAdminService {
private final HrtUserMapper userMapper;
/**
* @description [分页查询用户列表后台管理]
* @author Leocoder
*/
@Override
public IPage<HrtUserAdminVo> listPage(HrtUserAdminQueryBo bo) {
Page<HrtUser> page = new Page<>(bo.getPageNum(), bo.getPageSize());
LambdaQueryWrapper<HrtUser> wrapper = new LambdaQueryWrapper<>();
// 用户名模糊查询
wrapper.like(StrUtil.isNotEmpty(bo.getUsername()), HrtUser::getUsername, bo.getUsername());
// 昵称模糊查询
wrapper.like(StrUtil.isNotEmpty(bo.getNickname()), HrtUser::getNickname, bo.getNickname());
// 手机号精确查询
wrapper.eq(StrUtil.isNotEmpty(bo.getPhone()), HrtUser::getPhone, bo.getPhone());
// 邮箱精确查询
wrapper.eq(StrUtil.isNotEmpty(bo.getEmail()), HrtUser::getEmail, bo.getEmail());
// 状态查询
wrapper.eq(Objects.nonNull(bo.getStatus()), HrtUser::getStatus, bo.getStatus());
// 性别查询
wrapper.eq(Objects.nonNull(bo.getGender()), HrtUser::getGender, bo.getGender());
// 省份查询
wrapper.eq(StrUtil.isNotEmpty(bo.getProvince()), HrtUser::getProvince, bo.getProvince());
// 城市查询
wrapper.eq(StrUtil.isNotEmpty(bo.getCity()), HrtUser::getCity, bo.getCity());
// 关键词搜索用户名昵称手机号邮箱
if (StrUtil.isNotEmpty(bo.getKeyword())) {
wrapper.and(w -> w
.like(HrtUser::getUsername, bo.getKeyword())
.or()
.like(HrtUser::getNickname, bo.getKeyword())
.or()
.like(HrtUser::getPhone, bo.getKeyword())
.or()
.like(HrtUser::getEmail, bo.getKeyword())
);
}
// 注册时间范围查询
wrapper.ge(Objects.nonNull(bo.getCreateTimeBegin()), HrtUser::getCreateTime, bo.getCreateTimeBegin());
wrapper.le(Objects.nonNull(bo.getCreateTimeEnd()), HrtUser::getCreateTime, bo.getCreateTimeEnd());
// 排序处理
if ("asc".equalsIgnoreCase(bo.getSortOrder())) {
if ("login_time".equals(bo.getSortField())) {
wrapper.orderByAsc(HrtUser::getLoginTime);
} else {
wrapper.orderByAsc(HrtUser::getCreateTime);
}
} else {
if ("login_time".equals(bo.getSortField())) {
wrapper.orderByDesc(HrtUser::getLoginTime);
} else {
wrapper.orderByDesc(HrtUser::getCreateTime);
}
}
IPage<HrtUser> userPage = userMapper.selectPage(page, wrapper);
return userPage.convert(user -> BeanUtil.copyProperties(user, HrtUserAdminVo.class));
}
/**
* @description [查看用户详情后台管理]
* @author Leocoder
*/
@Override
public HrtUserAdminDetailVo getDetail(Long id) {
HrtUser user = userMapper.selectById(id);
if (user == null) {
throw new BusinessException(404, "用户不存在");
}
return BeanUtil.copyProperties(user, HrtUserAdminDetailVo.class);
}
/**
* @description [新增用户]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Long addUser(HrtUserAdminBo bo) {
// 验证用户名是否已存在
checkUsernameExists(bo.getUsername(), null);
// 验证手机号是否已存在
if (StrUtil.isNotEmpty(bo.getPhone())) {
checkPhoneExists(bo.getPhone(), null);
}
// 验证邮箱是否已存在
if (StrUtil.isNotEmpty(bo.getEmail())) {
checkEmailExists(bo.getEmail(), null);
}
// 密码必填校验
if (StrUtil.isEmpty(bo.getPassword())) {
throw new BusinessException(400, "密码不能为空");
}
HrtUser user = BeanUtil.copyProperties(bo, HrtUser.class);
// 处理空字符串转null,避免唯一索引冲突
if (StrUtil.isEmpty(bo.getEmail())) {
user.setEmail(null);
}
if (StrUtil.isEmpty(bo.getPhone())) {
user.setPhone(null);
}
// 加密密码 - 使用统一的密码加密工具
String encryptedPassword = CoderSaTokenPasswordUtil.encryptPassword(bo.getPassword());
user.setPassword(encryptedPassword);
// 初始化状态为正常
if (user.getStatus() == null) {
user.setStatus(1);
}
int result = userMapper.insert(user);
if (result <= 0) {
throw new BusinessException(500, "新增用户失败");
}
return user.getId();
}
/**
* @description [编辑用户]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean editUser(HrtUserAdminBo bo) {
if (bo.getId() == null) {
throw new BusinessException(400, "用户ID不能为空");
}
// 检查用户是否存在
HrtUser existUser = userMapper.selectById(bo.getId());
if (existUser == null) {
throw new BusinessException(404, "用户不存在");
}
// 验证用户名是否已被其他用户使用
checkUsernameExists(bo.getUsername(), bo.getId());
// 验证手机号是否已被其他用户使用
if (StrUtil.isNotEmpty(bo.getPhone())) {
checkPhoneExists(bo.getPhone(), bo.getId());
}
// 验证邮箱是否已被其他用户使用
if (StrUtil.isNotEmpty(bo.getEmail())) {
checkEmailExists(bo.getEmail(), bo.getId());
}
HrtUser user = BeanUtil.copyProperties(bo, HrtUser.class);
// 处理空字符串转null,避免唯一索引冲突
if (StrUtil.isEmpty(bo.getEmail())) {
user.setEmail(null);
}
if (StrUtil.isEmpty(bo.getPhone())) {
user.setPhone(null);
}
// 编辑用户时不修改密码密码修改请使用专门的重置密码接口
user.setPassword(null);
int result = userMapper.updateById(user);
return result > 0;
}
/**
* @description [删除用户]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean deleteUser(Long id) {
// 检查用户是否存在
HrtUser user = userMapper.selectById(id);
if (user == null) {
throw new BusinessException(404, "用户不存在");
}
int result = userMapper.deleteById(id);
return result > 0;
}
/**
* @description [批量删除用户]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean batchDelete(List<Long> ids) {
if (ids == null || ids.isEmpty()) {
throw new BusinessException(400, "请选择要删除的用户");
}
int result = userMapper.deleteBatchIds(ids);
return result > 0;
}
/**
* @description [修改用户状态]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean changeStatus(Long id, Integer status) {
// 检查用户是否存在
HrtUser user = userMapper.selectById(id);
if (user == null) {
throw new BusinessException(404, "用户不存在");
}
if (status == null || (status != 0 && status != 1)) {
throw new BusinessException(400, "用户状态参数错误");
}
HrtUser updateUser = new HrtUser();
updateUser.setId(id);
updateUser.setStatus(status);
int result = userMapper.updateById(updateUser);
return result > 0;
}
/**
* @description [重置用户密码]
* @author Leocoder
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean resetPassword(Long id, String newPassword) {
// 检查用户是否存在
HrtUser user = userMapper.selectById(id);
if (user == null) {
throw new BusinessException(404, "用户不存在");
}
if (StrUtil.isEmpty(newPassword)) {
throw new BusinessException(400, "新密码不能为空");
}
// 加密密码 - 使用统一的密码加密工具
String encryptedPassword = CoderSaTokenPasswordUtil.encryptPassword(newPassword);
HrtUser updateUser = new HrtUser();
updateUser.setId(id);
updateUser.setPassword(encryptedPassword);
int result = userMapper.updateById(updateUser);
return result > 0;
}
/**
* @description [检查用户名是否已存在]
* @author Leocoder
*/
private void checkUsernameExists(String username, Long excludeId) {
LambdaQueryWrapper<HrtUser> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(HrtUser::getUsername, username);
if (excludeId != null) {
wrapper.ne(HrtUser::getId, excludeId);
}
Long count = userMapper.selectCount(wrapper);
if (count > 0) {
throw new BusinessException(400, "用户名已存在");
}
}
/**
* @description [检查手机号是否已存在]
* @author Leocoder
*/
private void checkPhoneExists(String phone, Long excludeId) {
LambdaQueryWrapper<HrtUser> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(HrtUser::getPhone, phone);
if (excludeId != null) {
wrapper.ne(HrtUser::getId, excludeId);
}
Long count = userMapper.selectCount(wrapper);
if (count > 0) {
throw new BusinessException(400, "手机号已存在");
}
}
/**
* @description [检查邮箱是否已存在]
* @author Leocoder
*/
private void checkEmailExists(String email, Long excludeId) {
LambdaQueryWrapper<HrtUser> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(HrtUser::getEmail, email);
if (excludeId != null) {
wrapper.ne(HrtUser::getId, excludeId);
}
Long count = userMapper.selectCount(wrapper);
if (count > 0) {
throw new BusinessException(400, "邮箱已存在");
}
}
}