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 @@ - - 登录/注册 通知 + 管理 反馈站 - {{ userInfo.userName }} + {{ userInfo.username }} 个人中心 - 修改个人信息 + 修改个人信息 + 发布帖子 退出登录 @@ -62,10 +62,11 @@ \ No newline at end of file diff --git a/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/components/Login.vue b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/components/Login.vue index a783cc5..04a03ff 100644 --- a/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/components/Login.vue +++ b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/components/Login.vue @@ -216,8 +216,7 @@ async function login() { userStore.login({ avatar:require ('@/assets/default-avatar/boy_1.png'), - username: loginForm.value.userFlag, // 使用用户标识作为用户名 - password: loginForm.value.password, + userName: '珈人一号', userid:1 }); diff --git a/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/router/index.js b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/router/index.js index 3c1e8df..f20a21a 100644 --- a/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/router/index.js +++ b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/router/index.js @@ -7,6 +7,7 @@ import UserPage from '@/views/UserPage.vue'; import NotificationList from '@/views/NotificationList.vue'; import ChangeInformation from '@/views/ChangeInformation.vue'; import FeedBack from '@/views/FeedBack.vue'; +import PostPublish from '@/views/PostPublish.vue'; const routes = [ { @@ -45,7 +46,7 @@ const routes = [ component: () => import('@/views/NotificationDetail.vue'), props: true }, - {//通知页面 + {//反馈页面 path: '/feedback', name: 'FeedBack', component: FeedBack @@ -55,6 +56,46 @@ const routes = [ path:'/changeinformation', name:'ChangeInformation', component:ChangeInformation + }, + { + // 发布帖子页面 + path: '/postpublish', + name: 'PostPublish', + component: PostPublish + }, + { + // 管理员页面 + path: '/admin', + name: 'Admin', + component: () => import('@/views/admin/AdminDashboard.vue'), + children: [ + { + path: '', + name: 'AdminOverview', + component: () => import('@/views/admin/AdminOverview.vue') + }, + { + path: 'posts', + name: 'AdminPosts', + component: () => import('@/views/admin/AdminPosts.vue') + }, + { + path: 'users', + name: 'AdminUsers', + component: () => import('@/views/admin/AdminUsers.vue') + }, + { + path: 'comments', + name: 'AdminComments', + component: () => import('@/views/admin/AdminComments.vue') + }, + { + path: 'categories', + name: 'AdminCategories', + component: () => import('@/views/admin/AdminCategories.vue') + } + ], + meta: { requiresAdmin: true } } ]; diff --git a/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/stores/postlist.js b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/stores/postlist.js index a7a4958..5c42b73 100644 --- a/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/stores/postlist.js +++ b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/stores/postlist.js @@ -1,5 +1,4 @@ import {defineStore} from 'pinia'; -//import axios from 'axios'; import request from '@/utils/request'; import { ElMessage } from 'element-plus'; @@ -47,17 +46,17 @@ export const usePostListStore = defineStore('postList', { const res = await request.post('/post/list', requestData); if (res.code === 200) { const { records, lastVal: newLastVal, offset: newOffset, size: newSize } = res.data; - if (records.length > 0) { + if (records && records.length > 0) { // 字段映射 const mappedRecords = records.map(post => ({ id: post.id, image: post.image, - avatar: post.userAvatar , + avatar: post.userAvatar || require('@/assets/default-avatar/boy_1.png'), title: post.title, summary: post.content ? post.content.slice(0, 40) + (post.content.length > 40 ? '...' : '') : '', - likes: post.likeCount, - comments: post.commentCount, - favorites: post.favoriteCount, + likes: post.likeCount || 0, + comments: post.commentCount || 0, + favorites: post.favoriteCount || 0, category: post.category || '全部', createTime: post.createTime, userName: post.userName, @@ -67,23 +66,25 @@ export const usePostListStore = defineStore('postList', { this.offset = newOffset; this.pageSize = newSize; } - if (records.length < this.pageSize) { + if (!records || records.length < this.pageSize) { this.finished = true; // 没有更多数据 } - } - else { - // 登录失败 + } else { + console.error('获取帖子列表返回错误:', res.msg); ElMessage({ - message: '获取帖子列表失败,请稍后重试', + message: res.msg || '获取帖子列表失败,请稍后重试', type: 'error', - duration: 500 + duration: 1500 }); } - }catch (error) { + } catch (error) { console.error("获取帖子列表失败:", error); - console.error('获取失败', error); - alert(error.response?.message || '获取失败,请稍后重试'); - }finally { + ElMessage({ + message: error.response?.data?.msg || '获取帖子列表失败,请稍后重试', + type: 'error', + duration: 1500 + }); + } finally { this.loading = false; } }, diff --git a/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/stores/user.js b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/stores/user.js index 8a624d1..7f7b642 100644 --- a/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/stores/user.js +++ b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/stores/user.js @@ -4,26 +4,36 @@ export const useUserStore = defineStore('user', { state: () => ({ isLoggedIn: false, // 登录状态 userInfo: { - avatar: '', // 用户头像 URL - username: '', // 用户名 userid: 0, // 用户 ID - moto:'',// 用户简介 - phone: '', // 用户手机号 + username: '', // 用户名 + avatar: '', // 用户头像 email: '', // 用户邮箱 - studentID: '', // 学号 + phone: '', // 用户手机号 + studentId: '', // 学号 college: '', // 学院 - gender: 0, // 性别 0: 未知, 1: 男, 2: 女 - password: '' + gender: 0, // 性别,0-未知,1-男,2-女 }, }), actions: { login(userData) { this.isLoggedIn = true; - this.userInfo = userData; + this.userInfo = { + ...userData, + }; }, logout() { this.isLoggedIn = false; - this.userInfo = { avatar: '', username: '' , userid: 0 }; + this.userInfo = { + userid: 0, + username: '', + avatar: '', + email: '', + phone: '', + studentId: '', + college: '', + gender: 0, + isPublic: true + }; }, }, }); \ No newline at end of file diff --git a/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/stores/userpost.js b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/stores/userpost.js index 9db88e8..7fd5abe 100644 --- a/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/stores/userpost.js +++ b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/stores/userpost.js @@ -1,8 +1,8 @@ import {defineStore} from 'pinia'; -//import axios from 'axios'; import request from '@/utils/request'; +import { ElMessage } from 'element-plus'; -export const usePostListStore = defineStore('postList', { +export const useUserPostStore = defineStore('userPost', { state: () => ({ posts: [], // 帖子列表 total: 0, // 帖子总数 @@ -41,16 +41,16 @@ export const usePostListStore = defineStore('postList', { const res = await request.post('/post/user', { lastVal, offset, size }); if (res.code === 200) { const { records, lastVal: newLastVal, offset: newOffset, size: newSize } = res.data; - if (records.length > 0) { + if (records && records.length > 0) { // 字段映射 const mappedRecords = records.map(post => ({ id: post.id, avatar: post.userAvatar || post.image || require('@/assets/default-avatar/boy_1.png'), title: post.title, summary: post.content ? post.content.slice(0, 40) + (post.content.length > 40 ? '...' : '') : '', - likes: post.likeCount, - comments: post.commentCount, - favorites: post.favoriteCount, + likes: post.likeCount || 0, + comments: post.commentCount || 0, + favorites: post.favoriteCount || 0, category: post.category || '全部', createTime: post.createTime, userName: post.userName, @@ -60,10 +60,24 @@ export const usePostListStore = defineStore('postList', { this.offset = newOffset; this.pageSize = newSize; } - if (records.length < size) { + if (!records || records.length < size) { this.finished = true; // 没有更多数据 } + } else { + console.error('获取用户帖子列表返回错误:', res.msg); + ElMessage({ + message: res.msg || '获取用户帖子列表失败,请稍后重试', + type: 'error', + duration: 1500 + }); } + } catch (error) { + console.error("获取用户帖子列表失败:", error); + ElMessage({ + message: error.response?.data?.msg || '获取用户帖子列表失败,请稍后重试', + type: 'error', + duration: 1500 + }); } finally { this.loading = false; } diff --git a/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/views/PostPublish.vue b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/views/PostPublish.vue index 4b3a73c..22efa73 100644 --- a/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/views/PostPublish.vue +++ b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/views/PostPublish.vue @@ -4,7 +4,7 @@ - + @@ -91,116 +91,138 @@ - \ No newline at end of file diff --git a/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/views/UserPage.vue b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/views/UserPage.vue index 37e7ac6..bc77211 100644 --- a/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/views/UserPage.vue +++ b/珞珈岛-项目相关文件/luojia-island/vue-frontend/src/views/UserPage.vue @@ -6,161 +6,402 @@ - {{ userInfo.username }} - ONLINE - - - 学院: - {{ userInfo.college || '未填写' }} - - - 性别: - - 男 - 女 - 未知 - - - - + {{ userInfo.username }} + + + + + 学院: + {{ userInfo.college || '未设置' }} + + + + 性别: + + 男 + 女 + 未知 + + + + + 电话: + {{ userInfo.phone || '未设置' }} + + + + 邮箱: + {{ userInfo.email || '未设置' }} + + + + 隐私设置: + + + + + + + + + + + {{ isFollowing ? '已关注' : '关注' }} + + 发送消息 + + - 你的帖子 + {{ 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 @@ + + + + 分类管理 + + 添加分类 + + + + + + + + + + + + + + + 无图标 + + + + + + + + + + + + + 编辑 + + + + 删除 + + + + + + + + + + + + + + + + + + + + + + + + + + + + 支持jpg、png格式,建议尺寸100x100px + + + + + 数字越小排序越靠前 + + + + + 取消 + 确认 + + + + + + + + + \ 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 @@ + + + + + + + + + + + + + + + + 搜索 + + + 重置 + + + + + + + + + + + + + + + {{ row.content }} + + + + 回复 @{{ row.replyUsername }} + + + + + + + + + + {{ row.username }} + + + + + + + + {{ row.postTitle }} + + + + + + + + + {{ row.likeCount }} + + + + + + + + 删除 + + + + + + + + + + + + + + + + + \ 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 @@ + + + + + 👥 + + 在线用户 + {{ stats.onlineUsers }} + 当前在线用户数 + + + + + 📝 + + 帖子总数 + {{ stats.totalPosts }} + + 今日新增: + +{{ stats.todayPosts }} + + + + + + 💬 + + 评论总数 + {{ stats.totalComments }} + + 今日新增: + +{{ stats.todayComments }} + + + + + + 👤 + + 用户总数 + {{ stats.totalUsers }} + + 今日注册: + +{{ stats.todayUsers }} + + + + + + + + + 过去7天活跃度 + + + + + + + + {{ day }} + + + + + + + 分类数据统计 + + + + + + 分类名称 + 帖子数量 + 占比 + + + + + {{ category.name }} + {{ category.count }} + + + + {{ category.percentage }}% + + + + + + + + + + + + + 最新帖子 + 查看全部 + + + + + 标题 + 作者 + 分类 + 发布时间 + 操作 + + + + + {{ post.title }} + {{ post.author }} + {{ post.category }} + {{ formatDate(post.createTime) }} + + 查看 + + + + + + + + + 最新用户 + 查看全部 + + + + + 用户名 + 注册时间 + 状态 + 操作 + + + + + {{ user.username }} + {{ formatDate(user.createTime) }} + + + {{ user.status === 1 ? '正常' : '冻结' }} + + + + 查看 + + + + + + + + + + + + \ 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + 搜索 + + + 重置 + + + + + + + + + + + + + + + {{ row.title }} + + + + + + + + + + {{ row.username }} + + + + + + + + + + {{ row.viewCount }} + {{ row.likeCount }} + {{ row.commentCount }} + + + + + + + + + 正常 + 置顶 + 隐藏 + + + + + + + 置顶 + + + 取消置顶 + + + + 隐藏 + + + 显示 + + + + + 删除 + + + + + + + + + + + + + + + + + \ 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 搜索 + + + 重置 + + + + + + + + + + + + + + + + {{ row.username }} + ID: {{ row.id }} + + + + + + + + + {{ row.postCount || 0 }} + {{ row.commentCount || 0 }} + {{ row.followerCount || 0 }} + {{ row.integral || 0 }} + + + + + + + + + 普通用户 + 管理员 + 超级管理员 + + + + + + 正常 + 冻结 + + + + + + + 冻结账号 + + + 解冻账号 + + + handleRoleChange(cmd, row)"> + + 设置角色 + + + + 普通用户 + 管理员 + 超级管理员 + + + + + + + + + + + + + + + + + + \ No newline at end of file
{{ userInfo.userName }}
{{ userInfo.username }}
ONLINE
{{ post.summary }}
{{ row.content }}