diff --git a/珞珈岛-项目相关文件/luojia-island/common/src/main/java/com/luojia_channel/common/config/WebMvcConfig.java b/珞珈岛-项目相关文件/luojia-island/common/src/main/java/com/luojia_channel/common/config/WebMvcConfig.java index 07715a6..278bbb5 100644 --- a/珞珈岛-项目相关文件/luojia-island/common/src/main/java/com/luojia_channel/common/config/WebMvcConfig.java +++ b/珞珈岛-项目相关文件/luojia-island/common/src/main/java/com/luojia_channel/common/config/WebMvcConfig.java @@ -18,6 +18,7 @@ public class WebMvcConfig implements WebMvcConfigurer { "/user/register", "/user/captcha", "/user/verify-captcha", + "/user/info/getuserinfo", "/post/list", "/post/detail", "/comment/list", diff --git a/珞珈岛-项目相关文件/luojia-island/service/pom.xml b/珞珈岛-项目相关文件/luojia-island/service/pom.xml index ebc0e28..08590a0 100644 --- a/珞珈岛-项目相关文件/luojia-island/service/pom.xml +++ b/珞珈岛-项目相关文件/luojia-island/service/pom.xml @@ -56,6 +56,13 @@ test + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.1.0 + + diff --git a/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/admin/controller/AdminController.java b/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/admin/controller/AdminController.java new file mode 100644 index 0000000..2bfb2de --- /dev/null +++ b/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/admin/controller/AdminController.java @@ -0,0 +1,127 @@ +package com.luojia_channel.modules.admin.controller; + +import com.luojia_channel.common.domain.Result; +import com.luojia_channel.common.domain.page.PageResponse; +import com.luojia_channel.modules.admin.dto.*; +import com.luojia_channel.modules.admin.service.AdminService; +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.springframework.web.bind.annotation.*; + +import java.util.Map; + +@RestController +@RequestMapping("/admin") +@RequiredArgsConstructor +@Tag(name = "管理员模块", description = "管理员相关接口") +public class AdminController { + + private final AdminService adminService; + + @GetMapping("/overview") + @Operation(summary = "获取系统总览数据", description = "获取系统各项统计数据,包括用户总数、帖子总数、评论总数、活跃用户等") + public Result getOverview() { + return Result.success(adminService.getOverview()); + } + + @GetMapping("/users") + @Operation(summary = "获取用户列表", description = "分页获取用户列表,支持按用户名、手机号、邮箱等搜索筛选") + public Result> getUsers( + @Parameter(description = "页码") @RequestParam(defaultValue = "1") Integer page, + @Parameter(description = "每页数量") @RequestParam(defaultValue = "10") Integer size, + @Parameter(description = "搜索关键词") @RequestParam(required = false) String keyword, + @Parameter(description = "用户角色") @RequestParam(required = false) Integer role, + @Parameter(description = "用户状态") @RequestParam(required = false) Integer status + ) { + return Result.success(adminService.getUserList(page, size, keyword, role, status)); + } + + @PutMapping("/users/{id}/status") + @Operation(summary = "更改用户状态", description = "冻结或解冻用户") + public Result changeUserStatus( + @Parameter(description = "用户ID") @PathVariable Long id, + @Parameter(description = "状态(1正常 2冻结)") @RequestParam Integer status + ) { + adminService.changeUserStatus(id, status); + return Result.success(); + } + + @PutMapping("/users/{id}/role") + @Operation(summary = "更改用户角色", description = "升级或降级用户角色") + public Result changeUserRole( + @Parameter(description = "用户ID") @PathVariable Long id, + @Parameter(description = "角色(1普通用户 2管理员 3超级管理员)") @RequestParam Integer role + ) { + adminService.changeUserRole(id, role); + return Result.success(); + } + + @GetMapping("/posts") + @Operation(summary = "获取帖子列表", description = "分页获取帖子列表,支持按标题、内容、分类等搜索筛选") + public Result> getPosts( + @Parameter(description = "页码") @RequestParam(defaultValue = "1") Integer page, + @Parameter(description = "每页数量") @RequestParam(defaultValue = "10") Integer size, + @Parameter(description = "搜索关键词") @RequestParam(required = false) String keyword, + @Parameter(description = "分类ID") @RequestParam(required = false) Long categoryId, + @Parameter(description = "状态") @RequestParam(required = false) Integer status + ) { + return Result.success(adminService.getPostList(page, size, keyword, categoryId, status)); + } + + @DeleteMapping("/posts/{id}") + @Operation(summary = "删除帖子", description = "管理员删除帖子") + public Result deletePost(@Parameter(description = "帖子ID") @PathVariable Long id) { + adminService.deletePost(id); + return Result.success(); + } + + @PutMapping("/posts/{id}/status") + @Operation(summary = "更改帖子状态", description = "置顶、取消置顶、隐藏或显示帖子") + public Result changePostStatus( + @Parameter(description = "帖子ID") @PathVariable Long id, + @Parameter(description = "操作类型(1置顶 2取消置顶 3隐藏 4显示)") @RequestParam Integer action + ) { + adminService.changePostStatus(id, action); + return Result.success(); + } + + @GetMapping("/comments") + @Operation(summary = "获取评论列表", description = "分页获取评论列表,支持按内容、帖子ID等搜索筛选") + public Result> getComments( + @Parameter(description = "页码") @RequestParam(defaultValue = "1") Integer page, + @Parameter(description = "每页数量") @RequestParam(defaultValue = "10") Integer size, + @Parameter(description = "搜索关键词") @RequestParam(required = false) String keyword, + @Parameter(description = "帖子ID") @RequestParam(required = false) Long postId + ) { + return Result.success(adminService.getCommentList(page, size, keyword, postId)); + } + + @DeleteMapping("/comments/{id}") + @Operation(summary = "删除评论", description = "管理员删除评论") + public Result deleteComment(@Parameter(description = "评论ID") @PathVariable Long id) { + adminService.deleteComment(id); + return Result.success(); + } + + @GetMapping("/statistics/user") + @Operation(summary = "获取用户统计数据", description = "获取用户注册增长、活跃度等统计数据") + public Result> getUserStatistics( + @Parameter(description = "统计类型(daily,weekly,monthly)") @RequestParam(defaultValue = "daily") String type, + @Parameter(description = "开始日期") @RequestParam(required = false) String startDate, + @Parameter(description = "结束日期") @RequestParam(required = false) String endDate + ) { + return Result.success(adminService.getUserStatistics(type, startDate, endDate)); + } + + @GetMapping("/statistics/post") + @Operation(summary = "获取帖子统计数据", description = "获取帖子发布、点赞、收藏等统计数据") + public Result> getPostStatistics( + @Parameter(description = "统计类型(daily,weekly,monthly)") @RequestParam(defaultValue = "daily") String type, + @Parameter(description = "开始日期") @RequestParam(required = false) String startDate, + @Parameter(description = "结束日期") @RequestParam(required = false) String endDate + ) { + return Result.success(adminService.getPostStatistics(type, startDate, endDate)); + } +} \ No newline at end of file diff --git a/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/admin/dto/AdminCommentDTO.java b/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/admin/dto/AdminCommentDTO.java new file mode 100644 index 0000000..9625da1 --- /dev/null +++ b/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/admin/dto/AdminCommentDTO.java @@ -0,0 +1,81 @@ +package com.luojia_channel.modules.admin.dto; + +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 管理员评论DTO + */ +@Data +public class AdminCommentDTO { + /** + * 评论ID + */ + private Long id; + + /** + * 评论内容 + */ + private String content; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 用户ID + */ + private Long userId; + + /** + * 用户名 + */ + private String username; + + /** + * 用户头像 + */ + private String userAvatar; + + /** + * 帖子ID + */ + private Long postId; + + /** + * 帖子标题 + */ + private String postTitle; + + /** + * 父评论ID + */ + private Long parentCommentId; + + /** + * 顶级评论ID + */ + private Long topId; + + /** + * 回复用户名 + */ + private String replyUsername; + + /** + * 点赞数 + */ + private Integer likeCount; + + /** + * 回复数 + */ + private Integer replyCount; +} \ No newline at end of file diff --git a/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/admin/dto/AdminOverviewDTO.java b/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/admin/dto/AdminOverviewDTO.java new file mode 100644 index 0000000..ed52761 --- /dev/null +++ b/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/admin/dto/AdminOverviewDTO.java @@ -0,0 +1,82 @@ +package com.luojia_channel.modules.admin.dto; + +import lombok.Data; + +import java.util.List; +import java.util.Map; + +/** + * 管理员总览数据DTO + */ +@Data +public class AdminOverviewDTO { + /** + * 用户总数 + */ + private Long totalUsers; + + /** + * 今日新增用户数 + */ + private Long newUsers; + + /** + * 帖子总数 + */ + private Long totalPosts; + + /** + * 今日新增帖子数 + */ + private Long newPosts; + + /** + * 评论总数 + */ + private Long totalComments; + + /** + * 今日新增评论数 + */ + private Long newComments; + + /** + * 总浏览量 + */ + private Long totalViews; + + /** + * 今日浏览量 + */ + private Long todayViews; + + /** + * 活跃用户排行 + */ + private List activeUsers; + + /** + * 热门帖子排行 + */ + private List hotPosts; + + /** + * 用户增长趋势(最近7天) + */ + private Map userGrowth; + + /** + * 帖子增长趋势(最近7天) + */ + private Map postGrowth; + + /** + * 用户类型分布(按角色) + */ + private Map userRoleDistribution; + + /** + * 帖子分类分布 + */ + private Map postCategoryDistribution; +} \ No newline at end of file diff --git a/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/admin/dto/AdminPostDTO.java b/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/admin/dto/AdminPostDTO.java new file mode 100644 index 0000000..ea74603 --- /dev/null +++ b/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/admin/dto/AdminPostDTO.java @@ -0,0 +1,91 @@ +package com.luojia_channel.modules.admin.dto; + +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 管理员帖子DTO + */ +@Data +public class AdminPostDTO { + /** + * 帖子ID + */ + private Long id; + + /** + * 帖子标题 + */ + private String title; + + /** + * 帖子内容 + */ + private String content; + + /** + * 帖子图片 + */ + private String image; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 状态(0:正常 1:置顶 2:隐藏) + */ + private Integer status; + + /** + * 用户ID + */ + private Long userId; + + /** + * 用户名 + */ + private String username; + + /** + * 用户头像 + */ + private String userAvatar; + + /** + * 分类ID + */ + private Long categoryId; + + /** + * 分类名称 + */ + private String categoryName; + + /** + * 点赞数 + */ + private Integer likeCount; + + /** + * 评论数 + */ + private Integer commentCount; + + /** + * 收藏数 + */ + private Integer favoriteCount; + + /** + * 浏览量 + */ + private Integer viewCount; +} \ No newline at end of file diff --git a/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/admin/dto/AdminUserDTO.java b/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/admin/dto/AdminUserDTO.java new file mode 100644 index 0000000..35af5ea --- /dev/null +++ b/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/admin/dto/AdminUserDTO.java @@ -0,0 +1,71 @@ +package com.luojia_channel.modules.admin.dto; + +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 管理员用户DTO - 仅包含管理员可见的非隐私信息 + */ +@Data +public class AdminUserDTO { + /** + * 用户ID + */ + private Long id; + + /** + * 用户名 + */ + private String username; + + /** + * 头像URL + */ + private String avatar; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 用户状态(1正常 2冻结) + */ + private Integer status; + + /** + * 用户角色(1普通用户 2管理员 3超级管理员) + */ + private Integer role; + + /** + * 用户积分 + */ + private Integer integral; + + /** + * 发帖数量 + */ + private Integer postCount; + + /** + * 评论数量 + */ + private Integer commentCount; + + /** + * 粉丝数量 + */ + private Integer followerCount; + + /** + * 关注数量 + */ + private Integer followingCount; +} \ No newline at end of file diff --git a/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/admin/service/AdminService.java b/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/admin/service/AdminService.java new file mode 100644 index 0000000..f4941ef --- /dev/null +++ b/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/admin/service/AdminService.java @@ -0,0 +1,100 @@ +package com.luojia_channel.modules.admin.service; + +import com.luojia_channel.common.domain.page.PageResponse; +import com.luojia_channel.modules.admin.dto.*; + +import java.util.Map; + +/** + * 管理员服务接口 + */ +public interface AdminService { + /** + * 获取系统总览数据 + * @return 总览数据 + */ + AdminOverviewDTO getOverview(); + + /** + * 获取用户列表 + * @param page 页码 + * @param size 每页数量 + * @param keyword 搜索关键词 + * @param role 角色 + * @param status 状态 + * @return 用户列表分页结果 + */ + PageResponse getUserList(Integer page, Integer size, String keyword, Integer role, Integer status); + + /** + * 修改用户状态 + * @param id 用户ID + * @param status 状态 + */ + void changeUserStatus(Long id, Integer status); + + /** + * 修改用户角色 + * @param id 用户ID + * @param role 角色 + */ + void changeUserRole(Long id, Integer role); + + /** + * 获取帖子列表 + * @param page 页码 + * @param size 每页数量 + * @param keyword 搜索关键词 + * @param categoryId 分类ID + * @param status 状态 + * @return 帖子列表分页结果 + */ + PageResponse getPostList(Integer page, Integer size, String keyword, Long categoryId, Integer status); + + /** + * 删除帖子 + * @param id 帖子ID + */ + void deletePost(Long id); + + /** + * 修改帖子状态 + * @param id 帖子ID + * @param action 操作类型 + */ + void changePostStatus(Long id, Integer action); + + /** + * 获取评论列表 + * @param page 页码 + * @param size 每页数量 + * @param keyword 搜索关键词 + * @param postId 帖子ID + * @return 评论列表分页结果 + */ + PageResponse getCommentList(Integer page, Integer size, String keyword, Long postId); + + /** + * 删除评论 + * @param id 评论ID + */ + void deleteComment(Long id); + + /** + * 获取用户统计数据 + * @param type 统计类型 + * @param startDate 开始日期 + * @param endDate 结束日期 + * @return 统计数据 + */ + Map getUserStatistics(String type, String startDate, String endDate); + + /** + * 获取帖子统计数据 + * @param type 统计类型 + * @param startDate 开始日期 + * @param endDate 结束日期 + * @return 统计数据 + */ + Map getPostStatistics(String type, String startDate, String endDate); +} \ No newline at end of file diff --git a/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/admin/service/impl/AdminServiceImpl.java b/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/admin/service/impl/AdminServiceImpl.java new file mode 100644 index 0000000..4a33cd2 --- /dev/null +++ b/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/admin/service/impl/AdminServiceImpl.java @@ -0,0 +1,547 @@ +package com.luojia_channel.modules.admin.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.luojia_channel.common.domain.page.PageResponse; +import com.luojia_channel.modules.admin.dto.*; +import com.luojia_channel.modules.admin.service.AdminService; +import com.luojia_channel.modules.post.entity.Post; +import com.luojia_channel.modules.post.entity.Comment; +import com.luojia_channel.modules.post.mapper.PostMapper; +import com.luojia_channel.modules.post.mapper.CommentMapper; +import com.luojia_channel.modules.user.entity.User; +import com.luojia_channel.modules.user.mapper.UserMapper; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 管理员服务实现类 + */ +@Service +@RequiredArgsConstructor +public class AdminServiceImpl implements AdminService { + + private final UserMapper userMapper; + private final PostMapper postMapper; + private final CommentMapper commentMapper; + + @Override + public AdminOverviewDTO getOverview() { + AdminOverviewDTO overview = new AdminOverviewDTO(); + + // 获取用户总数 + overview.setTotalUsers(userMapper.selectCount(null)); + + // 获取今日新增用户数 + LocalDateTime today = LocalDate.now().atStartOfDay(); + overview.setNewUsers(userMapper.selectCount( + new LambdaQueryWrapper() + .ge(User::getCreateTime, today) + )); + + // 获取帖子总数 + overview.setTotalPosts(postMapper.selectCount(null)); + + // 获取今日新增帖子数 + overview.setNewPosts(postMapper.selectCount( + new LambdaQueryWrapper() + .ge(Post::getCreateTime, today) + )); + + // 获取评论总数 + overview.setTotalComments(commentMapper.selectCount(null)); + + // 获取今日新增评论数 + overview.setNewComments(commentMapper.selectCount( + new LambdaQueryWrapper() + .ge(Comment::getCreateTime, today) + )); + + // 获取总浏览量和今日浏览量(假设有这样的字段或方法) + overview.setTotalViews(0L); // 实际项目中应该从数据库获取 + overview.setTodayViews(0L); // 实际项目中应该从数据库获取 + + // 获取活跃用户排行(假设通过发帖和评论数量判断) + List activeUsers = new ArrayList<>(); // 实际项目中应该从数据库联表查询 + overview.setActiveUsers(activeUsers); + + // 获取热门帖子排行 + List hotPosts = new ArrayList<>(); // 实际项目中应该从数据库联表查询 + overview.setHotPosts(hotPosts); + + // 用户增长趋势(最近7天) + Map userGrowth = new LinkedHashMap<>(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM-dd"); + LocalDate end = LocalDate.now(); + LocalDate start = end.minusDays(6); + for (LocalDate date = start; !date.isAfter(end); date = date.plusDays(1)) { + String dateStr = date.format(formatter); + LocalDateTime dayStart = date.atStartOfDay(); + LocalDateTime dayEnd = date.plusDays(1).atStartOfDay(); + + Long count = userMapper.selectCount( + new LambdaQueryWrapper() + .ge(User::getCreateTime, dayStart) + .lt(User::getCreateTime, dayEnd) + ); + userGrowth.put(dateStr, count); + } + overview.setUserGrowth(userGrowth); + + // 帖子增长趋势(最近7天) + Map postGrowth = new LinkedHashMap<>(); + for (LocalDate date = start; !date.isAfter(end); date = date.plusDays(1)) { + String dateStr = date.format(formatter); + LocalDateTime dayStart = date.atStartOfDay(); + LocalDateTime dayEnd = date.plusDays(1).atStartOfDay(); + + Long count = postMapper.selectCount( + new LambdaQueryWrapper() + .ge(Post::getCreateTime, dayStart) + .lt(Post::getCreateTime, dayEnd) + ); + postGrowth.put(dateStr, count); + } + overview.setPostGrowth(postGrowth); + + // 用户类型分布(按角色) + Map userRoleDistribution = new HashMap<>(); + userRoleDistribution.put("普通用户", userMapper.selectCount( + new LambdaQueryWrapper().eq(User::getRole, 1) + )); + userRoleDistribution.put("管理员", userMapper.selectCount( + new LambdaQueryWrapper().eq(User::getRole, 2) + )); + userRoleDistribution.put("超级管理员", userMapper.selectCount( + new LambdaQueryWrapper().eq(User::getRole, 3) + )); + overview.setUserRoleDistribution(userRoleDistribution); + + // 帖子分类分布(实际项目中应该从分类表联查) + Map postCategoryDistribution = new HashMap<>(); + overview.setPostCategoryDistribution(postCategoryDistribution); + + return overview; + } + + @Override + public PageResponse getUserList(Integer page, Integer size, String keyword, Integer role, Integer status) { + Page pageParam = new Page<>(page, size); + + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + + // 按条件筛选 + if (StringUtils.hasText(keyword)) { + queryWrapper.like(User::getUsername, keyword); + } + + if (role != null) { + queryWrapper.eq(User::getRole, role); + } + + if (status != null) { + queryWrapper.eq(User::getStatus, status); + } + + // 按创建时间降序排序 + queryWrapper.orderByDesc(User::getCreateTime); + + IPage userPage = userMapper.selectPage(pageParam, queryWrapper); + + // 转换为DTO + List userDTOs = userPage.getRecords().stream().map(user -> { + AdminUserDTO dto = new AdminUserDTO(); + BeanUtils.copyProperties(user, dto); + + // 获取用户的发帖数、评论数、粉丝数、关注数(实际项目中应该通过关联查询获取) + dto.setPostCount(0); + dto.setCommentCount(0); + dto.setFollowerCount(0); + dto.setFollowingCount(0); + + return dto; + }).collect(Collectors.toList()); + + return PageResponse.builder() + .current((long) page) + .size((long) size) + .total(userPage.getTotal()) + .records(userDTOs) + .build(); + } + + @Override + @Transactional + public void changeUserStatus(Long id, Integer status) { + if (id == null || status == null) { + throw new IllegalArgumentException("参数不能为空"); + } + + // 检查状态值是否合法 + if (status != 1 && status != 2) { + throw new IllegalArgumentException("用户状态值不合法"); + } + + // 检查用户是否存在 + User user = userMapper.selectById(id); + if (user == null) { + throw new IllegalArgumentException("用户不存在"); + } + + // 修改状态 + user.setStatus(status); + userMapper.updateById(user); + } + + @Override + @Transactional + public void changeUserRole(Long id, Integer role) { + if (id == null || role == null) { + throw new IllegalArgumentException("参数不能为空"); + } + + // 检查角色值是否合法 + if (role < 1 || role > 3) { + throw new IllegalArgumentException("用户角色值不合法"); + } + + // 检查用户是否存在 + User user = userMapper.selectById(id); + if (user == null) { + throw new IllegalArgumentException("用户不存在"); + } + + // 修改角色 + user.setRole(role); + userMapper.updateById(user); + } + + @Override + public PageResponse getPostList(Integer page, Integer size, String keyword, Long categoryId, Integer status) { + Page pageParam = new Page<>(page, size); + + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + + // 按条件筛选 + if (StringUtils.hasText(keyword)) { + queryWrapper.like(Post::getTitle, keyword) + .or().like(Post::getContent, keyword); + } + + if (categoryId != null) { + queryWrapper.eq(Post::getCategoryId, categoryId); + } + + if (status != null) { + queryWrapper.eq(Post::getStatus, status); + } + + // 按创建时间降序排序 + queryWrapper.orderByDesc(Post::getCreateTime); + + IPage postPage = postMapper.selectPage(pageParam, queryWrapper); + + // 转换为DTO + List postDTOs = postPage.getRecords().stream().map(post -> { + AdminPostDTO dto = new AdminPostDTO(); + BeanUtils.copyProperties(post, dto); + + // 获取发帖用户信息(实际项目中应该通过关联查询获取) + User user = userMapper.selectById(post.getUserId()); + if (user != null) { + dto.setUsername(user.getUsername()); + dto.setUserAvatar(user.getAvatar()); + } + + // 获取分类信息(实际项目中应该通过关联查询获取) + dto.setCategoryName("默认分类"); // 示例值,实际应从数据库获取 + + // 获取帖子的点赞数、评论数、收藏数、浏览量(实际项目中应该通过关联查询获取) + dto.setLikeCount(0); + dto.setCommentCount(0); + dto.setFavoriteCount(0); + dto.setViewCount(0); + + return dto; + }).collect(Collectors.toList()); + + return PageResponse.builder() + .current((long) page) + .size((long) size) + .total(postPage.getTotal()) + .records(postDTOs) + .build(); + } + + @Override + @Transactional + public void deletePost(Long id) { + if (id == null) { + throw new IllegalArgumentException("参数不能为空"); + } + + // 检查帖子是否存在 + Post post = postMapper.selectById(id); + if (post == null) { + throw new IllegalArgumentException("帖子不存在或已被删除"); + } + + // 删除帖子 + postMapper.deleteById(id); + + // 删除关联的评论(实际项目中应该通过关联删除) + commentMapper.delete(new LambdaQueryWrapper() + .eq(Comment::getPostId, id)); + } + + @Override + @Transactional + public void changePostStatus(Long id, Integer action) { + if (id == null || action == null) { + throw new IllegalArgumentException("参数不能为空"); + } + + // 检查帖子是否存在 + Post post = postMapper.selectById(id); + if (post == null) { + throw new IllegalArgumentException("帖子不存在或已被删除"); + } + + // 根据操作类型修改状态 + switch (action) { + case 1: // 置顶 + post.setStatus(1); + break; + case 2: // 取消置顶 + post.setStatus(0); + break; + case 3: // 隐藏 + post.setStatus(2); + break; + case 4: // 显示 + post.setStatus(0); + break; + default: + throw new IllegalArgumentException("操作类型不合法"); + } + + postMapper.updateById(post); + } + + @Override + public PageResponse getCommentList(Integer page, Integer size, String keyword, Long postId) { + Page pageParam = new Page<>(page, size); + + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + + // 按条件筛选 + if (StringUtils.hasText(keyword)) { + queryWrapper.like(Comment::getContent, keyword); + } + + if (postId != null) { + queryWrapper.eq(Comment::getPostId, postId); + } + + // 按创建时间降序排序 + queryWrapper.orderByDesc(Comment::getCreateTime); + + IPage commentPage = commentMapper.selectPage(pageParam, queryWrapper); + + // 转换为DTO + List commentDTOs = commentPage.getRecords().stream().map(comment -> { + AdminCommentDTO dto = new AdminCommentDTO(); + BeanUtils.copyProperties(comment, dto); + + // 获取评论用户信息(实际项目中应该通过关联查询获取) + User user = userMapper.selectById(comment.getUserId()); + if (user != null) { + dto.setUsername(user.getUsername()); + dto.setUserAvatar(user.getAvatar()); + } + + // 获取回复用户信息(实际项目中应该通过关联查询获取) + if (comment.getParentCommentId() != null) { + User replyUser = userMapper.selectById(comment.getParentCommentId()); + if (replyUser != null) { + dto.setReplyUsername(replyUser.getUsername()); + } + } + + // 获取帖子信息(实际项目中应该通过关联查询获取) + Post post = postMapper.selectById(comment.getPostId()); + if (post != null) { + dto.setPostTitle(post.getTitle()); + } + + // 获取评论的点赞数(实际项目中应该通过关联查询获取) + dto.setLikeCount(comment.getLikeCount() != null ? comment.getLikeCount().intValue() : 0); + + return dto; + }).collect(Collectors.toList()); + + return PageResponse.builder() + .current((long) page) + .size((long) size) + .total(commentPage.getTotal()) + .records(commentDTOs) + .build(); + } + + @Override + @Transactional + public void deleteComment(Long id) { + if (id == null) { + throw new IllegalArgumentException("参数不能为空"); + } + + // 检查评论是否存在 + Comment comment = commentMapper.selectById(id); + if (comment == null) { + throw new IllegalArgumentException("评论不存在或已被删除"); + } + + // 删除评论 + commentMapper.deleteById(id); + + // 删除子评论(实际项目中应该根据具体业务逻辑决定是否删除) + commentMapper.delete(new LambdaQueryWrapper() + .eq(Comment::getParentCommentId, id)); + } + + @Override + public Map getUserStatistics(String type, String startDate, String endDate) { + Map result = new HashMap<>(); + + // 日期格式化器 + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + + // 默认查询最近7天 + LocalDate end = endDate != null ? LocalDate.parse(endDate, formatter) : LocalDate.now(); + LocalDate start; + + if (startDate != null) { + start = LocalDate.parse(startDate, formatter); + } else { + switch (type) { + case "weekly": + start = end.minusDays(7); + break; + case "monthly": + start = end.minusDays(30); + break; + case "daily": + default: + start = end.minusDays(7); + break; + } + } + + // 用户注册统计 + Map registrations = new LinkedHashMap<>(); + for (LocalDate date = start; !date.isAfter(end); date = date.plusDays(1)) { + String dateStr = date.format(formatter); + LocalDateTime dayStart = date.atStartOfDay(); + LocalDateTime dayEnd = date.plusDays(1).atStartOfDay(); + + Long count = userMapper.selectCount( + new LambdaQueryWrapper() + .ge(User::getCreateTime, dayStart) + .lt(User::getCreateTime, dayEnd) + ); + registrations.put(dateStr, count); + } + result.put("registrations", registrations); + + // 用户活跃度统计(实际项目中应该根据登录记录或操作记录统计) + Map activeUsers = new LinkedHashMap<>(); + for (LocalDate date = start; !date.isAfter(end); date = date.plusDays(1)) { + String dateStr = date.format(formatter); + activeUsers.put(dateStr, 0L); // 示例值,实际应从数据库获取 + } + result.put("activeUsers", activeUsers); + + return result; + } + + @Override + public Map getPostStatistics(String type, String startDate, String endDate) { + Map result = new HashMap<>(); + + // 日期格式化器 + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + + // 默认查询最近7天 + LocalDate end = endDate != null ? LocalDate.parse(endDate, formatter) : LocalDate.now(); + LocalDate start; + + if (startDate != null) { + start = LocalDate.parse(startDate, formatter); + } else { + switch (type) { + case "weekly": + start = end.minusDays(7); + break; + case "monthly": + start = end.minusDays(30); + break; + case "daily": + default: + start = end.minusDays(7); + break; + } + } + + // 帖子发布统计 + Map publications = new LinkedHashMap<>(); + for (LocalDate date = start; !date.isAfter(end); date = date.plusDays(1)) { + String dateStr = date.format(formatter); + LocalDateTime dayStart = date.atStartOfDay(); + LocalDateTime dayEnd = date.plusDays(1).atStartOfDay(); + + Long count = postMapper.selectCount( + new LambdaQueryWrapper() + .ge(Post::getCreateTime, dayStart) + .lt(Post::getCreateTime, dayEnd) + ); + publications.put(dateStr, count); + } + result.put("publications", publications); + + // 评论统计 + Map comments = new LinkedHashMap<>(); + for (LocalDate date = start; !date.isAfter(end); date = date.plusDays(1)) { + String dateStr = date.format(formatter); + LocalDateTime dayStart = date.atStartOfDay(); + LocalDateTime dayEnd = date.plusDays(1).atStartOfDay(); + + Long count = commentMapper.selectCount( + new LambdaQueryWrapper() + .ge(Comment::getCreateTime, dayStart) + .lt(Comment::getCreateTime, dayEnd) + ); + comments.put(dateStr, count); + } + result.put("comments", comments); + + // 点赞统计(实际项目中应该从点赞表查询) + Map likes = new LinkedHashMap<>(); + for (LocalDate date = start; !date.isAfter(end); date = date.plusDays(1)) { + String dateStr = date.format(formatter); + likes.put(dateStr, 0L); // 示例值,实际应从数据库获取 + } + result.put("likes", likes); + + return result; + } +} \ No newline at end of file diff --git a/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/user/controller/UserInfoController.java b/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/user/controller/UserInfoController.java index 7359c8c..486e7c7 100644 --- a/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/user/controller/UserInfoController.java +++ b/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/user/controller/UserInfoController.java @@ -3,6 +3,7 @@ package com.luojia_channel.modules.user.controller; import com.luojia_channel.common.domain.Result; import com.luojia_channel.modules.file.dto.UploadFileDTO; import com.luojia_channel.modules.user.dto.UserChangeInfoDTO; +import com.luojia_channel.modules.user.dto.UserInfoDTO; import com.luojia_channel.modules.user.service.UserInfoService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; @@ -18,6 +19,21 @@ import org.springframework.web.multipart.MultipartFile; @Tag(name = "用户信息管理", description = "用户修改个人信息相关接口") public class UserInfoController { private final UserInfoService userInfoService; + + @GetMapping("/getuserinfo") + @Operation( + summary="获取用户信息", + description="获取指定用户的信息,如果不指定userId则获取当前登录用户信息", + tags = {"用户信息管理"} + ) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "获取成功"), + @ApiResponse(responseCode = "500", description = "获取失败,用户不存在或未登录") + }) + public Result getUserInfo(@RequestParam(required = false) Long userId) { + return Result.success(userInfoService.getUserInfo(userId)); + } + @PostMapping("/update") @Operation( summary="修改用户信息", diff --git a/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/user/dto/UserInfoDTO.java b/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/user/dto/UserInfoDTO.java new file mode 100644 index 0000000..3ea217c --- /dev/null +++ b/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/user/dto/UserInfoDTO.java @@ -0,0 +1,59 @@ +package com.luojia_channel.modules.user.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(description = "用户信息DTO") +public class UserInfoDTO { + @Schema( + description = "用户ID" + ) + private Long id; + + @Schema( + description = "用户名" + ) + private String username; + + @Schema( + description = "手机号" + ) + private String phone; + + @Schema( + description = "邮箱" + ) + private String email; + + @Schema( + description = "头像url" + ) + private String avatar; + + @Schema( + description = "性别(0未知,1男,2女)" + ) + private Integer gender; + + @Schema( + description = "学院" + ) + private String college; + + @Schema( + description = "角色(1普通用户,2管理员,3超级管理员)" + ) + private Integer role; + + @Schema( + description = "状态(1正常,2冻结)" + ) + private Integer status; +} \ No newline at end of file diff --git a/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/user/service/UserInfoService.java b/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/user/service/UserInfoService.java index 4cd7749..735936d 100644 --- a/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/user/service/UserInfoService.java +++ b/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/user/service/UserInfoService.java @@ -3,6 +3,7 @@ package com.luojia_channel.modules.user.service; import com.baomidou.mybatisplus.extension.service.IService; import com.luojia_channel.modules.file.dto.UploadFileDTO; import com.luojia_channel.modules.user.dto.UserChangeInfoDTO; +import com.luojia_channel.modules.user.dto.UserInfoDTO; import com.luojia_channel.modules.user.entity.User; import org.springframework.web.multipart.MultipartFile; @@ -13,4 +14,11 @@ public interface UserInfoService extends IService { void updatePassword(String password); String uploadAvatar(MultipartFile file); + + /** + * 获取用户信息 + * @param userId 用户ID,如果为null则获取当前登录用户信息 + * @return 用户信息DTO + */ + UserInfoDTO getUserInfo(Long userId); } diff --git a/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/user/service/impl/UserInfoServiceImpl.java b/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/user/service/impl/UserInfoServiceImpl.java index b2a6b1a..2f3a2cc 100644 --- a/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/user/service/impl/UserInfoServiceImpl.java +++ b/珞珈岛-项目相关文件/luojia-island/service/src/main/java/com/luojia_channel/modules/user/service/impl/UserInfoServiceImpl.java @@ -10,6 +10,7 @@ import com.luojia_channel.modules.file.service.impl.FileServiceImpl; import com.luojia_channel.modules.file.utils.GeneratePathUtil; import com.luojia_channel.modules.file.utils.ValidateFileUtil; import com.luojia_channel.modules.user.dto.UserChangeInfoDTO; +import com.luojia_channel.modules.user.dto.UserInfoDTO; import com.luojia_channel.modules.user.entity.User; import com.luojia_channel.modules.user.mapper.UserMapper; import com.luojia_channel.modules.user.service.UserInfoService; @@ -65,4 +66,36 @@ public class UserInfoServiceImpl extends ServiceImpl implement public String uploadAvatar(MultipartFile file) { return fileService.uploadFile(file); } + + @Override + public UserInfoDTO getUserInfo(Long userId) { + // 如果userId为null,则获取当前登录用户的ID + if (userId == null) { + userId = UserContext.getUserId(); + if (userId == null) { + throw new UserException("用户未登录"); + } + } + + // 从数据库获取用户信息 + User user = userMapper.selectById(userId); + if (user == null) { + throw new UserException("用户不存在"); + } + + // 转换为DTO对象 + UserInfoDTO userInfoDTO = UserInfoDTO.builder() + .id(user.getId()) + .username(user.getUsername()) + .phone(user.getPhone()) + .email(user.getEmail()) + .avatar(user.getAvatar()) + .gender(user.getGender()) + .college(user.getCollege()) + .role(user.getRole()) + .status(user.getStatus()) + .build(); + + return userInfoDTO; + } } diff --git a/珞珈岛-项目相关文件/luojia-island/service/src/main/resources/application-local.yaml b/珞珈岛-项目相关文件/luojia-island/service/src/main/resources/application-local.yaml index ae193d0..70a6636 100644 --- a/珞珈岛-项目相关文件/luojia-island/service/src/main/resources/application-local.yaml +++ b/珞珈岛-项目相关文件/luojia-island/service/src/main/resources/application-local.yaml @@ -1,36 +1,36 @@ ##本地开发环境 -# lj: -# db: -# host: localhost -# password: lzt&264610 -# redis: -# host: localhost -# port: 6379 -# password: 123456 -# rabbitmq: -# host: localhost -# port: 5672 -# username: guest -# password: guest -# minio: -# endpoint: http://localhost:9000 -# accessKey: minioadmin -# secretKey: minioadmin + lj: + db: + host: localhost + password: 123456 + redis: + host: localhost + port: 6379 + password: 123456 + rabbitmq: + host: localhost + port: 5672 + username: root + password: 123456 + minio: + endpoint: http://localhost:9000 + accessKey: minioadmin + secretKey: minioadmin -lj: - db: - host: 192.168.125.128 - password: MySQL@5678 - redis: - host: 192.168.125.128 - port: 6379 - password: Redis@9012 - rabbitmq: - host: 192.168.125.128 - port: 5672 - username: rabbit_admin - password: Rabbit@3456 - minio: - endpoint: http://192.168.125.128:9000 - accessKey: minio_admin - secretKey: Minio@1234 +#lj: +# db: +# host: 192.168.125.128 +# password: MySQL@5678 +# redis: +# host: 192.168.125.128 +# port: 6379 +# password: Redis@9012 +# rabbitmq: +# host: 192.168.125.128 +# port: 5672 +# username: rabbit_admin +# password: Rabbit@3456 +# minio: +# endpoint: http://192.168.125.128:9000 +# accessKey: minio_admin +# secretKey: Minio@1234 diff --git a/珞珈岛-项目相关文件/luojia-island/service/src/main/resources/application.yaml b/珞珈岛-项目相关文件/luojia-island/service/src/main/resources/application.yaml index db26a0f..7cbd4aa 100644 --- a/珞珈岛-项目相关文件/luojia-island/service/src/main/resources/application.yaml +++ b/珞珈岛-项目相关文件/luojia-island/service/src/main/resources/application.yaml @@ -8,8 +8,11 @@ springdoc: disable-swagger-default-url: true tags-sorter: alpha operations-sorter: alpha - packages-to-scan: com.luojia_channel.modules - paths-to-match: /user/**, /post/**, /comment/**, /message/**, /follow/**, /file/** + enabled: true + default-produces-media-type: application/json + default-consumes-media-type: application/json + packagesToScan: com.luojia_channel.modules + paths-to-match: /api/**,/admin/** spring: application: name: service @@ -62,8 +65,5 @@ mybatis-plus: mapper-locations: classpath*:mapper/**/*.xml type-aliases-package: com.luojia.luojia_channel.modules.*.entity -management: - health: - elasticsearch: - enabled: false + diff --git a/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/components/Header.vue b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/components/Header.vue index 6b9971f..2dfd8d3 100644 --- a/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/components/Header.vue +++ b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/components/Header.vue @@ -31,23 +31,23 @@ - -
-

你的帖子

+

{{ isCurrentUser ? '我的帖子' : `${userInfo.username}的帖子` }}

+
+ 暂无帖子 +
-

{{ post.title }}

+
+

{{ post.title }}

+ {{ formatDate(post.createTime) }} +

{{ post.summary }}

- 热度 {{ post.likes }} - 评论 {{ post.comments }} - 赞 {{ post.favorites }} + {{ post.viewCount || 0 }} + {{ post.likeCount || 0 }} + {{ post.commentCount || 0 }}
+ + +
加载中...
+
加载更多
+
没有更多了
-

{{ userInfo.userName }} 个人信息

+

{{ userInfo.username }} 的统计数据

- 发帖数 - {{ userStats.postCount }} +
{{ userStats.postCount || 0 }}
+
发帖数
- 粉丝 - {{ userStats.followers }} +
{{ userStats.followers || 0 }}
+
粉丝
- 你关注的人数 - {{ userStats.following }} +
{{ userStats.following || 0 }}
+
关注
- 获赞数 - {{ userStats.likes }} +
{{ userStats.likes || 0 }}
+
获赞
+
+
+
+ + +
+

推荐关注

+
+
+ 用户头像 +
+
{{ user.username }}
+
{{ user.followers }}位粉丝
+
-
- - -
加载中...
-
{{ error }}
-
- -
- {{ post.title }}
\ No newline at end of file diff --git a/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/views/admin/AdminCategories.vue b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/views/admin/AdminCategories.vue new file mode 100644 index 0000000..3f6665d --- /dev/null +++ b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/views/admin/AdminCategories.vue @@ -0,0 +1,373 @@ + + + + + \ No newline at end of file diff --git a/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/views/admin/AdminComments.vue b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/views/admin/AdminComments.vue new file mode 100644 index 0000000..58bf906 --- /dev/null +++ b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/views/admin/AdminComments.vue @@ -0,0 +1,285 @@ + + + + + \ No newline at end of file diff --git a/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/views/admin/AdminDashboard.vue b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/views/admin/AdminDashboard.vue new file mode 100644 index 0000000..8910270 --- /dev/null +++ b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/views/admin/AdminDashboard.vue @@ -0,0 +1,182 @@ + + + + + \ No newline at end of file diff --git a/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/views/admin/AdminOverview.vue b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/views/admin/AdminOverview.vue new file mode 100644 index 0000000..f1e31f2 --- /dev/null +++ b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/views/admin/AdminOverview.vue @@ -0,0 +1,577 @@ + + + + + \ No newline at end of file diff --git a/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/views/admin/AdminPosts.vue b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/views/admin/AdminPosts.vue new file mode 100644 index 0000000..789d03d --- /dev/null +++ b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/views/admin/AdminPosts.vue @@ -0,0 +1,408 @@ + + + + + \ No newline at end of file diff --git a/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/views/admin/AdminUsers.vue b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/views/admin/AdminUsers.vue new file mode 100644 index 0000000..75882db --- /dev/null +++ b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/views/admin/AdminUsers.vue @@ -0,0 +1,373 @@ + + + + + \ No newline at end of file