This commit is contained in:
2025-09-09 11:13:36 +08:00
parent cf50a9f1fa
commit fcd35c78e5
60 changed files with 2753 additions and 2196 deletions
+4 -14
View File
@@ -80,11 +80,9 @@ type: "always_apply"
43. 异常信息要包含足够的上下文信息
44. 生产环境禁止输出debug级别日志
---
## Java Spring Boot 项目开发与代码质量保障规范(扩展)
适用范围:本规范适用于 logistics-finance 项目所有后端模块(common、gateway、auth、user、order、waybill、vehicle、finance、report、ai、file。若与本文件前文条款或现有项目规范冲突,以更严格者为准。
适用范围:本规范适用于 EmotionMuseum 项目所有后端模块。若与本文件前文条款或现有项目规范冲突,以更严格者为准。
### 一、代码规范完善
@@ -149,9 +147,7 @@ type: "always_apply"
- 事务管理
- 仅在 Service 层声明事务;方法内仅包含数据库操作或与数据库一致性相关的远程调用;跨服务一致性使用可靠消息/补偿方案。
---
## 二、代码质量保障机制
## 代码质量保障机制
- 代码审查流程(Code Review
- 所有变更必须走 PR;至少 1 名同组开发+1 名模块 Owner 审核通过方可合并。
@@ -176,9 +172,7 @@ type: "always_apply"
- 小步快跑、单一职责、先加测试再重构;保持对外行为一致(新增特性使用特性开关/版本控制)。
- 严禁大规模跨模块重构合并在单次 PR;拆分为多个可审查的独立提交。
---
## 三、变更管理流程
## 变更管理流程
- 变更前影响分析
- 维度:接口兼容性(路径/入参/语义)、数据库(表/字段/索引/数据迁移)、配置(Nacos/环境变量)、依赖版本、性能、容量与并发、安全与合规、可回滚性。
@@ -200,9 +194,7 @@ type: "always_apply"
- 紧急修复:创建 hotfix → 修复 → 快速测试 → 合并 master 与 release → 立即发布 → 追补测试与文档。
- 常规开发:feature → PR 审核 → 合并 → 集成测试 → 发布。
---
## 四、持续改进机制
## 持续改进机制
- 规范评审与更新
- 每月一次质量例会,评审新增问题与改进项;规范变更需在本文件留痕(版本/日期/变更点)。
@@ -216,8 +208,6 @@ type: "always_apply"
- 反馈闭环
- 通过代码评审、事后复盘(Postmortem)、问题工单收敛到规范条款;指定责任人与截止时间;下次评审验证落地结果。
---
## 附:标准检查清单(节选)
- PR 自检
@@ -8,9 +8,6 @@ import com.emotion.dto.request.EmotionRecordUpdateRequest;
import com.emotion.dto.response.EmotionRecordResponse;
import com.emotion.service.EmotionRecordService;
import com.emotion.util.CurrentUserUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -18,8 +15,6 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Map;
@@ -30,8 +25,7 @@ import java.util.Map;
* @date 2025-07-22
*/
@RestController
@RequestMapping("/emotion-records")
@Tag(name = "情绪记录管理", description = "用户情绪记录的增删改查功能")
@RequestMapping("/emotionRecord")
public class EmotionRecordController {
private static final Logger log = LoggerFactory.getLogger(EmotionRecordController.class);
@@ -42,8 +36,7 @@ public class EmotionRecordController {
/**
* 创建情绪记录
*/
@PostMapping
@Operation(summary = "创建情绪记录", description = "创建新的情绪记录")
@PostMapping(value = "/create")
public Result<EmotionRecordResponse> createRecord(@RequestBody @Valid EmotionRecordCreateRequest request) {
log.info("创建情绪记录: userId={}", request.getUserId());
@@ -56,51 +49,27 @@ public class EmotionRecordController {
}
/**
* 获取用户情绪记录列表
* 分页查询情绪记录
*/
@Operation(summary = "获取用户情绪记录列表", description = "分页获取当前用户的情绪记录,按创建时间倒序")
@GetMapping("/user")
public Result<PageResult<EmotionRecordResponse>> getRecordList(
@Validated EmotionRecordPageRequest request) {
@GetMapping(value = "/page")
public Result<PageResult<EmotionRecordResponse>> getPage(@Validated EmotionRecordPageRequest request) {
// 从上下文中获取当前用户ID
String userId = CurrentUserUtil.requireCurrentUserId();
log.info("获取用户情绪记录列表: userId={}, current={}, size={}", userId, request.getCurrent(), request.getSize());
log.info("分页查询情绪记录: userId={}, current={}, size={}", userId, request.getCurrent(), request.getSize());
PageResult<EmotionRecordResponse> page = emotionRecordService.getPageByUserIdWithResponse(userId, request);
log.info("获取用户情绪记录成功: userId={}, total={}, records={}",
userId, page.getTotal(), page.getRecords().size());
log.info("分页查询情绪记录成功: userId={}, total={}, records={}",
userId, page.getTotal(), page.getRecords().size());
return Result.success(page);
}
/**
* 获取用户最近情绪记录
*/
@Operation(summary = "获取用户最近情绪记录", description = "获取当前用户最近的情绪记录列表")
@GetMapping("/user/recent")
public Result<List<EmotionRecordResponse>> getRecentRecords(
@Parameter(description = "限制数量") @RequestParam(defaultValue = "5") Integer limit) {
// 从上下文中获取当前用户ID
String userId = CurrentUserUtil.requireCurrentUserId();
log.info("获取用户最近情绪记录: userId={}, limit={}", userId, limit);
List<EmotionRecordResponse> records = emotionRecordService.getRecentByUserIdWithResponse(userId, limit);
log.info("获取用户最近情绪记录成功: userId={}, records={}", userId, records.size());
return Result.success(records);
}
/**
* 获取情绪记录详情
*/
@Operation(summary = "获取情绪记录详情", description = "根据ID获取情绪记录详情")
@GetMapping
@GetMapping(value = "/detail")
public Result<EmotionRecordResponse> getRecord(@RequestParam String id) {
log.info("获取情绪记录详情: {}", id);
@@ -114,8 +83,7 @@ public class EmotionRecordController {
/**
* 更新情绪记录
*/
@Operation(summary = "更新情绪记录", description = "更新指定的情绪记录")
@PutMapping
@PutMapping(value = "/update")
public Result<EmotionRecordResponse> updateRecord(@RequestBody @Valid EmotionRecordUpdateRequest request) {
log.info("更新情绪记录: {}", request.getId());
@@ -129,8 +97,7 @@ public class EmotionRecordController {
/**
* 删除情绪记录
*/
@Operation(summary = "删除情绪记录", description = "删除指定的情绪记录")
@DeleteMapping
@DeleteMapping(value = "/delete")
public Result<String> deleteRecord(@RequestParam String id) {
log.info("删除情绪记录: {}", id);
@@ -144,8 +111,7 @@ public class EmotionRecordController {
/**
* 获取情绪统计
*/
@Operation(summary = "获取情绪统计", description = "获取当前用户的情绪统计信息")
@GetMapping("/stats")
@GetMapping(value = "/stats")
public Result<Map<String, Object>> getEmotionStats(
@RequestParam(required = false) String startDate,
@RequestParam(required = false) String endDate) {
@@ -1,16 +1,20 @@
package com.emotion.controller;
import com.emotion.common.Result;
import com.emotion.dto.request.EmotionSummaryGenerateRequest;
import com.emotion.dto.request.EmotionSummaryStatusRequest;
import com.emotion.dto.response.EmotionSummaryGenerateResponse;
import com.emotion.dto.response.EmotionSummaryStatusResponse;
import com.emotion.service.AiChatService;
import com.emotion.util.CurrentUserUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.scheduling.annotation.Async;
import java.util.concurrent.CompletableFuture;
import java.util.Map;
import javax.validation.Valid;
/**
* 情绪总结控制器
@@ -20,64 +24,49 @@ import java.util.Map;
*/
@Slf4j
@RestController
@RequestMapping("/emotion-summary")
@RequestMapping("/emotionSummary")
@Tag(name = "情绪总结管理", description = "用户情绪记录总结和分析功能")
public class EmotionSummaryController {
@Autowired
private AiChatService aiChatService;
/**
* 生成用户当天的情绪记录总结
*/
@Operation(summary = "生成用户当天的情绪记录总结", description = "基于用户当天的聊天记录生成情绪分析和记录")
@PostMapping("/generate")
public Result<Map<String, Object>> generateEmotionSummary() {
try {
String userId = CurrentUserUtil.requireCurrentUserId();
log.info("收到生成情绪记录总结请求: userId={}", userId);
// 调用AI服务异步生成情绪总结(阻塞获取结果)
Map<String, Object> result = aiChatService.generateEmotionSummaryAsync(userId).get();
if ((Boolean) result.get("success")) {
log.info("情绪记录总结生成成功: userId={}", userId);
return Result.success("情绪记录总结生成成功", result);
} else {
String message = (String) result.get("message");
log.warn("情绪记录总结生成失败: userId={}, message={}", userId, message);
return Result.error(message);
}
} catch (IllegalStateException e) {
log.warn("用户认证失败: {}", e.getMessage());
return Result.error(e.getMessage());
} catch (Exception e) {
log.error("生成情绪记录总结时发生异常", e);
return Result.error("生成情绪记录总结失败: " + e.getMessage());
@PostMapping(value = "/generate")
public Result<EmotionSummaryGenerateResponse> generateEmotionSummary(
@RequestBody @Valid EmotionSummaryGenerateRequest request) {
String userId = CurrentUserUtil.requireCurrentUserId();
log.info("收到生成情绪记录总结请求: userId={}", userId);
// 调用AI服务生成情绪总结
EmotionSummaryGenerateResponse response = aiChatService.generateEmotionSummaryWithResponse(userId);
if (response.getSuccess()) {
log.info("情绪记录总结生成成功: userId={}", userId);
return Result.success("情绪记录总结生成成功", response);
} else {
log.warn("情绪记录总结生成失败: userId={}, message={}", userId, response.getMessage());
return Result.error(response.getMessage());
}
}
/**
* 获取用户情绪记录总结状态
*/
@Operation(summary = "获取用户情绪记录总结状态", description = "检查用户今天是否已经生成过情绪记录")
@GetMapping("/status")
public Result<Map<String, Object>> getEmotionSummaryStatus() {
@GetMapping(value = "/status")
public Result<EmotionSummaryStatusResponse> getEmotionSummaryStatus(
@Validated EmotionSummaryStatusRequest request) {
// 从上下文中获取当前用户ID
String userId = CurrentUserUtil.requireCurrentUserId();
log.info("查询用户情绪记录总结状态: userId={}", userId);
try {
// 从上下文中获取当前用户ID
String userId = CurrentUserUtil.requireCurrentUserId();
// 调用AI服务获取状态信息
EmotionSummaryStatusResponse response = aiChatService.getEmotionSummaryStatusWithResponse(userId);
log.info("查询用户情绪记录总结状态: userId={}", userId);
// 这里可以添加检查用户今天是否已经生成过情绪记录的逻辑
// 暂时返回基本状态信息
Map<String, Object> status = Map.of(
"userId", userId,
"canGenerate", true,
"message", "可以生成情绪记录总结"
);
return Result.success(status);
} catch (IllegalStateException e) {
log.warn("用户认证失败: {}", e.getMessage());
return Result.error(e.getMessage());
} catch (Exception e) {
log.error("查询情绪记录总结状态时发生异常", e);
return Result.error("查询状态失败: " + e.getMessage());
}
return Result.success(response);
}
}
}
@@ -1,19 +1,26 @@
package com.emotion.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.emotion.common.PageResult;
import com.emotion.common.Result;
import com.emotion.dto.request.PageRequest;
import com.emotion.entity.GrowthTopic;
import com.emotion.dto.request.growth.GrowthTopicCreateRequest;
import com.emotion.dto.request.growth.GrowthTopicPageRequest;
import com.emotion.dto.request.growth.GrowthTopicUpdateRequest;
import com.emotion.dto.response.growth.GrowthTopicResponse;
import com.emotion.service.GrowthTopicService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.List;
import javax.validation.Valid;
/**
* 成长话题控制器
*
* @author emotion-museum
* @date 2025-09-08
*/
@RestController
@RequestMapping("/growth-topic")
@RequestMapping("/growthTopic")
public class GrowthTopicController {
@Autowired
@@ -22,49 +29,54 @@ public class GrowthTopicController {
/**
* 分页查询成长话题
*/
@GetMapping("/page")
public Result<IPage<GrowthTopic>> getPage(@Validated PageRequest request) {
IPage<GrowthTopic> page = growthTopicService.getPage(request);
return Result.success(page);
@GetMapping(value = "/page")
public Result<PageResult<GrowthTopicResponse>> getPage(@Validated GrowthTopicPageRequest request) {
PageResult<GrowthTopicResponse> pageResult = growthTopicService.getPageWithResponse(request);
return Result.success(pageResult);
}
/**
* 根据ID获取成长话题
*/
@GetMapping(value = "/detail")
public Result<GrowthTopicResponse> getById(@RequestParam String id) {
GrowthTopicResponse response = growthTopicService.getGrowthTopicResponseById(id);
if (response == null) {
return Result.notFound("成长话题不存在");
}
return Result.success(response);
}
/**
* 创建成长话题
*/
@PostMapping("/create")
public Result<GrowthTopic> createGrowthTopic(@RequestBody @Validated GrowthTopicCreateRequest request) {
GrowthTopic topic = growthTopicService.createGrowthTopic(
request.getTitle(),
request.getDescription(),
request.getCategory(),
request.getDifficultyLevel(),
request.getTags(),
request.getEndTime()
);
return Result.success(topic);
@PostMapping(value = "/create")
public Result<GrowthTopicResponse> create(@Valid @RequestBody GrowthTopicCreateRequest request) {
GrowthTopicResponse response = growthTopicService.createGrowthTopicWithResponse(request);
return Result.success(response);
}
// 可根据GrowthTopicService接口继续补充其他接口...
public static class GrowthTopicCreateRequest {
private String title;
private String description;
private String category;
private String difficultyLevel;
private String tags;
private LocalDateTime endTime;
// getter/setter
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public String getCategory() { return category; }
public void setCategory(String category) { this.category = category; }
public String getDifficultyLevel() { return difficultyLevel; }
public void setDifficultyLevel(String difficultyLevel) { this.difficultyLevel = difficultyLevel; }
public String getTags() { return tags; }
public void setTags(String tags) { this.tags = tags; }
public LocalDateTime getEndTime() { return endTime; }
public void setEndTime(LocalDateTime endTime) { this.endTime = endTime; }
/**
* 更新成长话题
*/
@PutMapping(value = "/update")
public Result<GrowthTopicResponse> update(@Valid @RequestBody GrowthTopicUpdateRequest request) {
GrowthTopicResponse response = growthTopicService.updateGrowthTopicWithResponse(request);
if (response == null) {
return Result.notFound("成长话题不存在");
}
return Result.success(response);
}
}
/**
* 删除成长话题
*/
@DeleteMapping(value = "/delete")
public Result<Void> delete(@RequestParam String id) {
boolean deleted = growthTopicService.deleteGrowthTopic(id);
if (!deleted) {
return Result.error("删除失败");
}
return Result.success();
}
}
@@ -1,19 +1,26 @@
package com.emotion.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.emotion.common.PageResult;
import com.emotion.common.Result;
import com.emotion.dto.request.PageRequest;
import com.emotion.entity.GuestUser;
import com.emotion.dto.request.guest.GuestUserCreateRequest;
import com.emotion.dto.request.guest.GuestUserPageRequest;
import com.emotion.dto.request.guest.GuestUserUpdateRequest;
import com.emotion.dto.response.guest.GuestUserResponse;
import com.emotion.service.GuestUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.List;
import javax.validation.Valid;
/**
* 访客用户控制器
*
* @author emotion-museum
* @date 2025-09-08
*/
@RestController
@RequestMapping("/guest-user")
@RequestMapping("/guestUser")
public class GuestUserController {
@Autowired
@@ -22,64 +29,54 @@ public class GuestUserController {
/**
* 分页查询访客用户
*/
@GetMapping("/page")
public Result<IPage<GuestUser>> getPage(@Validated PageRequest request) {
IPage<GuestUser> page = guestUserService.getPage(request);
return Result.success(page);
@GetMapping(value = "/page")
public Result<PageResult<GuestUserResponse>> getPage(@Validated GuestUserPageRequest request) {
PageResult<GuestUserResponse> pageResult = guestUserService.getPageWithResponse(request);
return Result.success(pageResult);
}
/**
* 根据ID获取访客用户
*/
@GetMapping(value = "/detail")
public Result<GuestUserResponse> getById(@RequestParam String id) {
GuestUserResponse response = guestUserService.getGuestUserResponseById(id);
if (response == null) {
return Result.notFound("访客用户不存在");
}
return Result.success(response);
}
/**
* 创建访客用户
*/
@PostMapping("/create")
public Result<GuestUser> createGuestUser(@RequestBody @Validated GuestUserCreateRequest request) {
GuestUser guestUser = guestUserService.createGuestUser(
request.getDeviceId(),
request.getIpAddress(),
request.getUserAgent(),
request.getLocation());
return Result.success(guestUser);
@PostMapping(value = "/create")
public Result<GuestUserResponse> create(@Valid @RequestBody GuestUserCreateRequest request) {
GuestUserResponse response = guestUserService.createGuestUserWithResponse(request);
return Result.success(response);
}
// 可根据GuestUserService接口继续补充其他接口...
public static class GuestUserCreateRequest {
private String deviceId;
private String ipAddress;
private String userAgent;
private String location;
// getter/setter
public String getDeviceId() {
return deviceId;
/**
* 更新访客用户
*/
@PutMapping(value = "/update")
public Result<GuestUserResponse> update(@Valid @RequestBody GuestUserUpdateRequest request) {
GuestUserResponse response = guestUserService.updateGuestUserWithResponse(request);
if (response == null) {
return Result.notFound("访客用户不存在");
}
return Result.success(response);
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public String getIpAddress() {
return ipAddress;
}
public void setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
}
public String getUserAgent() {
return userAgent;
}
public void setUserAgent(String userAgent) {
this.userAgent = userAgent;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
/**
* 删除访客用户
*/
@DeleteMapping(value = "/delete")
public Result<Void> delete(@RequestParam String id) {
boolean deleted = guestUserService.deleteGuestUser(id);
if (!deleted) {
return Result.error("删除失败");
}
return Result.success();
}
}
@@ -10,16 +10,16 @@ import com.emotion.dto.response.MessageResponse;
import com.emotion.service.MessageService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
/**
* 消息控制器
*
* @author emotion-museum
* @date 2025-07-23
* @date 2025-09-08
*/
@RestController
@RequestMapping("/message")
@@ -32,104 +32,72 @@ public class MessageController {
/**
* 创建消息
*/
@PostMapping
@PostMapping(value = "/create")
public Result<MessageResponse> create(@Valid @RequestBody MessageCreateRequest request) {
log.info("创建消息: conversationId={}", request.getConversationId());
try {
MessageResponse response = messageService.createMessageFromRequest(request);
log.info("创建消息成功: messageId={}", response.getId());
return Result.success(response);
} catch (IllegalStateException e) {
log.error("用户未认证: {}", e.getMessage());
return Result.error(401, "用户未登录或认证失败");
} catch (Exception e) {
log.error("创建消息失败", e);
return Result.error(500, "创建消息失败,请稍后重试");
}
MessageResponse response = messageService.createMessageFromRequest(request);
return Result.success(response);
}
/**
* 根据ID获取消息
*/
@GetMapping("/{id}")
public Result<MessageResponse> getById(@PathVariable String id) {
log.info("获取消息详情: id={}", id);
try {
MessageResponse response = messageService.getMessageById(id);
if (response == null) {
return Result.error(404, "消息不存在");
}
return Result.success(response);
} catch (Exception e) {
log.error("获取消息详情失败", e);
return Result.error(500, "获取消息详情失败,请稍后重试");
@GetMapping(value = "/detail")
public Result<MessageResponse> getById(@RequestParam String id) {
MessageResponse response = messageService.getMessageById(id);
if (response == null) {
return Result.notFound("消息不存在");
}
return Result.success(response);
}
/**
* 根据用户ID分页查询消息
* 分页查询消息
*/
@GetMapping("/user/page")
public Result<PageResult<MessageResponse>> getPageByUserId(
@RequestParam(defaultValue = "1") Long current,
@RequestParam(defaultValue = "20") Long size) {
log.info("获取用户消息分页: current={}, size={}", current, size);
// 构建请求对象
MessagePageRequest request = new MessagePageRequest();
request.setCurrent(current);
request.setSize(size);
PageResult<MessageResponse> pageResult = messageService.getUserMessagesWithPage(request);
log.info("获取用户消息分页成功: total={}", pageResult.getTotal());
@GetMapping(value = "/page")
public Result<PageResult<MessageResponse>> getPage(@Validated MessagePageRequest request) {
PageResult<MessageResponse> pageResult = messageService.getPageWithResponse(request);
return Result.success(pageResult);
}
/**
* 根据用户ID和关键词搜索消息
* 搜索消息
*/
@PostMapping("/user/search")
public Result<List<MessageResponse>> searchByUserId(@Valid @RequestBody MessageSearchRequest request) {
log.info("搜索用户消息: keyword={}, limit={}", request.getKeyword(), request.getLimit());
try {
List<MessageResponse> responses = messageService.searchUserMessages(request);
log.info("搜索用户消息成功: {} 条消息", responses.size());
return Result.success(responses);
} catch (IllegalStateException e) {
log.error("用户未认证: {}", e.getMessage());
return Result.error(401, "用户未登录或认证失败");
} catch (Exception e) {
log.error("搜索用户消息失败", e);
return Result.error(500, "搜索失败,请稍后重试");
}
@PostMapping(value = "/search")
public Result<PageResult<MessageResponse>> search(@Valid @RequestBody MessageSearchRequest request) {
PageResult<MessageResponse> pageResult = messageService.searchWithResponse(request);
return Result.success(pageResult);
}
/**
* 获取用户最近的聊天记录
* 获取最近的消息
*/
@PostMapping("/user/recent")
public Result<List<MessageResponse>> getRecentMessages(@Valid @RequestBody MessageRecentRequest request) {
log.info("获取用户最近消息: limit={}", request.getLimit());
try {
List<MessageResponse> responses = messageService.getUserRecentMessages(request);
log.info("获取用户最近消息成功: {} 条消息", responses.size());
return Result.success(responses);
} catch (IllegalStateException e) {
log.error("用户未认证: {}", e.getMessage());
return Result.error(401, "用户未登录或认证失败");
} catch (Exception e) {
log.error("获取最近消息失败", e);
return Result.error(500, "获取最近消息失败,请稍后重试");
}
@PostMapping(value = "/recent")
public Result<PageResult<MessageResponse>> getRecentMessages(@Valid @RequestBody MessageRecentRequest request) {
PageResult<MessageResponse> pageResult = messageService.getRecentWithResponse(request);
return Result.success(pageResult);
}
/**
* 更新消息
*/
@PutMapping(value = "/update")
public Result<MessageResponse> update(@RequestParam String id, @RequestParam String content) {
MessageResponse response = messageService.updateMessage(id, content);
if (response == null) {
return Result.notFound("消息不存在");
}
return Result.success(response);
}
/**
* 删除消息
*/
@DeleteMapping(value = "/delete")
public Result<Void> delete(@RequestParam String id) {
boolean deleted = messageService.deleteMessage(id);
if (!deleted) {
return Result.error("删除失败");
}
return Result.success();
}
}
@@ -1,20 +1,24 @@
package com.emotion.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.emotion.common.PageResult;
import com.emotion.common.Result;
import com.emotion.dto.request.PageRequest;
import com.emotion.dto.request.IdRequest;
import com.emotion.dto.response.BaseResponse;
import com.emotion.entity.Reward;
import com.emotion.dto.request.reward.RewardCreateRequest;
import com.emotion.dto.request.reward.RewardPageRequest;
import com.emotion.dto.request.reward.RewardUpdateRequest;
import com.emotion.dto.response.reward.RewardResponse;
import com.emotion.service.RewardService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
import javax.validation.Valid;
/**
* 奖励控制器
*
* @author emotion-museum
* @date 2025-09-08
*/
@RestController
@RequestMapping("/reward")
public class RewardController {
@@ -25,67 +29,54 @@ public class RewardController {
/**
* 分页查询奖励
*/
@GetMapping("/page")
public Result<IPage<Reward>> getPage(@Validated PageRequest request) {
IPage<Reward> page = rewardService.getPage(request);
return Result.success(page);
@GetMapping(value = "/page")
public Result<PageResult<RewardResponse>> getPage(@Validated RewardPageRequest request) {
PageResult<RewardResponse> pageResult = rewardService.getPageWithResponse(request);
return Result.success(pageResult);
}
/**
* 根据用户ID分页查询奖励
* 根据ID获取奖励
*/
@GetMapping("/page/user/{userId}")
public Result<IPage<Reward>> getPageByUserId(@Validated PageRequest request, @PathVariable String userId) {
IPage<Reward> page = rewardService.getPageByUserId(request, userId);
return Result.success(page);
}
/**
* 根据用户ID查询奖励
*/
@GetMapping("/user/{userId}")
public Result<List<Reward>> getByUserId(@PathVariable String userId) {
List<Reward> list = rewardService.getByUserId(userId);
return Result.success(list);
@GetMapping(value = "/detail")
public Result<RewardResponse> getById(@RequestParam String id) {
RewardResponse response = rewardService.getRewardResponseById(id);
if (response == null) {
return Result.notFound("奖励不存在");
}
return Result.success(response);
}
/**
* 创建奖励
*/
@PostMapping("/create")
public Result<Reward> createReward(@RequestBody @Validated RewardCreateRequest request) {
Reward reward = rewardService.createReward(
request.getUserId(),
request.getRewardType(),
request.getPoints(),
request.getSource(),
request.getDescription(),
request.getExpiredTime()
);
return Result.success(reward);
@PostMapping(value = "/create")
public Result<RewardResponse> create(@Valid @RequestBody RewardCreateRequest request) {
RewardResponse response = rewardService.createRewardWithResponse(request);
return Result.success(response);
}
// 可根据RewardService接口继续补充其他接口...
public static class RewardCreateRequest {
private String userId;
private String rewardType;
private Integer points;
private String source;
private String description;
private LocalDateTime expiredTime;
// getter/setter
public String getUserId() { return userId; }
public void setUserId(String userId) { this.userId = userId; }
public String getRewardType() { return rewardType; }
public void setRewardType(String rewardType) { this.rewardType = rewardType; }
public Integer getPoints() { return points; }
public void setPoints(Integer points) { this.points = points; }
public String getSource() { return source; }
public void setSource(String source) { this.source = source; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public LocalDateTime getExpiredTime() { return expiredTime; }
public void setExpiredTime(LocalDateTime expiredTime) { this.expiredTime = expiredTime; }
/**
* 更新奖励
*/
@PutMapping(value = "/update")
public Result<RewardResponse> update(@Valid @RequestBody RewardUpdateRequest request) {
RewardResponse response = rewardService.updateRewardWithResponse(request);
if (response == null) {
return Result.notFound("奖励不存在");
}
return Result.success(response);
}
}
/**
* 删除奖励
*/
@DeleteMapping(value = "/delete")
public Result<Void> delete(@RequestParam String id) {
boolean deleted = rewardService.deleteReward(id);
if (!deleted) {
return Result.error("删除失败");
}
return Result.success();
}
}
@@ -1,18 +1,26 @@
package com.emotion.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.emotion.common.PageResult;
import com.emotion.common.Result;
import com.emotion.dto.request.PageRequest;
import com.emotion.entity.TopicInteraction;
import com.emotion.dto.request.TopicInteractionCreateRequest;
import com.emotion.dto.request.TopicInteractionPageRequest;
import com.emotion.dto.request.TopicInteractionUpdateRequest;
import com.emotion.dto.response.TopicInteractionResponse;
import com.emotion.service.TopicInteractionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import javax.validation.Valid;
/**
* 话题互动控制器
*
* @author emotion-museum
* @date 2025-09-08
*/
@RestController
@RequestMapping("/topic-interaction")
@RequestMapping("/topicInteraction")
public class TopicInteractionController {
@Autowired
@@ -21,45 +29,54 @@ public class TopicInteractionController {
/**
* 分页查询话题互动
*/
@GetMapping("/page")
public Result<IPage<TopicInteraction>> getPage(@Validated PageRequest request) {
IPage<TopicInteraction> page = topicInteractionService.getPage(request);
return Result.success(page);
@GetMapping(value = "/page")
public Result<PageResult<TopicInteractionResponse>> getPage(@Validated TopicInteractionPageRequest request) {
PageResult<TopicInteractionResponse> pageResult = topicInteractionService.getPageWithResponse(request);
return Result.success(pageResult);
}
/**
* 根据ID获取话题互动
*/
@GetMapping(value = "/detail")
public Result<TopicInteractionResponse> getById(@RequestParam String id) {
TopicInteractionResponse response = topicInteractionService.getTopicInteractionResponseById(id);
if (response == null) {
return Result.notFound("话题互动不存在");
}
return Result.success(response);
}
/**
* 创建话题互动
*/
@PostMapping("/create")
public Result<TopicInteraction> createTopicInteraction(@RequestBody @Validated TopicInteractionCreateRequest request) {
TopicInteraction interaction = topicInteractionService.createTopicInteraction(
request.getTopicId(),
request.getUserId(),
request.getInteractionType(),
request.getContent(),
request.getAttachments()
);
return Result.success(interaction);
@PostMapping(value = "/create")
public Result<TopicInteractionResponse> create(@Valid @RequestBody TopicInteractionCreateRequest request) {
TopicInteractionResponse response = topicInteractionService.createTopicInteractionWithResponse(request);
return Result.success(response);
}
// 可根据TopicInteractionService接口继续补充其他接口...
public static class TopicInteractionCreateRequest {
private String topicId;
private String userId;
private String interactionType;
private String content;
private String attachments;
// getter/setter
public String getTopicId() { return topicId; }
public void setTopicId(String topicId) { this.topicId = topicId; }
public String getUserId() { return userId; }
public void setUserId(String userId) { this.userId = userId; }
public String getInteractionType() { return interactionType; }
public void setInteractionType(String interactionType) { this.interactionType = interactionType; }
public String getContent() { return content; }
public void setContent(String content) { this.content = content; }
public String getAttachments() { return attachments; }
public void setAttachments(String attachments) { this.attachments = attachments; }
/**
* 更新话题互动
*/
@PutMapping(value = "/update")
public Result<TopicInteractionResponse> update(@Valid @RequestBody TopicInteractionUpdateRequest request) {
TopicInteractionResponse response = topicInteractionService.updateTopicInteractionWithResponse(request);
if (response == null) {
return Result.notFound("话题互动不存在");
}
return Result.success(response);
}
}
/**
* 删除话题互动
*/
@DeleteMapping(value = "/delete")
public Result<Void> delete(@RequestParam String id) {
boolean deleted = topicInteractionService.deleteTopicInteraction(id);
if (!deleted) {
return Result.error("删除失败");
}
return Result.success();
}
}
@@ -1,27 +1,18 @@
package com.emotion.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.emotion.common.BasePageRequest;
import com.emotion.common.PageResult;
import com.emotion.common.Result;
import com.emotion.dto.request.UserCreateRequest;
import com.emotion.dto.request.UserUpdateRequest;
import com.emotion.dto.request.UserPageRequest;
import com.emotion.dto.request.UserProfileUpdateRequest;
import com.emotion.dto.request.UserUpdateRequest;
import com.emotion.dto.response.UserResponse;
import com.emotion.entity.User;
import com.emotion.service.UserService;
import com.emotion.util.UserContextHolder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;
/**
* 用户控制器
@@ -36,183 +27,81 @@ public class UserController {
@Autowired
private UserService userService;
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
/**
* 分页查询用户
*/
@GetMapping("/page")
public Result<PageResult<UserResponse>> getPage(@Validated BasePageRequest request) {
IPage<User> page = userService.getPage(request);
List<UserResponse> userResponses = page.getRecords().stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
PageResult<UserResponse> pageResult = new PageResult<>();
pageResult.setCurrent(page.getCurrent());
pageResult.setSize(page.getSize());
pageResult.setTotal(page.getTotal());
pageResult.setPages(page.getPages());
pageResult.setRecords(userResponses);
@GetMapping(value = "/page")
public Result<PageResult<UserResponse>> getPage(@Validated UserPageRequest request) {
PageResult<UserResponse> pageResult = userService.getPageWithResponse(request);
return Result.success(pageResult);
}
/**
* 根据ID获取用户信息
*/
@GetMapping("/{id}")
public Result<UserResponse> getById(@PathVariable String id) {
User user = userService.getById(id);
@GetMapping(value = "/detail")
public Result<UserResponse> getById(@RequestParam String id) {
UserResponse user = userService.getUserResponseById(id);
if (user == null) {
return Result.notFound("用户不存在");
}
return Result.success(convertToResponse(user));
return Result.success(user);
}
/**
* 创建用户
*/
@PostMapping
@PostMapping(value = "/create")
public Result<UserResponse> create(@Valid @RequestBody UserCreateRequest request) {
User user = userService.createUser(
request.getAccount(),
request.getUsername(),
request.getPassword(),
request.getEmail(),
request.getPhone()
);
return Result.success(convertToResponse(user));
UserResponse user = userService.createUserWithResponse(request);
return Result.success(user);
}
/**
* 更新用户
*/
@PutMapping("/{id}")
public Result<UserResponse> update(@PathVariable String id, @Valid @RequestBody UserUpdateRequest request) {
User user = new User();
BeanUtils.copyProperties(request, user);
user.setId(id);
boolean updated = userService.updateById(user);
if (!updated) {
@PutMapping(value = "/update")
public Result<UserResponse> update(@Valid @RequestBody UserUpdateRequest request) {
UserResponse updatedUser = userService.updateUserWithResponse(request);
if (updatedUser == null) {
return Result.error("更新失败");
}
User updatedUser = userService.getById(id);
return Result.success(convertToResponse(updatedUser));
return Result.success(updatedUser);
}
/**
* 删除用户
*/
@DeleteMapping("/{id}")
public Result<Void> delete(@PathVariable String id) {
boolean deleted = userService.removeById(id);
@DeleteMapping(value = "/delete")
public Result<Void> delete(@RequestParam String id) {
boolean deleted = userService.deleteUser(id);
if (!deleted) {
return Result.error("删除失败");
}
return Result.success();
}
/**
* 根据账号查询用户
*/
@GetMapping("/account/{account}")
public Result<UserResponse> getByAccount(@PathVariable String account) {
User user = userService.getByAccount(account);
if (user == null) {
return Result.notFound("用户不存在");
}
return Result.success(convertToResponse(user));
}
/**
* 统计用户数量
*/
@GetMapping("/count/status/{status}")
public Result<Long> countByStatus(@PathVariable Integer status) {
Long count = userService.countByStatus(status);
return Result.success(count);
}
/**
* 获取当前用户个人资料
*/
@GetMapping("/profile")
public Result<UserResponse> getCurrentUserProfile(HttpServletRequest request) {
String currentUserId = getCurrentUserId(request);
if (currentUserId == null) {
@GetMapping(value = "/profile")
public Result<UserResponse> getCurrentUserProfile() {
UserResponse user = userService.getCurrentUserProfileWithResponse();
if (user == null) {
return Result.unauthorized("用户未登录");
}
User user = userService.getById(currentUserId);
if (user == null) {
return Result.notFound("用户不存在");
}
return Result.success(convertToResponse(user));
return Result.success(user);
}
/**
* 更新当前用户个人资料
*/
@PutMapping("/profile")
public Result<UserResponse> updateCurrentUserProfile(@Valid @RequestBody UserProfileUpdateRequest request,
HttpServletRequest httpRequest) {
String currentUserId = getCurrentUserId(httpRequest);
if (currentUserId == null) {
@PutMapping(value = "/profile")
public Result<UserResponse> updateCurrentUserProfile(@Valid @RequestBody UserProfileUpdateRequest request) {
UserResponse updatedUser = userService.updateCurrentUserProfileWithResponse(request);
if (updatedUser == null) {
return Result.unauthorized("用户未登录");
}
User user = new User();
BeanUtils.copyProperties(request, user);
user.setId(currentUserId);
boolean updated = userService.updateById(user);
if (!updated) {
return Result.error("更新失败");
}
User updatedUser = userService.getById(currentUserId);
return Result.success(convertToResponse(updatedUser));
}
/**
* 获取当前用户ID
* 从JWT拦截器设置的请求属性中获取用户ID
*/
private String getCurrentUserId(HttpServletRequest request) {
// 优先从UserContextHolder获取(线程本地存储)
String userId = UserContextHolder.getCurrentUserId();
if (userId != null) {
return userId;
}
// 如果UserContextHolder中没有,从请求属性中获取(兼容性)
Object userIdAttr = request.getAttribute("userId");
if (userIdAttr != null) {
return userIdAttr.toString();
}
return null;
}
/**
* 转换为响应对象
*/
private UserResponse convertToResponse(User user) {
UserResponse response = new UserResponse();
BeanUtils.copyProperties(user, response);
response.setId(user.getId());
if (user.getCreateTime() != null) {
response.setCreateTime(user.getCreateTime().format(DATE_TIME_FORMATTER));
}
if (user.getUpdateTime() != null) {
response.setUpdateTime(user.getUpdateTime().format(DATE_TIME_FORMATTER));
}
if (user.getLastActiveTime() != null) {
response.setLastActiveTime(user.getLastActiveTime().format(DATE_TIME_FORMATTER));
}
return response;
return Result.success(updatedUser);
}
}
@@ -1,22 +1,20 @@
package com.emotion.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.emotion.common.PageResult;
import com.emotion.common.Result;
import com.emotion.dto.request.PageRequest;
import com.emotion.dto.response.BaseResponse;
import com.emotion.entity.UserStats;
import com.emotion.dto.request.UserStatsCreateRequest;
import com.emotion.dto.request.UserStatsIncrementRequest;
import com.emotion.dto.request.UserStatsPageRequest;
import com.emotion.dto.request.UserStatsUpdateValueRequest;
import com.emotion.dto.response.UserStatsResponse;
import com.emotion.service.UserStatsService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotBlank;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;
/**
* 用户统计控制器
@@ -25,123 +23,37 @@ import java.util.stream.Collectors;
* @date 2025-07-23
*/
@RestController
@RequestMapping("/user-stats")
@RequestMapping("/userStats")
@Validated
public class UserStatsController {
@Autowired
private UserStatsService userStatsService;
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
/**
* 分页查询用户统计
*/
@GetMapping("/page")
public Result<PageResult<UserStatsResponse>> getPage(@Validated PageRequest request) {
IPage<UserStats> page = userStatsService.getPage(request);
List<UserStatsResponse> responses = page.getRecords().stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
PageResult<UserStatsResponse> pageResult = new PageResult<>();
pageResult.setCurrent(page.getCurrent());
pageResult.setSize(page.getSize());
pageResult.setTotal(page.getTotal());
pageResult.setPages(page.getPages());
pageResult.setRecords(responses);
@GetMapping(value = "/page")
public Result<PageResult<UserStatsResponse>> getPage(@Validated UserStatsPageRequest request) {
PageResult<UserStatsResponse> pageResult = userStatsService.getPageWithResponse(request);
return Result.success(pageResult);
}
/**
* 根据用户ID获取统计信息
*/
@GetMapping("/user/{userId}")
public Result<UserStatsResponse> getByUserId(@PathVariable String userId) {
UserStats stats = userStatsService.getByUserId(userId);
if (stats == null) {
return Result.notFound("用户统计不存在");
}
return Result.success(convertToResponse(stats));
}
/**
* 根据用户ID和统计类型获取统计信息
*/
@GetMapping("/user/{userId}/type/{statsType}")
public Result<UserStatsResponse> getByUserIdAndStatsType(@PathVariable String userId, @PathVariable String statsType) {
UserStats stats = userStatsService.getByUserIdAndStatsType(userId, statsType);
if (stats == null) {
return Result.notFound("用户统计不存在");
}
return Result.success(convertToResponse(stats));
}
/**
* 根据统计类型查询统计信息
*/
@GetMapping("/type/{statsType}")
public Result<List<UserStatsResponse>> getByStatsType(@PathVariable String statsType) {
List<UserStats> statsList = userStatsService.getByStatsType(statsType);
List<UserStatsResponse> responses = statsList.stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
return Result.success(responses);
}
/**
* 查询用户的所有统计类型
*/
@GetMapping("/user/{userId}/all")
public Result<List<UserStatsResponse>> getAllStatsByUserId(@PathVariable String userId) {
List<UserStats> statsList = userStatsService.getAllStatsByUserId(userId);
List<UserStatsResponse> responses = statsList.stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
return Result.success(responses);
}
/**
* 查询排名前N的用户统计
*/
@GetMapping("/type/{statsType}/top")
public Result<List<UserStatsResponse>> getTopUsersByStatsType(@PathVariable String statsType, @RequestParam(defaultValue = "10") Integer limit) {
List<UserStats> statsList = userStatsService.getTopUsersByStatsType(statsType, limit);
List<UserStatsResponse> responses = statsList.stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
return Result.success(responses);
}
/**
* 查询用户在指定统计类型中的排名
*/
@GetMapping("/user/{userId}/type/{statsType}/rank")
public Result<Long> getUserRankByStatsType(@PathVariable String userId, @PathVariable String statsType) {
Long rank = userStatsService.getUserRankByStatsType(userId, statsType);
return Result.success(rank);
}
/**
* 创建或更新用户统计
*/
@PostMapping
public Result<UserStatsResponse> createOrUpdate(@RequestBody @Validated UserStatsCreateRequest request) {
UserStats stats = userStatsService.createOrUpdateUserStats(
request.getUserId(),
request.getStatsType(),
request.getValue(),
request.getPeriod()
);
return Result.success(convertToResponse(stats));
@PostMapping(value = "/createOrUpdate")
public Result<UserStatsResponse> createOrUpdate(@Valid @RequestBody UserStatsCreateRequest request) {
UserStatsResponse stats = userStatsService.createOrUpdateUserStatsWithResponse(request);
return Result.success(stats);
}
/**
* 更新用户统计值
*/
@PutMapping("/user/{userId}/type/{statsType}")
public Result<Void> updateStatsValue(@PathVariable String userId, @PathVariable String statsType, @RequestParam Double value) {
boolean updated = userStatsService.updateStatsValue(userId, statsType, value);
@PutMapping(value = "/updateStatsValue")
public Result<Void> updateStatsValue(@Valid @RequestBody UserStatsUpdateValueRequest request) {
boolean updated = userStatsService.updateStatsValue(request);
if (!updated) {
return Result.error("更新失败");
}
@@ -151,9 +63,9 @@ public class UserStatsController {
/**
* 增加用户统计值
*/
@PutMapping("/user/{userId}/type/{statsType}/increment")
public Result<Void> incrementStatsValue(@PathVariable String userId, @PathVariable String statsType, @RequestParam Double increment) {
boolean updated = userStatsService.incrementStatsValue(userId, statsType, increment);
@PutMapping(value = "/incrementStatsValue")
public Result<Void> incrementStatsValue(@Valid @RequestBody UserStatsIncrementRequest request) {
boolean updated = userStatsService.incrementStatsValue(request);
if (!updated) {
return Result.error("增加失败");
}
@@ -163,8 +75,8 @@ public class UserStatsController {
/**
* 重新计算用户统计
*/
@PutMapping("/user/{userId}/recalculate")
public Result<Void> recalculateUserStats(@PathVariable String userId) {
@PutMapping(value = "/recalculateUserStats")
public Result<Void> recalculateUserStats(@RequestParam String userId) {
boolean recalculated = userStatsService.recalculateUserStats(userId);
if (!recalculated) {
return Result.error("重新计算失败");
@@ -175,7 +87,7 @@ public class UserStatsController {
/**
* 重新计算所有用户统计
*/
@PutMapping("/recalculate-all")
@PutMapping(value = "/recalculateAll")
public Result<Void> recalculateAllUserStats() {
boolean recalculated = userStatsService.recalculateAllUserStats();
if (!recalculated) {
@@ -184,37 +96,10 @@ public class UserStatsController {
return Result.success();
}
/**
* 查询平均统计值
*/
@GetMapping("/type/{statsType}/avg")
public Result<Double> getAvgValueByStatsType(@PathVariable String statsType) {
Double avgValue = userStatsService.getAvgValueByStatsType(statsType);
return Result.success(avgValue);
}
/**
* 查询最大统计值
*/
@GetMapping("/type/{statsType}/max")
public Result<Double> getMaxValueByStatsType(@PathVariable String statsType) {
Double maxValue = userStatsService.getMaxValueByStatsType(statsType);
return Result.success(maxValue);
}
/**
* 查询最小统计值
*/
@GetMapping("/type/{statsType}/min")
public Result<Double> getMinValueByStatsType(@PathVariable String statsType) {
Double minValue = userStatsService.getMinValueByStatsType(statsType);
return Result.success(minValue);
}
/**
* 删除过期的统计数据
*/
@DeleteMapping("/expired")
@DeleteMapping(value = "/deleteExpired")
public Result<Void> deleteExpiredStats(@RequestParam(defaultValue = "30") Integer days) {
boolean deleted = userStatsService.deleteExpiredStats(days);
if (!deleted) {
@@ -222,49 +107,4 @@ public class UserStatsController {
}
return Result.success();
}
/**
* 转换为响应对象
*/
private UserStatsResponse convertToResponse(UserStats stats) {
UserStatsResponse response = new UserStatsResponse();
BeanUtils.copyProperties(stats, response);
response.setId(stats.getId());
if (stats.getCreateTime() != null) {
response.setCreateTime(stats.getCreateTime().format(DATE_TIME_FORMATTER));
}
if (stats.getUpdateTime() != null) {
response.setUpdateTime(stats.getUpdateTime().format(DATE_TIME_FORMATTER));
}
return response;
}
/**
* 用户统计创建请求
*/
@lombok.Data
public static class UserStatsCreateRequest {
@NotBlank(message = "用户ID不能为空")
private String userId;
@NotBlank(message = "统计类型不能为空")
private String statsType;
@NotNull(message = "统计值不能为空")
private Double value;
private String period;
}
/**
* 用户统计响应类
*/
@lombok.Data
@lombok.EqualsAndHashCode(callSuper = true)
public static class UserStatsResponse extends BaseResponse {
private String userId;
private String statsType;
private Double value;
private String period;
}
}
}
@@ -1,114 +0,0 @@
package com.emotion.controller;
import com.emotion.service.AiChatService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.HashMap;
import java.util.Map;
/**
* WebSocket控制器
*
* @author emotion-museum
* @date 2025-07-22
*/
@Controller
public class WebSocketController {
private static final Logger log = LoggerFactory.getLogger(WebSocketController.class);
@Autowired
private SimpMessagingTemplate messagingTemplate;
@Autowired
private AiChatService aiChatService;
// 已移除旧的WebSocket消息处理方法,使用新的ChatWebSocketController
// 已移除旧的用户连接处理方法,使用新的ChatWebSocketController
/**
* 处理AI聊天消息
*/
@MessageMapping("/chat.ai")
public void handleAiChat(@Payload Map<String, Object> chatMessage,
SimpMessageHeaderAccessor headerAccessor) {
log.info("收到AI聊天消息: {}", chatMessage);
try {
String content = (String) chatMessage.get("content");
String conversationId = (String) chatMessage.get("conversationId");
String userId = (String) chatMessage.get("userId");
// 调用AI服务
String aiReply = aiChatService.sendMessage(conversationId, content, userId);
// 构建AI回复消息
Map<String, Object> aiResponse = new HashMap<>();
aiResponse.put("content", aiReply);
aiResponse.put("sender", "AI助手");
aiResponse.put("type", "AI_REPLY");
aiResponse.put("conversationId", conversationId);
aiResponse.put("timestamp", System.currentTimeMillis());
// 发送给特定用户
if (userId != null) {
messagingTemplate.convertAndSendToUser(userId, "/queue/messages", aiResponse);
} else {
// 发送到公共频道
messagingTemplate.convertAndSend("/topic/conversation/" + conversationId, aiResponse);
}
} catch (Exception e) {
log.error("处理AI聊天失败", e);
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("content", "AI服务暂时不可用,请稍后再试");
errorResponse.put("sender", "System");
errorResponse.put("type", "ERROR");
errorResponse.put("timestamp", System.currentTimeMillis());
String userId = (String) chatMessage.get("userId");
if (userId != null) {
messagingTemplate.convertAndSendToUser(userId, "/queue/messages", errorResponse);
}
}
}
/**
* 发送系统消息
*/
public void sendSystemMessage(String destination, String message) {
Map<String, Object> systemMessage = new HashMap<>();
systemMessage.put("content", message);
systemMessage.put("sender", "System");
systemMessage.put("type", "SYSTEM");
systemMessage.put("timestamp", System.currentTimeMillis());
messagingTemplate.convertAndSend(destination, systemMessage);
}
/**
* WebSocket状态监控接口
*/
@GetMapping("/api/ws/status")
@ResponseBody
public Map<String, Object> getWebSocketStatus() {
Map<String, Object> status = new HashMap<>();
status.put("status", "active");
status.put("timestamp", System.currentTimeMillis());
status.put("endpoint", "/ws/chat");
status.put("protocols", new String[]{"websocket", "sockjs"});
status.put("message", "WebSocket服务正常运行");
return status;
}
}
@@ -4,6 +4,7 @@ import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
@@ -21,6 +22,7 @@ public class EmotionRecordCreateRequest {
* 用户ID
*/
@NotBlank(message = "用户ID不能为空")
@Size(max = 32, message = "用户ID长度不能超过32个字符")
private String userId;
/**
@@ -33,6 +35,7 @@ public class EmotionRecordCreateRequest {
* 情绪类型
*/
@NotBlank(message = "情绪类型不能为空")
@Size(max = 32, message = "情绪类型长度不能超过32个字符")
private String emotionType;
/**
@@ -44,11 +47,13 @@ public class EmotionRecordCreateRequest {
/**
* 触发因素
*/
@Size(max = 768, message = "触发因素长度不能超过768个字符")
private String triggers;
/**
* 描述
*/
@Size(max = 768, message = "描述长度不能超过768个字符")
private String description;
/**
@@ -59,25 +64,30 @@ public class EmotionRecordCreateRequest {
/**
* 天气
*/
@Size(max = 64, message = "天气长度不能超过64个字符")
private String weather;
/**
* 地点
*/
@Size(max = 128, message = "地点长度不能超过128个字符")
private String location;
/**
* 活动
*/
@Size(max = 128, message = "活动长度不能超过128个字符")
private String activity;
/**
* 相关人物
*/
@Size(max = 256, message = "相关人物长度不能超过256个字符")
private String people;
/**
* 备注
*/
@Size(max = 1024, message = "备注长度不能超过1024个字符")
private String notes;
}
@@ -4,6 +4,8 @@ import com.emotion.common.BasePageRequest;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.Size;
/**
* 情绪记录分页请求类
*
@@ -17,15 +19,18 @@ public class EmotionRecordPageRequest extends BasePageRequest {
/**
* 用户ID(可选)
*/
@Size(max = 32, message = "用户ID长度不能超过32个字符")
private String userId;
/**
* 情绪类型(可选)
*/
@Size(max = 32, message = "情绪类型长度不能超过32个字符")
private String emotionType;
/**
* 地点(可选)
*/
@Size(max = 128, message = "地点长度不能超过128个字符")
private String location;
}
@@ -3,6 +3,7 @@ package com.emotion.dto.request;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
@@ -20,6 +21,7 @@ public class EmotionRecordUpdateRequest {
* 情绪记录ID
*/
@NotBlank(message = "情绪记录ID不能为空")
@Size(max = 32, message = "情绪记录ID长度不能超过32个字符")
private String id;
/**
@@ -30,6 +32,7 @@ public class EmotionRecordUpdateRequest {
/**
* 情绪类型
*/
@Size(max = 32, message = "情绪类型长度不能超过32个字符")
private String emotionType;
/**
@@ -40,11 +43,13 @@ public class EmotionRecordUpdateRequest {
/**
* 触发因素
*/
@Size(max = 768, message = "触发因素长度不能超过768个字符")
private String triggers;
/**
* 描述
*/
@Size(max = 768, message = "描述长度不能超过768个字符")
private String description;
/**
@@ -55,25 +60,30 @@ public class EmotionRecordUpdateRequest {
/**
* 天气
*/
@Size(max = 64, message = "天气长度不能超过64个字符")
private String weather;
/**
* 地点
*/
@Size(max = 128, message = "地点长度不能超过128个字符")
private String location;
/**
* 活动
*/
@Size(max = 128, message = "活动长度不能超过128个字符")
private String activity;
/**
* 相关人物
*/
@Size(max = 256, message = "相关人物长度不能超过256个字符")
private String people;
/**
* 备注
*/
@Size(max = 1024, message = "备注长度不能超过1024个字符")
private String notes;
}
@@ -0,0 +1,14 @@
package com.emotion.dto.request;
import lombok.Data;
/**
* 情绪总结生成请求类
*
* @author emotion-museum
* @date 2025-09-08
*/
@Data
public class EmotionSummaryGenerateRequest {
// 目前情绪总结生成不需要额外参数
}
@@ -0,0 +1,14 @@
package com.emotion.dto.request;
import lombok.Data;
/**
* 情绪总结状态请求类
*
* @author emotion-museum
* @date 2025-09-08
*/
@Data
public class EmotionSummaryStatusRequest {
// 目前情绪总结状态查询不需要额外参数
}
@@ -0,0 +1,65 @@
package com.emotion.dto.request;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
/**
* 话题互动创建请求
*
* @author emotion-museum
* @date 2025-09-08
*/
@Data
public class TopicInteractionCreateRequest {
/**
* 话题ID
*/
@NotBlank(message = "话题ID不能为空")
@Size(max = 50, message = "话题ID长度不能超过50个字符")
private String topicId;
/**
* 互动类型
*/
@NotBlank(message = "互动类型不能为空")
@Size(max = 50, message = "互动类型长度不能超过50个字符")
private String interactionType;
/**
* 内容
*/
@Size(max = 1000, message = "内容长度不能超过1000个字符")
private String content;
/**
* 用户输入
*/
@Size(max = 1000, message = "用户输入长度不能超过1000个字符")
private String userInput;
/**
* AI回应
*/
@Size(max = 1000, message = "AI回应长度不能超过1000个字符")
private String aiResponse;
/**
* 附件
*/
@Size(max = 500, message = "附件长度不能超过500个字符")
private String attachments;
/**
* 评分
*/
private Integer rating;
/**
* 反馈
*/
@Size(max = 500, message = "反馈长度不能超过500个字符")
private String feedback;
}
@@ -0,0 +1,36 @@
package com.emotion.dto.request;
import com.emotion.common.BasePageRequest;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.Size;
/**
* 话题互动分页查询请求
*
* @author emotion-museum
* @date 2025-09-08
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class TopicInteractionPageRequest extends BasePageRequest {
/**
* 话题ID
*/
@Size(max = 50, message = "话题ID长度不能超过50个字符")
private String topicId;
/**
* 用户ID
*/
@Size(max = 50, message = "用户ID长度不能超过50个字符")
private String userId;
/**
* 互动类型
*/
@Size(max = 50, message = "互动类型长度不能超过50个字符")
private String interactionType;
}
@@ -0,0 +1,70 @@
package com.emotion.dto.request;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
/**
* 话题互动更新请求
*
* @author emotion-museum
* @date 2025-09-08
*/
@Data
public class TopicInteractionUpdateRequest {
/**
* ID
*/
@NotBlank(message = "ID不能为空")
@Size(max = 50, message = "ID长度不能超过50个字符")
private String id;
/**
* 话题ID
*/
@Size(max = 50, message = "话题ID长度不能超过50个字符")
private String topicId;
/**
* 互动类型
*/
@Size(max = 50, message = "互动类型长度不能超过50个字符")
private String interactionType;
/**
* 内容
*/
@Size(max = 1000, message = "内容长度不能超过1000个字符")
private String content;
/**
* 用户输入
*/
@Size(max = 1000, message = "用户输入长度不能超过1000个字符")
private String userInput;
/**
* AI回应
*/
@Size(max = 1000, message = "AI回应长度不能超过1000个字符")
private String aiResponse;
/**
* 附件
*/
@Size(max = 500, message = "附件长度不能超过500个字符")
private String attachments;
/**
* 评分
*/
private Integer rating;
/**
* 反馈
*/
@Size(max = 500, message = "反馈长度不能超过500个字符")
private String feedback;
}
@@ -0,0 +1,53 @@
package com.emotion.dto.request;
import com.emotion.common.BasePageRequest;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.Size;
/**
* 用户分页查询请求
*
* @author emotion-museum
* @date 2025-09-08
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class UserPageRequest extends BasePageRequest {
/**
* 账号
*/
@Size(max = 20, message = "账号长度不能超过20个字符")
private String account;
/**
* 用户名
*/
@Size(max = 20, message = "用户名长度不能超过20个字符")
private String username;
/**
* 邮箱
*/
@Size(max = 100, message = "邮箱长度不能超过100个字符")
private String email;
/**
* 手机号
*/
@Size(max = 20, message = "手机号长度不能超过20个字符")
private String phone;
/**
* 状态
*/
private Integer status;
/**
* 会员等级
*/
@Size(max = 20, message = "会员等级长度不能超过20个字符")
private String memberLevel;
}
@@ -0,0 +1,39 @@
package com.emotion.dto.request;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* 用户统计创建请求
*
* @author emotion-museum
* @date 2025-09-09
*/
@Data
public class UserStatsCreateRequest extends BaseRequest {
/**
* 用户ID
*/
@NotBlank(message = "用户ID不能为空")
private String userId;
/**
* 统计类型
*/
@NotBlank(message = "统计类型不能为空")
private String statsType;
/**
* 统计值
*/
@NotNull(message = "统计值不能为空")
private Double value;
/**
* 周期
*/
private String period;
}
@@ -0,0 +1,34 @@
package com.emotion.dto.request;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* 用户统计值增加请求
*
* @author emotion-museum
* @date 2025-09-09
*/
@Data
public class UserStatsIncrementRequest extends BaseRequest {
/**
* 用户ID
*/
@NotBlank(message = "用户ID不能为空")
private String userId;
/**
* 统计类型
*/
@NotBlank(message = "统计类型不能为空")
private String statsType;
/**
* 增加值
*/
@NotNull(message = "增加值不能为空")
private Double increment;
}
@@ -0,0 +1,26 @@
package com.emotion.dto.request;
import com.emotion.common.BasePageRequest;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 用户统计分页查询请求
*
* @author emotion-museum
* @date 2025-09-09
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class UserStatsPageRequest extends BasePageRequest {
/**
* 用户ID
*/
private String userId;
/**
* 统计类型
*/
private String statsType;
}
@@ -0,0 +1,34 @@
package com.emotion.dto.request;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* 用户统计值更新请求
*
* @author emotion-museum
* @date 2025-09-09
*/
@Data
public class UserStatsUpdateValueRequest extends BaseRequest {
/**
* 用户ID
*/
@NotBlank(message = "用户ID不能为空")
private String userId;
/**
* 统计类型
*/
@NotBlank(message = "统计类型不能为空")
private String statsType;
/**
* 统计值
*/
@NotNull(message = "统计值不能为空")
private Double value;
}
@@ -1,9 +1,9 @@
package com.emotion.dto.request;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import java.time.LocalDate;
@@ -12,11 +12,16 @@ import java.time.LocalDate;
* 用户更新请求类
*
* @author emotion-museum
* @date 2025-07-24
* @date 2025-09-08
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class UserUpdateRequest extends BaseRequest {
public class UserUpdateRequest {
/**
* ID
*/
@NotBlank(message = "ID不能为空")
private String id;
/**
* 用户名
@@ -70,4 +75,10 @@ public class UserUpdateRequest extends BaseRequest {
* 状态
*/
private Integer status;
/**
* 会员等级
*/
@Size(max = 20, message = "会员等级长度不能超过20个字符")
private String memberLevel;
}
@@ -0,0 +1,55 @@
package com.emotion.dto.request.growth;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.time.LocalDateTime;
/**
* 成长话题创建请求
*
* @author emotion-museum
* @date 2025-09-08
*/
@Data
public class GrowthTopicCreateRequest {
/**
* 课题标题
*/
@NotBlank(message = "标题不能为空")
@Size(max = 100, message = "标题长度不能超过100个字符")
private String title;
/**
* 描述
*/
@Size(max = 500, message = "描述长度不能超过500个字符")
private String description;
/**
* 分类
*/
@NotBlank(message = "分类不能为空")
@Size(max = 50, message = "分类长度不能超过50个字符")
private String category;
/**
* 难度等级
*/
@NotBlank(message = "难度等级不能为空")
@Size(max = 20, message = "难度等级长度不能超过20个字符")
private String difficultyLevel;
/**
* 标签
*/
@Size(max = 200, message = "标签长度不能超过200个字符")
private String tags;
/**
* 结束时间
*/
private LocalDateTime endTime;
}
@@ -0,0 +1,34 @@
package com.emotion.dto.request.growth;
import com.emotion.common.BasePageRequest;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
/**
* 成长话题分页查询请求
*
* @author emotion-museum
* @date 2025-09-08
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class GrowthTopicPageRequest extends BasePageRequest {
/**
* 分类
*/
private String category;
/**
* 难度等级
*/
private String difficultyLevel;
/**
* 标签
*/
private String tags;
}
@@ -0,0 +1,58 @@
package com.emotion.dto.request.growth;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.time.LocalDateTime;
/**
* 成长话题更新请求
*
* @author emotion-museum
* @date 2025-09-08
*/
@Data
public class GrowthTopicUpdateRequest {
/**
* ID
*/
@NotBlank(message = "ID不能为空")
private String id;
/**
* 课题标题
*/
@Size(max = 100, message = "标题长度不能超过100个字符")
private String title;
/**
* 描述
*/
@Size(max = 500, message = "描述长度不能超过500个字符")
private String description;
/**
* 分类
*/
@Size(max = 50, message = "分类长度不能超过50个字符")
private String category;
/**
* 难度等级
*/
@Size(max = 20, message = "难度等级长度不能超过20个字符")
private String difficultyLevel;
/**
* 标签
*/
@Size(max = 200, message = "标签长度不能超过200个字符")
private String tags;
/**
* 结束时间
*/
private LocalDateTime endTime;
}
@@ -0,0 +1,41 @@
package com.emotion.dto.request.guest;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
/**
* 访客用户创建请求
*
* @author emotion-museum
* @date 2025-09-08
*/
@Data
public class GuestUserCreateRequest {
/**
* 设备ID
*/
@NotBlank(message = "设备ID不能为空")
@Size(max = 100, message = "设备ID长度不能超过100个字符")
private String deviceId;
/**
* IP地址
*/
@Size(max = 50, message = "IP地址长度不能超过50个字符")
private String ipAddress;
/**
* 用户代理
*/
@Size(max = 500, message = "用户代理长度不能超过500个字符")
private String userAgent;
/**
* 地理位置
*/
@Size(max = 100, message = "地理位置长度不能超过100个字符")
private String location;
}
@@ -0,0 +1,31 @@
package com.emotion.dto.request.guest;
import com.emotion.common.BasePageRequest;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 访客用户分页查询请求
*
* @author emotion-museum
* @date 2025-09-08
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class GuestUserPageRequest extends BasePageRequest {
/**
* 设备ID
*/
private String deviceId;
/**
* IP地址
*/
private String ipAddress;
/**
* 用户代理
*/
private String userAgent;
}
@@ -0,0 +1,40 @@
package com.emotion.dto.request.guest;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
/**
* 访客用户更新请求
*
* @author emotion-museum
* @date 2025-09-08
*/
@Data
public class GuestUserUpdateRequest {
/**
* ID
*/
@NotBlank(message = "ID不能为空")
private String id;
/**
* 访客昵称
*/
@Size(max = 50, message = "访客昵称长度不能超过50个字符")
private String nickname;
/**
* 访客头像
*/
@Size(max = 200, message = "访客头像长度不能超过200个字符")
private String avatar;
/**
* 地理位置
*/
@Size(max = 100, message = "地理位置长度不能超过100个字符")
private String location;
}
@@ -0,0 +1,65 @@
package com.emotion.dto.request.reward;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.time.LocalDateTime;
/**
* 奖励创建请求
*
* @author emotion-museum
* @date 2025-09-08
*/
@Data
public class RewardCreateRequest {
/**
* 用户ID
*/
@NotBlank(message = "用户ID不能为空")
private String userId;
/**
* 奖励类型
*/
@NotBlank(message = "奖励类型不能为空")
@Size(max = 50, message = "奖励类型长度不能超过50个字符")
private String rewardType;
/**
* 奖励值
*/
@Size(max = 100, message = "奖励值长度不能超过100个字符")
private String value;
/**
* 描述
*/
@Size(max = 200, message = "描述长度不能超过200个字符")
private String description;
/**
* 课题ID
*/
private String topicId;
/**
* 成就ID
*/
private String achievementId;
/**
* 图标
*/
@Size(max = 200, message = "图标长度不能超过200个字符")
private String icon;
/**
* 稀有度
*/
@Size(max = 20, message = "稀有度长度不能超过20个字符")
private String rarity;
}
@@ -0,0 +1,31 @@
package com.emotion.dto.request.reward;
import com.emotion.common.BasePageRequest;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 奖励分页查询请求
*
* @author emotion-museum
* @date 2025-09-08
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class RewardPageRequest extends BasePageRequest {
/**
* 用户ID
*/
private String userId;
/**
* 奖励类型
*/
private String rewardType;
/**
* 来源
*/
private String source;
}
@@ -0,0 +1,67 @@
package com.emotion.dto.request.reward;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
/**
* 奖励更新请求
*
* @author emotion-museum
* @date 2025-09-08
*/
@Data
public class RewardUpdateRequest {
/**
* ID
*/
@NotBlank(message = "ID不能为空")
private String id;
/**
* 奖励类型
*/
@Size(max = 50, message = "奖励类型长度不能超过50个字符")
private String rewardType;
/**
* 奖励值
*/
@Size(max = 100, message = "奖励值长度不能超过100个字符")
private String value;
/**
* 描述
*/
@Size(max = 200, message = "描述长度不能超过200个字符")
private String description;
/**
* 课题ID
*/
private String topicId;
/**
* 成就ID
*/
private String achievementId;
/**
* 图标
*/
@Size(max = 200, message = "图标长度不能超过200个字符")
private String icon;
/**
* 稀有度
*/
@Size(max = 20, message = "稀有度长度不能超过20个字符")
private String rarity;
/**
* 是否新获得
*/
private Integer isNew;
}
@@ -0,0 +1,45 @@
package com.emotion.dto.response;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 情绪总结生成响应类
*
* @author emotion-museum
* @date 2025-09-08
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class EmotionSummaryGenerateResponse extends BaseResponse {
/**
* 是否成功
*/
private Boolean success;
/**
* 消息
*/
private String message;
/**
* 情绪记录ID
*/
private String emotionRecordId;
/**
* 情绪分析ID
*/
private String emotionAnalysisId;
/**
* 消息数量
*/
private Integer messageCount;
/**
* 记录日期
*/
private String recordDate;
}
@@ -0,0 +1,30 @@
package com.emotion.dto.response;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 情绪总结状态响应类
*
* @author emotion-museum
* @date 2025-09-08
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class EmotionSummaryStatusResponse extends BaseResponse {
/**
* 用户ID
*/
private String userId;
/**
* 是否可以生成
*/
private Boolean canGenerate;
/**
* 消息
*/
private String message;
}
@@ -0,0 +1,57 @@
package com.emotion.dto.response;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDateTime;
/**
* 话题互动响应类
*
* @author emotion-museum
* @date 2025-09-08
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class TopicInteractionResponse extends BaseResponse {
/**
* 话题ID
*/
private String topicId;
/**
* 互动类型
*/
private String type;
/**
* 内容
*/
private String content;
/**
* 用户输入
*/
private String userInput;
/**
* AI回应
*/
private String aiResponse;
/**
* 评分
*/
private Integer rating;
/**
* 反馈
*/
private String feedback;
/**
* 完成时间
*/
private LocalDateTime completedTime;
}
@@ -0,0 +1,35 @@
package com.emotion.dto.response;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 用户统计响应类
*
* @author emotion-museum
* @date 2025-09-08
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class UserStatsResponse extends BaseResponse {
/**
* 用户ID
*/
private String userId;
/**
* 统计类型
*/
private String statsType;
/**
* 统计值
*/
private Double value;
/**
* 周期
*/
private String period;
}
@@ -0,0 +1,74 @@
package com.emotion.dto.response.growth;
import com.emotion.dto.response.BaseResponse;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 成长话题响应类
*
* @author emotion-museum
* @date 2025-09-08
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class GrowthTopicResponse extends BaseResponse {
/**
* 课题标题
*/
private String title;
/**
* 分类
*/
private String category;
/**
* 难度: easy-简单, medium-中等, hard-困难
*/
private String difficulty;
/**
* 描述
*/
private String description;
/**
* 内容
*/
private String content;
/**
* 持续天数
*/
private Integer durationDays;
/**
* 解锁条件
*/
private String unlockConditions;
/**
* 是否解锁
*/
private Integer isUnlocked;
/**
* 进度百分比
*/
private BigDecimal progress;
/**
* 完成时间
*/
private LocalDateTime completedTime;
/**
* 奖励
*/
private String rewards;
}
@@ -0,0 +1,68 @@
package com.emotion.dto.response.guest;
import com.emotion.dto.response.BaseResponse;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDateTime;
/**
* 访客用户响应类
*
* @author emotion-museum
* @date 2025-09-08
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class GuestUserResponse extends BaseResponse {
/**
* 访客用户ID (格式: guest_xxx)
*/
private String guestUserId;
/**
* 客户端IP地址 (支持IPv6)
*/
private String ipAddress;
/**
* 用户代理信息
*/
private String userAgent;
/**
* 访客昵称
*/
private String nickname;
/**
* 访客头像
*/
private String avatar;
/**
* 最后活跃时间
*/
private LocalDateTime lastActiveTime;
/**
* 会话数量
*/
private Integer conversationCount;
/**
* 消息数量
*/
private Integer messageCount;
/**
* IP地址的地理位置信息
*/
private String location;
/**
* 设备信息
*/
private String deviceInfo;
}
@@ -0,0 +1,68 @@
package com.emotion.dto.response.reward;
import com.emotion.dto.response.BaseResponse;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDateTime;
/**
* 奖励响应类
*
* @author emotion-museum
* @date 2025-09-08
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class RewardResponse extends BaseResponse {
/**
* 课题ID
*/
private String topicId;
/**
* 成就ID
*/
private String achievementId;
/**
* 奖励类型
*/
private String type;
/**
* 奖励名称
*/
private String name;
/**
* 描述
*/
private String description;
/**
* 图标
*/
private String icon;
/**
* 稀有度
*/
private String rarity;
/**
* 奖励值
*/
private String value;
/**
* 获得时间
*/
private LocalDateTime earnedTime;
/**
* 是否新获得
*/
private Integer isNew;
}
@@ -28,6 +28,24 @@ public class UserStats extends BaseEntity {
@TableField("user_id")
private String userId;
/**
* 统计类型
*/
@TableField("stats_type")
private String statsType;
/**
* 统计值
*/
@TableField("value")
private Double value;
/**
* 周期
*/
@TableField("period")
private String period;
/**
* 总对话数
*/
@@ -105,4 +123,4 @@ public class UserStats extends BaseEntity {
*/
@TableField("social_interactions")
private Integer socialInteractions;
}
}
@@ -2,6 +2,8 @@ package com.emotion.service;
import com.emotion.dto.request.*;
import com.emotion.dto.response.*;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
/**
* AI聊天服务接口
@@ -114,26 +116,43 @@ public interface AiChatService {
*/
boolean healthCheck();
/**
* 发送日记内容生成AI总结评论
*
* @param conversationId 会话ID
* @param userMessage 用户日记内容
* @param userId 用户ID
* @return AI评论内容
*/
String sendSummaryMessage(String conversationId, String userMessage, String userId);
/**
* 生成用户情绪记录总结
* @param userId 用户ID
* @return 包含情绪总结等信息的Map
*/
java.util.Map<String, Object> generateEmotionSummary(String userId);
Map<String, Object> generateEmotionSummary(String userId);
/**
* 异步生成用户情绪记录总结
* @param userId 用户ID
* @return 包含情绪总结等信息的CompletableFuture
*/
java.util.concurrent.CompletableFuture<java.util.Map<String, Object>> generateEmotionSummaryAsync(String userId);
CompletableFuture<Map<String, Object>> generateEmotionSummaryAsync(String userId);
/**
* 发送日记内容生成AI总结评论
* @param conversationId 会话ID
* @param userMessage 用户日记内容
* 生成用户情绪记录总结并返回响应对象
*
* @param userId 用户ID
* @return AI评论内容
* @return 情绪总结生成响应
*/
String sendSummaryMessage(String conversationId, String userMessage, String userId);
EmotionSummaryGenerateResponse generateEmotionSummaryWithResponse(String userId);
/**
* 获取用户情绪记录总结状态并返回响应对象
*
* @param userId 用户ID
* @return 情绪总结状态响应
*/
EmotionSummaryStatusResponse getEmotionSummaryStatusWithResponse(String userId);
}
@@ -32,86 +32,6 @@ public interface EmotionRecordService extends IService<EmotionRecord> {
*/
IPage<EmotionRecord> getPageByUserId(BasePageRequest request, String userId);
/**
* 根据用户ID分页查询情绪记录(简化版本)
*/
IPage<EmotionRecord> getByUserIdWithPage(String userId, Integer current, Integer size);
/**
* 根据用户ID查询情绪记录
*/
List<EmotionRecord> getByUserId(String userId);
/**
* 根据情绪类型查询记录
*/
List<EmotionRecord> getByEmotionType(String emotionType);
/**
* 根据用户ID和情绪类型查询记录
*/
List<EmotionRecord> getByUserIdAndEmotionType(String userId, String emotionType);
/**
* 根据时间范围查询情绪记录
*/
List<EmotionRecord> getByUserIdAndTimeRange(String userId, LocalDateTime startTime, LocalDateTime endTime);
/**
* 根据强度范围查询情绪记录
*/
List<EmotionRecord> getByIntensityRange(Double minIntensity, Double maxIntensity);
/**
* 统计用户的情绪记录数量
*/
Long countByUserId(String userId);
/**
* 统计指定情绪类型的记录数量
*/
Long countByEmotionType(String emotionType);
/**
* 统计用户指定情绪类型的记录数量
*/
Long countByUserIdAndEmotionType(String userId, String emotionType);
/**
* 查询用户最近的情绪记录
*/
List<EmotionRecord> getRecentByUserId(String userId, Integer limit);
/**
* 查询用户的平均情绪强度
*/
Double getAvgIntensityByUserId(String userId);
/**
* 查询用户指定时间段的平均情绪强度
*/
Double getAvgIntensityByUserIdAndTimeRange(String userId, LocalDateTime startTime, LocalDateTime endTime);
/**
* 查询用户最常见的情绪类型
*/
String getMostFrequentEmotionByUserId(String userId);
/**
* 查询高强度情绪记录
*/
List<EmotionRecord> getHighIntensityRecords(Double minIntensity);
/**
* 根据触发因素查询情绪记录
*/
List<EmotionRecord> getByTrigger(String trigger);
/**
* 根据地点查询情绪记录
*/
List<EmotionRecord> getByLocation(String location);
/**
* 创建情绪记录
*/
@@ -154,9 +74,4 @@ public interface EmotionRecordService extends IService<EmotionRecord> {
* 获取用户情绪统计
*/
Map<String, Object> getEmotionStats(String userId, String startDate, String endDate);
/**
* 查询用户最近的情绪记录并返回响应
*/
List<EmotionRecordResponse> getRecentByUserIdWithResponse(String userId, Integer limit);
}
@@ -3,6 +3,10 @@ package com.emotion.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.emotion.common.BasePageRequest;
import com.emotion.common.PageResult;
import com.emotion.dto.request.growth.GrowthTopicCreateRequest;
import com.emotion.dto.request.growth.GrowthTopicUpdateRequest;
import com.emotion.dto.response.growth.GrowthTopicResponse;
import com.emotion.entity.GrowthTopic;
import java.time.LocalDateTime;
@@ -12,7 +16,7 @@ import java.util.List;
* 成长话题服务接口
*
* @author emotion-museum
* @date 2025-07-23
* @date 2025-09-08
*/
public interface GrowthTopicService extends IService<GrowthTopic> {
@@ -22,103 +26,33 @@ public interface GrowthTopicService extends IService<GrowthTopic> {
IPage<GrowthTopic> getPage(BasePageRequest request);
/**
* 根据分类查询话题
* 分页查询成长话题响应
*/
List<GrowthTopic> getByCategory(String category);
PageResult<GrowthTopicResponse> getPageWithResponse(BasePageRequest request);
/**
* 根据难度等级查询话题
* 根据ID获取成长话题响应
*/
List<GrowthTopic> getByDifficultyLevel(String difficultyLevel);
/**
* 根据状态查询话题
*/
List<GrowthTopic> getByStatus(String status);
/**
* 查询推荐话题
*/
List<GrowthTopic> getRecommendedTopics(Integer limit);
/**
* 查询热门话题
*/
List<GrowthTopic> getPopularTopics(Integer limit);
/**
* 查询最新话题
*/
List<GrowthTopic> getLatestTopics(Integer limit);
/**
* 根据参与人数范围查询话题
*/
List<GrowthTopic> getByParticipantRange(Integer minParticipants, Integer maxParticipants);
/**
* 根据时间范围查询话题
*/
List<GrowthTopic> getByTimeRange(LocalDateTime startTime, LocalDateTime endTime);
/**
* 统计指定分类的话题数量
*/
Long countByCategory(String category);
/**
* 统计指定状态的话题数量
*/
Long countByStatus(String status);
/**
* 统计指定难度等级的话题数量
*/
Long countByDifficultyLevel(String difficultyLevel);
/**
* 查询平均参与人数
*/
Double getAvgParticipantCount();
/**
* 查询指定分类的平均参与人数
*/
Double getAvgParticipantCountByCategory(String category);
/**
* 根据标签搜索话题
*/
List<GrowthTopic> searchByTags(String tags);
/**
* 根据关键词搜索话题
*/
List<GrowthTopic> searchByKeyword(String keyword);
/**
* 更新话题参与人数
*/
boolean updateParticipantCount(String id, Integer increment);
/**
* 更新话题状态
*/
boolean updateStatus(String id, String status);
/**
* 查询即将结束的话题
*/
List<GrowthTopic> getEndingSoonTopics(Integer days);
/**
* 查询长期话题
*/
List<GrowthTopic> getLongTermTopics();
GrowthTopicResponse getGrowthTopicResponseById(String id);
/**
* 创建成长话题
*/
GrowthTopic createGrowthTopic(String title, String description, String category,
String difficultyLevel, String tags, LocalDateTime endTime);
GrowthTopic createGrowthTopic(String title, String description, String category,
String difficultyLevel, String tags, LocalDateTime endTime);
/**
* 创建成长话题并返回响应
*/
GrowthTopicResponse createGrowthTopicWithResponse(GrowthTopicCreateRequest request);
/**
* 更新成长话题并返回响应
*/
GrowthTopicResponse updateGrowthTopicWithResponse(GrowthTopicUpdateRequest request);
/**
* 删除成长话题
*/
boolean deleteGrowthTopic(String id);
}
@@ -3,6 +3,10 @@ package com.emotion.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.emotion.common.BasePageRequest;
import com.emotion.common.PageResult;
import com.emotion.dto.request.guest.GuestUserCreateRequest;
import com.emotion.dto.request.guest.GuestUserUpdateRequest;
import com.emotion.dto.response.guest.GuestUserResponse;
import com.emotion.entity.GuestUser;
import java.time.LocalDateTime;
@@ -12,7 +16,7 @@ import java.util.List;
* 访客用户服务接口
*
* @author emotion-museum
* @date 2025-07-23
* @date 2025-09-08
*/
public interface GuestUserService extends IService<GuestUser> {
@@ -21,6 +25,16 @@ public interface GuestUserService extends IService<GuestUser> {
*/
IPage<GuestUser> getPage(BasePageRequest request);
/**
* 分页查询访客用户响应
*/
PageResult<GuestUserResponse> getPageWithResponse(BasePageRequest request);
/**
* 根据ID获取访客用户响应
*/
GuestUserResponse getGuestUserResponseById(String id);
/**
* 根据设备ID查询访客用户
*/
@@ -120,4 +134,19 @@ public interface GuestUserService extends IService<GuestUser> {
* 创建访客用户
*/
GuestUser createGuestUser(String deviceId, String ipAddress, String userAgent, String location);
}
/**
* 创建访客用户并返回响应
*/
GuestUserResponse createGuestUserWithResponse(GuestUserCreateRequest request);
/**
* 更新访客用户并返回响应
*/
GuestUserResponse updateGuestUserWithResponse(GuestUserUpdateRequest request);
/**
* 删除访客用户
*/
boolean deleteGuestUser(String id);
}
@@ -18,7 +18,7 @@ import java.util.List;
* 消息服务接口
*
* @author emotion-museum
* @date 2025-07-23
* @date 2025-09-08
*/
public interface MessageService extends IService<Message> {
@@ -27,6 +27,11 @@ public interface MessageService extends IService<Message> {
*/
IPage<Message> getPage(BasePageRequest request);
/**
* 分页查询消息响应
*/
PageResult<MessageResponse> getPageWithResponse(MessagePageRequest request);
/**
* 根据会话ID分页查询消息
*/
@@ -141,4 +146,24 @@ public interface MessageService extends IService<Message> {
* 根据ID获取消息响应(新接口)
*/
MessageResponse getMessageById(String id);
}
/**
* 搜索消息并返回响应
*/
PageResult<MessageResponse> searchWithResponse(MessageSearchRequest request);
/**
* 获取最近消息并返回响应
*/
PageResult<MessageResponse> getRecentWithResponse(MessageRecentRequest request);
/**
* 更新消息
*/
MessageResponse updateMessage(String id, String content);
/**
* 删除消息
*/
boolean deleteMessage(String id);
}
@@ -3,6 +3,10 @@ package com.emotion.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.emotion.common.BasePageRequest;
import com.emotion.common.PageResult;
import com.emotion.dto.request.reward.RewardCreateRequest;
import com.emotion.dto.request.reward.RewardUpdateRequest;
import com.emotion.dto.response.reward.RewardResponse;
import com.emotion.entity.Reward;
import java.time.LocalDateTime;
@@ -12,7 +16,7 @@ import java.util.List;
* 奖励服务接口
*
* @author emotion-museum
* @date 2025-07-23
* @date 2025-09-08
*/
public interface RewardService extends IService<Reward> {
@@ -21,11 +25,21 @@ public interface RewardService extends IService<Reward> {
*/
IPage<Reward> getPage(BasePageRequest request);
/**
* 分页查询奖励响应
*/
PageResult<RewardResponse> getPageWithResponse(BasePageRequest request);
/**
* 根据用户ID分页查询奖励
*/
IPage<Reward> getPageByUserId(BasePageRequest request, String userId);
/**
* 根据ID获取奖励响应
*/
RewardResponse getRewardResponseById(String id);
/**
* 根据用户ID查询奖励
*/
@@ -139,6 +153,21 @@ public interface RewardService extends IService<Reward> {
/**
* 创建奖励
*/
Reward createReward(String userId, String rewardType, Integer points, String source,
String description, LocalDateTime expiredTime);
}
Reward createReward(String userId, String rewardType, String value,
String description, String topicId, String achievementId, String icon, String rarity);
/**
* 创建奖励并返回响应
*/
RewardResponse createRewardWithResponse(RewardCreateRequest request);
/**
* 更新奖励并返回响应
*/
RewardResponse updateRewardWithResponse(RewardUpdateRequest request);
/**
* 删除奖励
*/
boolean deleteReward(String id);
}
@@ -2,12 +2,13 @@ package com.emotion.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.emotion.common.BasePageRequest;
import com.emotion.common.PageResult;
import com.emotion.dto.request.TopicInteractionCreateRequest;
import com.emotion.dto.request.TopicInteractionPageRequest;
import com.emotion.dto.request.TopicInteractionUpdateRequest;
import com.emotion.dto.response.TopicInteractionResponse;
import com.emotion.entity.TopicInteraction;
import java.time.LocalDateTime;
import java.util.List;
/**
* 话题互动服务接口
*
@@ -19,131 +20,25 @@ public interface TopicInteractionService extends IService<TopicInteraction> {
/**
* 分页查询话题互动
*/
IPage<TopicInteraction> getPage(BasePageRequest request);
PageResult<TopicInteractionResponse> getPageWithResponse(TopicInteractionPageRequest request);
/**
* 根据话题ID分页查询互动
* 根据ID获取话题互动响应对象
*/
IPage<TopicInteraction> getPageByTopicId(BasePageRequest request, String topicId);
/**
* 根据用户ID分页查询互动
*/
IPage<TopicInteraction> getPageByUserId(BasePageRequest request, String userId);
/**
* 根据话题ID查询互动
*/
List<TopicInteraction> getByTopicId(String topicId);
/**
* 根据用户ID查询互动
*/
List<TopicInteraction> getByUserId(String userId);
/**
* 根据互动类型查询互动
*/
List<TopicInteraction> getByInteractionType(String interactionType);
/**
* 根据话题ID和互动类型查询互动
*/
List<TopicInteraction> getByTopicIdAndInteractionType(String topicId, String interactionType);
/**
* 根据用户ID和互动类型查询互动
*/
List<TopicInteraction> getByUserIdAndInteractionType(String userId, String interactionType);
/**
* 根据话题ID和用户ID查询互动
*/
List<TopicInteraction> getByTopicIdAndUserId(String topicId, String userId);
/**
* 根据时间范围查询互动
*/
List<TopicInteraction> getByTimeRange(LocalDateTime startTime, LocalDateTime endTime);
/**
* 统计话题的互动数量
*/
Long countByTopicId(String topicId);
/**
* 统计用户的互动数量
*/
Long countByUserId(String userId);
/**
* 统计指定类型的互动数量
*/
Long countByInteractionType(String interactionType);
/**
* 统计话题指定类型的互动数量
*/
Long countByTopicIdAndInteractionType(String topicId, String interactionType);
/**
* 统计用户指定类型的互动数量
*/
Long countByUserIdAndInteractionType(String userId, String interactionType);
/**
* 查询话题最近的互动
*/
List<TopicInteraction> getRecentByTopicId(String topicId, Integer limit);
/**
* 查询用户最近的互动
*/
List<TopicInteraction> getRecentByUserId(String userId, Integer limit);
/**
* 查询热门互动(按点赞数排序)
*/
List<TopicInteraction> getPopularInteractions(Integer limit);
/**
* 查询话题的热门互动
*/
List<TopicInteraction> getPopularInteractionsByTopicId(String topicId, Integer limit);
/**
* 根据点赞数范围查询互动
*/
List<TopicInteraction> getByLikesRange(Integer minLikes, Integer maxLikes);
/**
* 查询用户是否已参与话题
*/
boolean hasUserInteracted(String topicId, String userId);
/**
* 查询用户在话题中的特定互动类型
*/
TopicInteraction getUserInteractionByType(String topicId, String userId, String interactionType);
/**
* 更新互动点赞数
*/
boolean updateLikes(String id, Integer increment);
/**
* 根据内容关键词搜索互动
*/
List<TopicInteraction> searchByContent(String keyword);
/**
* 根据话题ID和内容关键词搜索互动
*/
List<TopicInteraction> searchByTopicIdAndContent(String topicId, String keyword);
TopicInteractionResponse getTopicInteractionResponseById(String id);
/**
* 创建话题互动
*/
TopicInteraction createTopicInteraction(String topicId, String userId, String interactionType,
String content, String attachments);
TopicInteractionResponse createTopicInteractionWithResponse(TopicInteractionCreateRequest request);
/**
* 更新话题互动
*/
TopicInteractionResponse updateTopicInteractionWithResponse(TopicInteractionUpdateRequest request);
/**
* 删除话题互动
*/
boolean deleteTopicInteraction(String id);
}
@@ -1,13 +1,14 @@
package com.emotion.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.emotion.common.BasePageRequest;
import com.emotion.common.PageResult;
import com.emotion.dto.request.UserCreateRequest;
import com.emotion.dto.request.UserPageRequest;
import com.emotion.dto.request.UserUpdateRequest;
import com.emotion.dto.request.UserProfileUpdateRequest;
import com.emotion.dto.response.UserResponse;
import com.emotion.entity.User;
import java.time.LocalDateTime;
import java.util.List;
/**
* 用户服务接口
*
@@ -17,92 +18,37 @@ import java.util.List;
public interface UserService extends IService<User> {
/**
* 分页查询用户
* 分页查询用户响应
*/
IPage<User> getPage(BasePageRequest request);
PageResult<UserResponse> getPageWithResponse(UserPageRequest request);
/**
* 根据账号查询用户
* 根据ID获取用户响应
*/
User getByAccount(String account);
UserResponse getUserResponseById(String id);
/**
* 根据用户名查询用户
* 创建用户并返回响应
*/
User getByUsername(String username);
UserResponse createUserWithResponse(UserCreateRequest request);
/**
* 根据邮箱查询用户
* 更新用户并返回响应
*/
User getByEmail(String email);
UserResponse updateUserWithResponse(UserUpdateRequest request);
/**
* 根据手机号查询用户
* 更新当前用户个人资料并返回响应
*/
User getByPhone(String phone);
UserResponse updateCurrentUserProfileWithResponse(UserProfileUpdateRequest request);
/**
* 根据第三方平台信息查询用户
* 获取当前用户个人资料并返回响应
*/
User getByThirdParty(String thirdPartyId, String thirdPartyType);
UserResponse getCurrentUserProfileWithResponse();
/**
* 根据状态查询用户列表
* 删除用户
*/
List<User> getByStatus(Integer status);
/**
* 根据会员等级查询用户列表
*/
List<User> getByMemberLevel(String memberLevel);
/**
* 查询活跃用户(最近N天有活动)
*/
List<User> getActiveUsers(Integer days);
/**
* 查询新注册用户(最近N天注册)
*/
List<User> getNewUsers(Integer days);
/**
* 更新用户最后活跃时间
*/
boolean updateLastActiveTime(String userId, LocalDateTime lastActiveTime);
/**
* 更新用户状态
*/
boolean updateStatus(String userId, Integer status);
/**
* 更新用户使用天数
*/
boolean updateTotalDays(String userId, Integer totalDays);
/**
* 统计指定状态的用户数量
*/
Long countByStatus(Integer status);
/**
* 统计指定会员等级的用户数量
*/
Long countByMemberLevel(String memberLevel);
/**
* 创建用户
*/
User createUser(String account, String username, String password, String email, String phone);
/**
* 验证用户密码
*/
boolean validatePassword(String userId, String password);
/**
* 更新用户密码
*/
boolean updatePassword(String userId, String newPassword);
}
boolean deleteUser(String id);
}
@@ -1,11 +1,14 @@
package com.emotion.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.emotion.common.BasePageRequest;
import com.emotion.common.PageResult;
import com.emotion.dto.request.UserStatsCreateRequest;
import com.emotion.dto.request.UserStatsIncrementRequest;
import com.emotion.dto.request.UserStatsPageRequest;
import com.emotion.dto.request.UserStatsUpdateValueRequest;
import com.emotion.dto.response.UserStatsResponse;
import com.emotion.entity.UserStats;
import java.time.LocalDateTime;
import java.util.List;
/**
@@ -17,84 +20,19 @@ import java.util.List;
public interface UserStatsService extends IService<UserStats> {
/**
* 分页查询用户统计
* 分页查询用户统计响应
*/
IPage<UserStats> getPage(BasePageRequest request);
/**
* 根据用户ID查询统计信息
*/
UserStats getByUserId(String userId);
/**
* 根据统计类型查询统计信息
*/
List<UserStats> getByStatsType(String statsType);
/**
* 根据用户ID和统计类型查询统计信息
*/
UserStats getByUserIdAndStatsType(String userId, String statsType);
/**
* 根据时间范围查询统计信息
*/
List<UserStats> getByTimeRange(LocalDateTime startTime, LocalDateTime endTime);
/**
* 根据数值范围查询统计信息
*/
List<UserStats> getByValueRange(Double minValue, Double maxValue);
/**
* 统计指定类型的记录数量
*/
Long countByStatsType(String statsType);
/**
* 查询平均统计值
*/
Double getAvgValueByStatsType(String statsType);
/**
* 查询最大统计值
*/
Double getMaxValueByStatsType(String statsType);
/**
* 查询最小统计值
*/
Double getMinValueByStatsType(String statsType);
/**
* 查询用户的所有统计类型
*/
List<UserStats> getAllStatsByUserId(String userId);
/**
* 查询排名前N的用户统计
*/
List<UserStats> getTopUsersByStatsType(String statsType, Integer limit);
/**
* 查询用户在指定统计类型中的排名
*/
Long getUserRankByStatsType(String userId, String statsType);
PageResult<UserStatsResponse> getPageWithResponse(UserStatsPageRequest request);
/**
* 更新用户统计值
*/
boolean updateStatsValue(String userId, String statsType, Double value);
boolean updateStatsValue(UserStatsUpdateValueRequest request);
/**
* 增加用户统计值
*/
boolean incrementStatsValue(String userId, String statsType, Double increment);
/**
* 批量更新用户统计
*/
boolean batchUpdateStats(String userId, List<UserStats> statsList);
boolean incrementStatsValue(UserStatsIncrementRequest request);
/**
* 重新计算用户统计
@@ -107,22 +45,12 @@ public interface UserStatsService extends IService<UserStats> {
boolean recalculateAllUserStats();
/**
* 根据周期查询统计信息
* 创建或更新用户统计响应
*/
List<UserStats> getByPeriod(String period);
/**
* 根据用户ID和周期查询统计信息
*/
List<UserStats> getByUserIdAndPeriod(String userId, String period);
/**
* 创建或更新用户统计
*/
UserStats createOrUpdateUserStats(String userId, String statsType, Double value, String period);
UserStatsResponse createOrUpdateUserStatsWithResponse(UserStatsCreateRequest request);
/**
* 删除过期的统计数据
*/
boolean deleteExpiredStats(Integer days);
}
}
@@ -655,6 +655,77 @@ public class AiChatServiceImpl implements AiChatService {
}
}
@Override
public EmotionSummaryGenerateResponse generateEmotionSummaryWithResponse(String userId) {
log.info("生成用户情绪记录总结: userId={}", userId);
// 调用原有的generateEmotionSummary方法
Map<String, Object> result = generateEmotionSummary(userId);
// 转换为响应对象
return convertToGenerateResponse(result);
}
@Override
public EmotionSummaryStatusResponse getEmotionSummaryStatusWithResponse(String userId) {
log.info("获取用户情绪记录总结状态: userId={}", userId);
// 构建状态信息
Map<String, Object> statusInfo = Map.of(
"userId", userId,
"canGenerate", true,
"message", "可以生成情绪记录总结");
// 转换为响应对象
return convertToStatusResponse(statusInfo);
}
/**
* 转换为生成响应对象
*/
private EmotionSummaryGenerateResponse convertToGenerateResponse(Map<String, Object> result) {
EmotionSummaryGenerateResponse response = new EmotionSummaryGenerateResponse();
response.setSuccess((Boolean) result.get("success"));
response.setMessage((String) result.get("message"));
if (result.containsKey("emotionRecord") && result.get("emotionRecord") != null) {
// 从实际的EmotionRecord对象获取ID
Object emotionRecord = result.get("emotionRecord");
if (emotionRecord instanceof EmotionRecord) {
response.setEmotionRecordId(((EmotionRecord) emotionRecord).getId());
}
}
if (result.containsKey("analysisResult") && result.get("analysisResult") != null) {
// 从实际的EmotionAnalysis对象获取ID
Object analysisResult = result.get("analysisResult");
if (analysisResult instanceof EmotionAnalysis) {
response.setEmotionAnalysisId(((EmotionAnalysis) analysisResult).getId());
}
}
if (result.containsKey("messageCount")) {
response.setMessageCount((Integer) result.get("messageCount"));
}
if (result.containsKey("recordDate")) {
response.setRecordDate(result.get("recordDate").toString());
}
return response;
}
/**
* 转换为状态响应对象
*/
private EmotionSummaryStatusResponse convertToStatusResponse(Map<String, Object> statusInfo) {
EmotionSummaryStatusResponse response = new EmotionSummaryStatusResponse();
response.setUserId((String) statusInfo.get("userId"));
response.setCanGenerate((Boolean) statusInfo.get("canGenerate"));
response.setMessage((String) statusInfo.get("message"));
return response;
}
public boolean isServiceAvailable() {
try {
// 简单的健康检查
@@ -67,172 +67,6 @@ public class EmotionRecordServiceImpl extends ServiceImpl<EmotionRecordMapper, E
return this.page(page, wrapper);
}
@Override
public List<EmotionRecord> getByUserId(String userId) {
LambdaQueryWrapper<EmotionRecord> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(EmotionRecord::getUserId, userId)
.eq(EmotionRecord::getIsDeleted, 0)
.orderByDesc(EmotionRecord::getCreateTime);
return this.list(wrapper);
}
@Override
public List<EmotionRecord> getByEmotionType(String emotionType) {
LambdaQueryWrapper<EmotionRecord> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(EmotionRecord::getEmotionType, emotionType)
.eq(EmotionRecord::getIsDeleted, 0)
.orderByDesc(EmotionRecord::getCreateTime);
return this.list(wrapper);
}
@Override
public List<EmotionRecord> getByUserIdAndEmotionType(String userId, String emotionType) {
LambdaQueryWrapper<EmotionRecord> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(EmotionRecord::getUserId, userId)
.eq(EmotionRecord::getEmotionType, emotionType)
.eq(EmotionRecord::getIsDeleted, 0)
.orderByDesc(EmotionRecord::getCreateTime);
return this.list(wrapper);
}
@Override
public List<EmotionRecord> getByUserIdAndTimeRange(String userId, LocalDateTime startTime, LocalDateTime endTime) {
LambdaQueryWrapper<EmotionRecord> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(EmotionRecord::getUserId, userId)
.between(EmotionRecord::getCreateTime, startTime, endTime)
.eq(EmotionRecord::getIsDeleted, 0)
.orderByDesc(EmotionRecord::getCreateTime);
return this.list(wrapper);
}
@Override
public List<EmotionRecord> getByIntensityRange(Double minIntensity, Double maxIntensity) {
LambdaQueryWrapper<EmotionRecord> wrapper = new LambdaQueryWrapper<>();
wrapper.between(EmotionRecord::getIntensity, BigDecimal.valueOf(minIntensity), BigDecimal.valueOf(maxIntensity))
.eq(EmotionRecord::getIsDeleted, 0)
.orderByDesc(EmotionRecord::getIntensity);
return this.list(wrapper);
}
@Override
public Long countByUserId(String userId) {
LambdaQueryWrapper<EmotionRecord> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(EmotionRecord::getUserId, userId)
.eq(EmotionRecord::getIsDeleted, 0);
return this.count(wrapper);
}
@Override
public Long countByEmotionType(String emotionType) {
LambdaQueryWrapper<EmotionRecord> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(EmotionRecord::getEmotionType, emotionType)
.eq(EmotionRecord::getIsDeleted, 0);
return this.count(wrapper);
}
@Override
public Long countByUserIdAndEmotionType(String userId, String emotionType) {
LambdaQueryWrapper<EmotionRecord> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(EmotionRecord::getUserId, userId)
.eq(EmotionRecord::getEmotionType, emotionType)
.eq(EmotionRecord::getIsDeleted, 0);
return this.count(wrapper);
}
@Override
public List<EmotionRecord> getRecentByUserId(String userId, Integer limit) {
LambdaQueryWrapper<EmotionRecord> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(EmotionRecord::getUserId, userId)
.eq(EmotionRecord::getIsDeleted, 0)
.orderByDesc(EmotionRecord::getCreateTime)
.last("LIMIT " + limit);
return this.list(wrapper);
}
@Override
public Double getAvgIntensityByUserId(String userId) {
LambdaQueryWrapper<EmotionRecord> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(EmotionRecord::getUserId, userId)
.eq(EmotionRecord::getIsDeleted, 0);
List<EmotionRecord> records = this.list(wrapper);
if (records.isEmpty()) {
return 0.0;
}
double sum = records.stream()
.mapToDouble(record -> record.getIntensity().doubleValue())
.sum();
return sum / records.size();
}
@Override
public Double getAvgIntensityByUserIdAndTimeRange(String userId, LocalDateTime startTime, LocalDateTime endTime) {
LambdaQueryWrapper<EmotionRecord> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(EmotionRecord::getUserId, userId)
.between(EmotionRecord::getCreateTime, startTime, endTime)
.eq(EmotionRecord::getIsDeleted, 0);
List<EmotionRecord> records = this.list(wrapper);
if (records.isEmpty()) {
return 0.0;
}
double sum = records.stream()
.mapToDouble(record -> record.getIntensity().doubleValue())
.sum();
return sum / records.size();
}
@Override
public String getMostFrequentEmotionByUserId(String userId) {
LambdaQueryWrapper<EmotionRecord> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(EmotionRecord::getUserId, userId)
.eq(EmotionRecord::getIsDeleted, 0);
List<EmotionRecord> records = this.list(wrapper);
if (records.isEmpty()) {
return null;
}
return records.stream()
.collect(Collectors.groupingBy(EmotionRecord::getEmotionType, Collectors.counting()))
.entrySet()
.stream()
.max(Map.Entry.comparingByValue())
.map(Map.Entry::getKey)
.orElse(null);
}
@Override
public List<EmotionRecord> getHighIntensityRecords(Double minIntensity) {
LambdaQueryWrapper<EmotionRecord> wrapper = new LambdaQueryWrapper<>();
wrapper.ge(EmotionRecord::getIntensity, BigDecimal.valueOf(minIntensity))
.eq(EmotionRecord::getIsDeleted, 0)
.orderByDesc(EmotionRecord::getIntensity);
return this.list(wrapper);
}
@Override
public List<EmotionRecord> getByTrigger(String trigger) {
LambdaQueryWrapper<EmotionRecord> wrapper = new LambdaQueryWrapper<>();
wrapper.like(EmotionRecord::getTriggers, trigger)
.eq(EmotionRecord::getIsDeleted, 0)
.orderByDesc(EmotionRecord::getCreateTime);
return this.list(wrapper);
}
@Override
public List<EmotionRecord> getByLocation(String location) {
LambdaQueryWrapper<EmotionRecord> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(EmotionRecord::getLocation, location)
.eq(EmotionRecord::getIsDeleted, 0)
.orderByDesc(EmotionRecord::getCreateTime);
return this.list(wrapper);
}
@Override
public EmotionRecord createEmotionRecord(String userId, String emotionType, Double intensity,
String trigger, String location, String notes) {
@@ -250,18 +84,6 @@ public class EmotionRecordServiceImpl extends ServiceImpl<EmotionRecordMapper, E
return record;
}
@Override
public IPage<EmotionRecord> getByUserIdWithPage(String userId, Integer current, Integer size) {
Page<EmotionRecord> page = new Page<>(current, size);
LambdaQueryWrapper<EmotionRecord> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(EmotionRecord::getUserId, userId)
.eq(EmotionRecord::getIsDeleted, 0)
.orderByDesc(EmotionRecord::getCreateTime);
return this.page(page, wrapper);
}
// 新增的方法实现
@Override
@@ -457,14 +279,6 @@ public class EmotionRecordServiceImpl extends ServiceImpl<EmotionRecordMapper, E
return stats;
}
@Override
public List<EmotionRecordResponse> getRecentByUserIdWithResponse(String userId, Integer limit) {
List<EmotionRecord> records = getRecentByUserId(userId, limit);
return records.stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
}
/**
* 转换为响应对象
*/
@@ -5,9 +5,14 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.emotion.common.BasePageRequest;
import com.emotion.common.PageResult;
import com.emotion.dto.request.growth.GrowthTopicCreateRequest;
import com.emotion.dto.request.growth.GrowthTopicUpdateRequest;
import com.emotion.dto.response.growth.GrowthTopicResponse;
import com.emotion.entity.GrowthTopic;
import com.emotion.mapper.GrowthTopicMapper;
import com.emotion.service.GrowthTopicService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
@@ -15,12 +20,13 @@ import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
/**
* 成长话题服务实现类
*
* @author emotion-museum
* @date 2025-07-24
* @date 2025-09-08
*/
@Service
public class GrowthTopicServiceImpl extends ServiceImpl<GrowthTopicMapper, GrowthTopic> implements GrowthTopicService {
@@ -53,149 +59,31 @@ public class GrowthTopicServiceImpl extends ServiceImpl<GrowthTopicMapper, Growt
}
@Override
public List<GrowthTopic> getByCategory(String category) {
LambdaQueryWrapper<GrowthTopic> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(GrowthTopic::getCategory, category)
.eq(GrowthTopic::getIsDeleted, 0)
.orderByDesc(GrowthTopic::getCreateTime);
return this.list(wrapper);
public PageResult<GrowthTopicResponse> getPageWithResponse(BasePageRequest request) {
IPage<GrowthTopic> page = getPage(request);
List<GrowthTopicResponse> responses = page.getRecords().stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
PageResult<GrowthTopicResponse> pageResult = new PageResult<>();
pageResult.setRecords(responses);
pageResult.setCurrent(page.getCurrent());
pageResult.setSize(page.getSize());
pageResult.setTotal(page.getTotal());
pageResult.setPages(page.getPages());
return pageResult;
}
@Override
public List<GrowthTopic> getByDifficultyLevel(String difficultyLevel) {
LambdaQueryWrapper<GrowthTopic> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(GrowthTopic::getDifficulty, difficultyLevel)
.eq(GrowthTopic::getIsDeleted, 0)
.orderByDesc(GrowthTopic::getCreateTime);
return this.list(wrapper);
public GrowthTopicResponse getGrowthTopicResponseById(String id) {
GrowthTopic topic = this.getById(id);
if (topic == null || topic.getIsDeleted() == 1) {
return null;
}
return convertToResponse(topic);
}
@Override
public List<GrowthTopic> getByStatus(String status) {
// GrowthTopic实体中没有status字段,暂时返回空列表
return Collections.emptyList();
}
@Override
public List<GrowthTopic> getRecommendedTopics(Integer limit) {
// GrowthTopic实体中没有isRecommended字段,暂时返回最新话题
LambdaQueryWrapper<GrowthTopic> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(GrowthTopic::getIsDeleted, 0)
.orderByDesc(GrowthTopic::getCreateTime)
.last("LIMIT " + limit);
return this.list(wrapper);
}
@Override
public List<GrowthTopic> getPopularTopics(Integer limit) {
// GrowthTopic实体中没有participantCount字段,暂时返回最新话题
LambdaQueryWrapper<GrowthTopic> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(GrowthTopic::getIsDeleted, 0)
.orderByDesc(GrowthTopic::getCreateTime)
.last("LIMIT " + limit);
return this.list(wrapper);
}
@Override
public List<GrowthTopic> getLatestTopics(Integer limit) {
LambdaQueryWrapper<GrowthTopic> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(GrowthTopic::getIsDeleted, 0)
.orderByDesc(GrowthTopic::getCreateTime)
.last("LIMIT " + limit);
return this.list(wrapper);
}
@Override
public List<GrowthTopic> getByParticipantRange(Integer minParticipants, Integer maxParticipants) {
// GrowthTopic实体中没有participantCount字段,暂时返回空列表
return Collections.emptyList();
}
@Override
public List<GrowthTopic> getByTimeRange(LocalDateTime startTime, LocalDateTime endTime) {
LambdaQueryWrapper<GrowthTopic> wrapper = new LambdaQueryWrapper<>();
wrapper.between(GrowthTopic::getCreateTime, startTime, endTime)
.eq(GrowthTopic::getIsDeleted, 0)
.orderByDesc(GrowthTopic::getCreateTime);
return this.list(wrapper);
}
@Override
public Long countByCategory(String category) {
LambdaQueryWrapper<GrowthTopic> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(GrowthTopic::getCategory, category)
.eq(GrowthTopic::getIsDeleted, 0);
return this.count(wrapper);
}
@Override
public Long countByStatus(String status) {
// GrowthTopic实体中没有status字段,暂时返回0
return 0L;
}
@Override
public Long countByDifficultyLevel(String difficultyLevel) {
LambdaQueryWrapper<GrowthTopic> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(GrowthTopic::getDifficulty, difficultyLevel)
.eq(GrowthTopic::getIsDeleted, 0);
return this.count(wrapper);
}
@Override
public Double getAvgParticipantCount() {
// 这里需要自定义SQL查询平均值,暂时返回0
return 0.0;
}
@Override
public Double getAvgParticipantCountByCategory(String category) {
// 这里需要自定义SQL查询平均值,暂时返回0
return 0.0;
}
@Override
public List<GrowthTopic> searchByTags(String tags) {
// GrowthTopic实体中没有tags字段,暂时返回空列表
return Collections.emptyList();
}
@Override
public List<GrowthTopic> searchByKeyword(String keyword) {
LambdaQueryWrapper<GrowthTopic> wrapper = new LambdaQueryWrapper<>();
wrapper.and(w -> w.like(GrowthTopic::getTitle, keyword)
.or().like(GrowthTopic::getDescription, keyword))
.eq(GrowthTopic::getIsDeleted, 0)
.orderByDesc(GrowthTopic::getCreateTime);
return this.list(wrapper);
}
@Override
public boolean updateParticipantCount(String id, Integer increment) {
// GrowthTopic实体中没有participantCount字段,暂时返回false
return false;
}
@Override
public boolean updateStatus(String id, String status) {
// GrowthTopic实体中没有status字段,暂时返回false
return false;
}
@Override
public List<GrowthTopic> getEndingSoonTopics(Integer days) {
// GrowthTopic实体中没有endTime字段,暂时返回空列表
return Collections.emptyList();
}
@Override
public List<GrowthTopic> getLongTermTopics() {
// GrowthTopic实体中没有endTime字段,暂时返回空列表
return Collections.emptyList();
}
@Override
public GrowthTopic createGrowthTopic(String title, String description, String category,
public GrowthTopic createGrowthTopic(String title, String description, String category,
String difficultyLevel, String tags, LocalDateTime endTime) {
GrowthTopic topic = new GrowthTopic();
topic.setTitle(title);
@@ -211,4 +99,80 @@ public class GrowthTopicServiceImpl extends ServiceImpl<GrowthTopicMapper, Growt
this.save(topic);
return topic;
}
@Override
public GrowthTopicResponse createGrowthTopicWithResponse(GrowthTopicCreateRequest request) {
GrowthTopic topic = createGrowthTopic(
request.getTitle(),
request.getDescription(),
request.getCategory(),
request.getDifficultyLevel(),
request.getTags(),
request.getEndTime());
return convertToResponse(topic);
}
@Override
public GrowthTopicResponse updateGrowthTopicWithResponse(GrowthTopicUpdateRequest request) {
GrowthTopic topic = this.getById(request.getId());
if (topic == null || topic.getIsDeleted() == 1) {
return null;
}
// 只更新非空字段
if (StringUtils.hasText(request.getTitle())) {
topic.setTitle(request.getTitle());
}
if (StringUtils.hasText(request.getDescription())) {
topic.setDescription(request.getDescription());
topic.setContent(request.getDescription());
}
if (StringUtils.hasText(request.getCategory())) {
topic.setCategory(request.getCategory());
}
if (StringUtils.hasText(request.getDifficultyLevel())) {
topic.setDifficulty(request.getDifficultyLevel());
}
if (StringUtils.hasText(request.getTags())) {
// GrowthTopic实体中没有tags字段,暂时忽略
}
if (request.getEndTime() != null) {
// GrowthTopic实体中没有endTime字段,暂时忽略
}
this.updateById(topic);
return convertToResponse(topic);
}
@Override
public boolean deleteGrowthTopic(String id) {
GrowthTopic topic = this.getById(id);
if (topic == null || topic.getIsDeleted() == 1) {
return false;
}
// 逻辑删除
topic.setIsDeleted(1);
return this.updateById(topic);
}
/**
* 将实体转换为响应对象
*/
private GrowthTopicResponse convertToResponse(GrowthTopic topic) {
if (topic == null) {
return null;
}
GrowthTopicResponse response = new GrowthTopicResponse();
BeanUtils.copyProperties(topic, response);
response.setId(topic.getId());
if (topic.getCreateTime() != null) {
response.setCreateTime(topic.getCreateTime().toString());
}
if (topic.getUpdateTime() != null) {
response.setUpdateTime(topic.getUpdateTime().toString());
}
return response;
}
}
@@ -5,21 +5,27 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.emotion.common.BasePageRequest;
import com.emotion.common.PageResult;
import com.emotion.dto.request.guest.GuestUserCreateRequest;
import com.emotion.dto.request.guest.GuestUserUpdateRequest;
import com.emotion.dto.response.guest.GuestUserResponse;
import com.emotion.entity.GuestUser;
import com.emotion.mapper.GuestUserMapper;
import com.emotion.service.GuestUserService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
/**
* 访客用户服务实现类
*
* @author emotion-museum
* @date 2025-07-24
* @date 2025-09-08
*/
@Service
public class GuestUserServiceImpl extends ServiceImpl<GuestUserMapper, GuestUser> implements GuestUserService {
@@ -37,6 +43,30 @@ public class GuestUserServiceImpl extends ServiceImpl<GuestUserMapper, GuestUser
return this.page(page, wrapper);
}
@Override
public PageResult<GuestUserResponse> getPageWithResponse(BasePageRequest request) {
IPage<GuestUser> page = getPage(request);
List<GuestUserResponse> responses = page.getRecords().stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
PageResult<GuestUserResponse> pageResult = new PageResult<>();
pageResult.setRecords(responses);
pageResult.setCurrent(page.getCurrent());
pageResult.setSize(page.getSize());
pageResult.setTotal(page.getTotal());
pageResult.setPages(page.getPages());
return pageResult;
}
@Override
public GuestUserResponse getGuestUserResponseById(String id) {
GuestUser guestUser = this.getById(id);
if (guestUser == null || guestUser.getIsDeleted() == 1) {
return null;
}
return convertToResponse(guestUser);
}
@Override
public GuestUser getByDeviceId(String deviceId) {
LambdaQueryWrapper<GuestUser> wrapper = new LambdaQueryWrapper<>();
@@ -219,4 +249,68 @@ public class GuestUserServiceImpl extends ServiceImpl<GuestUserMapper, GuestUser
this.save(guestUser);
return guestUser;
}
@Override
public GuestUserResponse createGuestUserWithResponse(GuestUserCreateRequest request) {
GuestUser guestUser = createGuestUser(
request.getDeviceId(),
request.getIpAddress(),
request.getUserAgent(),
request.getLocation());
return convertToResponse(guestUser);
}
@Override
public GuestUserResponse updateGuestUserWithResponse(GuestUserUpdateRequest request) {
GuestUser guestUser = this.getById(request.getId());
if (guestUser == null || guestUser.getIsDeleted() == 1) {
return null;
}
// 只更新非空字段
if (StringUtils.hasText(request.getNickname())) {
guestUser.setNickname(request.getNickname());
}
if (StringUtils.hasText(request.getAvatar())) {
guestUser.setAvatar(request.getAvatar());
}
if (StringUtils.hasText(request.getLocation())) {
guestUser.setLocation(request.getLocation());
}
this.updateById(guestUser);
return convertToResponse(guestUser);
}
@Override
public boolean deleteGuestUser(String id) {
GuestUser guestUser = this.getById(id);
if (guestUser == null || guestUser.getIsDeleted() == 1) {
return false;
}
// 逻辑删除
guestUser.setIsDeleted(1);
return this.updateById(guestUser);
}
/**
* 将实体转换为响应对象
*/
private GuestUserResponse convertToResponse(GuestUser guestUser) {
if (guestUser == null) {
return null;
}
GuestUserResponse response = new GuestUserResponse();
BeanUtils.copyProperties(guestUser, response);
response.setId(guestUser.getId());
if (guestUser.getCreateTime() != null) {
response.setCreateTime(guestUser.getCreateTime().toString());
}
if (guestUser.getUpdateTime() != null) {
response.setUpdateTime(guestUser.getUpdateTime().toString());
}
return response;
}
}
@@ -29,7 +29,7 @@ import java.util.stream.Collectors;
* 消息服务实现类
*
* @author emotion-museum
* @date 2025-07-24
* @date 2025-09-08
*/
@Slf4j
@Service
@@ -50,6 +50,16 @@ public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> impl
return this.page(page, wrapper);
}
@Override
public PageResult<MessageResponse> getPageWithResponse(MessagePageRequest request) {
// 从上下文中获取当前用户ID
String userId = CurrentUserUtil.requireCurrentUserId();
// 调用用户消息分页查询方法
PageResult<MessageResponse> pageResult = getUserMessagesWithPage(request);
return pageResult;
}
@Override
public IPage<Message> getPageByConversationId(BasePageRequest request, String conversationId) {
Page<Message> page = new Page<>(request.getCurrent(), request.getSize());
@@ -218,18 +228,13 @@ public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> impl
@Override
public PageResult<MessageResponse> getUserMessagesWithPage(MessagePageRequest request) {
log.info("获取用户消息分页: current={}, size={}", request.getCurrent(), request.getSize());
// 从上下文中获取当前用户ID
String userId = CurrentUserUtil.requireCurrentUserId();
log.info("当前用户ID: {}", userId);
// 调用原有的分页查询方法
IPage<Message> page = getByUserIdWithPage(userId, Math.toIntExact(request.getCurrent()),
Math.toIntExact(request.getSize()));
log.info("查询结果: total={}, records={}", page.getTotal(), page.getRecords().size());
// 转换为响应对象
List<MessageResponse> responses = page.getRecords().stream()
.map(this::convertToResponse)
@@ -248,15 +253,11 @@ public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> impl
@Override
public List<MessageResponse> searchUserMessages(MessageSearchRequest request) {
log.info("搜索用户消息: keyword={}, limit={}", request.getKeyword(), request.getLimit());
// 从上下文中获取当前用户ID
String userId = CurrentUserUtil.requireCurrentUserId();
log.info("当前用户ID: {}", userId);
// 调用原有的搜索方法
List<Message> messages = searchByUserIdAndKeyword(userId, request.getKeyword(), request.getLimit());
log.info("搜索结果: {} 条消息", messages.size());
// 转换为响应对象
return messages.stream()
@@ -266,15 +267,11 @@ public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> impl
@Override
public List<MessageResponse> getUserRecentMessages(MessageRecentRequest request) {
log.info("获取用户最近消息: limit={}", request.getLimit());
// 从上下文中获取当前用户ID
String userId = CurrentUserUtil.requireCurrentUserId();
log.info("当前用户ID: {}", userId);
// 调用原有的获取最近消息方法
List<Message> messages = getRecentByUserId(userId, request.getLimit());
log.info("查询结果: {} 条最近消息", messages.size());
// 转换为响应对象
return messages.stream()
@@ -284,11 +281,8 @@ public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> impl
@Override
public MessageResponse createMessageFromRequest(MessageCreateRequest request) {
log.info("根据请求创建消息: conversationId={}", request.getConversationId());
// 从上下文中获取当前用户ID
String userId = CurrentUserUtil.requireCurrentUserId();
log.info("当前用户ID: {}", userId);
// 构建消息对象
Message message = new Message();
@@ -300,7 +294,6 @@ public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> impl
// 调用原有的创建方法
Message savedMessage = createMessage(message);
log.info("创建消息成功: messageId={}", savedMessage.getId());
// 转换为响应对象
return convertToResponse(savedMessage);
@@ -308,11 +301,8 @@ public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> impl
@Override
public MessageResponse getMessageById(String id) {
log.info("根据ID获取消息: id={}", id);
Message message = getById(id);
if (message == null) {
log.warn("消息不存在: id={}", id);
return null;
}
@@ -320,6 +310,95 @@ public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> impl
return convertToResponse(message);
}
@Override
public PageResult<MessageResponse> searchWithResponse(MessageSearchRequest request) {
// 从上下文中获取当前用户ID
String userId = CurrentUserUtil.requireCurrentUserId();
// 构建分页对象
Page<Message> page = new Page<>(1L, request.getLimit().longValue());
// 调用搜索方法
List<Message> messages = searchByUserIdAndKeyword(userId, request.getKeyword(), request.getLimit());
// 设置分页信息
page.setRecords(messages);
page.setTotal(messages.size());
// 转换为响应对象
List<MessageResponse> responses = messages.stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
// 构建分页结果
PageResult<MessageResponse> pageResult = new PageResult<>();
pageResult.setRecords(responses);
pageResult.setCurrent(page.getCurrent());
pageResult.setSize(page.getSize());
pageResult.setTotal(page.getTotal());
pageResult.setPages(page.getPages());
return pageResult;
}
@Override
public PageResult<MessageResponse> getRecentWithResponse(MessageRecentRequest request) {
// 从上下文中获取当前用户ID
String userId = CurrentUserUtil.requireCurrentUserId();
// 构建分页对象
Page<Message> page = new Page<>(1L, request.getLimit().longValue());
// 调用获取最近消息方法
List<Message> messages = getRecentByUserId(userId, request.getLimit());
// 设置分页信息
page.setRecords(messages);
page.setTotal(messages.size());
// 转换为响应对象
List<MessageResponse> responses = messages.stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
// 构建分页结果
PageResult<MessageResponse> pageResult = new PageResult<>();
pageResult.setRecords(responses);
pageResult.setCurrent(page.getCurrent());
pageResult.setSize(page.getSize());
pageResult.setTotal(page.getTotal());
pageResult.setPages(page.getPages());
return pageResult;
}
@Override
public MessageResponse updateMessage(String id, String content) {
Message message = this.getById(id);
if (message == null || message.getIsDeleted() == 1) {
return null;
}
// 更新内容
message.setContent(content);
this.updateById(message);
// 转换为响应对象
return convertToResponse(message);
}
@Override
public boolean deleteMessage(String id) {
Message message = this.getById(id);
if (message == null || message.getIsDeleted() == 1) {
return false;
}
// 逻辑删除
message.setIsDeleted(1);
return this.updateById(message);
}
/**
* 转换为响应对象
*/
@@ -6,21 +6,27 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.emotion.common.BasePageRequest;
import com.emotion.common.PageResult;
import com.emotion.dto.request.reward.RewardCreateRequest;
import com.emotion.dto.request.reward.RewardUpdateRequest;
import com.emotion.dto.response.reward.RewardResponse;
import com.emotion.entity.Reward;
import com.emotion.mapper.RewardMapper;
import com.emotion.service.RewardService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
/**
* 奖励服务实现类
*
* @author emotion-museum
* @date 2025-07-24
* @date 2025-09-08
*/
@Service
public class RewardServiceImpl extends ServiceImpl<RewardMapper, Reward> implements RewardService {
@@ -52,6 +58,21 @@ public class RewardServiceImpl extends ServiceImpl<RewardMapper, Reward> impleme
return this.page(page, wrapper);
}
@Override
public PageResult<RewardResponse> getPageWithResponse(BasePageRequest request) {
IPage<Reward> page = getPage(request);
List<RewardResponse> responses = page.getRecords().stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
PageResult<RewardResponse> pageResult = new PageResult<>();
pageResult.setRecords(responses);
pageResult.setCurrent(page.getCurrent());
pageResult.setSize(page.getSize());
pageResult.setTotal(page.getTotal());
pageResult.setPages(page.getPages());
return pageResult;
}
@Override
public IPage<Reward> getPageByUserId(BasePageRequest request, String userId) {
Page<Reward> page = new Page<>(request.getCurrent(), request.getSize());
@@ -62,6 +83,15 @@ public class RewardServiceImpl extends ServiceImpl<RewardMapper, Reward> impleme
return this.page(page, wrapper);
}
@Override
public RewardResponse getRewardResponseById(String id) {
Reward reward = this.getById(id);
if (reward == null || reward.getIsDeleted() == 1) {
return null;
}
return convertToResponse(reward);
}
@Override
public List<Reward> getByUserId(String userId) {
LambdaQueryWrapper<Reward> wrapper = new LambdaQueryWrapper<>();
@@ -223,12 +253,17 @@ public class RewardServiceImpl extends ServiceImpl<RewardMapper, Reward> impleme
}
@Override
public Reward createReward(String userId, String rewardType, Integer points, String source,
String description, LocalDateTime expiredTime) {
public Reward createReward(String userId, String rewardType, String value,
String description, String topicId, String achievementId, String icon, String rarity) {
Reward reward = new Reward();
reward.setType(rewardType);
reward.setName(rewardType + "奖励");
reward.setValue(value);
reward.setDescription(description);
reward.setTopicId(topicId);
reward.setAchievementId(achievementId);
reward.setIcon(icon);
reward.setRarity(rarity);
reward.setCreateBy(userId);
reward.setEarnedTime(LocalDateTime.now());
reward.setIsNew(1);
@@ -236,4 +271,87 @@ public class RewardServiceImpl extends ServiceImpl<RewardMapper, Reward> impleme
this.save(reward);
return reward;
}
@Override
public RewardResponse createRewardWithResponse(RewardCreateRequest request) {
Reward reward = createReward(
request.getUserId(),
request.getRewardType(),
request.getValue(),
request.getDescription(),
request.getTopicId(),
request.getAchievementId(),
request.getIcon(),
request.getRarity());
return convertToResponse(reward);
}
@Override
public RewardResponse updateRewardWithResponse(RewardUpdateRequest request) {
Reward reward = this.getById(request.getId());
if (reward == null || reward.getIsDeleted() == 1) {
return null;
}
// 只更新非空字段
if (StringUtils.hasText(request.getRewardType())) {
reward.setType(request.getRewardType());
}
if (StringUtils.hasText(request.getValue())) {
reward.setValue(request.getValue());
}
if (StringUtils.hasText(request.getDescription())) {
reward.setDescription(request.getDescription());
}
if (StringUtils.hasText(request.getTopicId())) {
reward.setTopicId(request.getTopicId());
}
if (StringUtils.hasText(request.getAchievementId())) {
reward.setAchievementId(request.getAchievementId());
}
if (StringUtils.hasText(request.getIcon())) {
reward.setIcon(request.getIcon());
}
if (StringUtils.hasText(request.getRarity())) {
reward.setRarity(request.getRarity());
}
if (request.getIsNew() != null) {
reward.setIsNew(request.getIsNew());
}
this.updateById(reward);
return convertToResponse(reward);
}
@Override
public boolean deleteReward(String id) {
Reward reward = this.getById(id);
if (reward == null || reward.getIsDeleted() == 1) {
return false;
}
// 逻辑删除
reward.setIsDeleted(1);
return this.updateById(reward);
}
/**
* 将实体转换为响应对象
*/
private RewardResponse convertToResponse(Reward reward) {
if (reward == null) {
return null;
}
RewardResponse response = new RewardResponse();
BeanUtils.copyProperties(reward, response);
response.setId(reward.getId());
if (reward.getCreateTime() != null) {
response.setCreateTime(reward.getCreateTime().toString());
}
if (reward.getUpdateTime() != null) {
response.setUpdateTime(reward.getUpdateTime().toString());
}
return response;
}
}
@@ -1,19 +1,21 @@
package com.emotion.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.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.emotion.common.BasePageRequest;
import com.emotion.common.PageResult;
import com.emotion.dto.request.TopicInteractionCreateRequest;
import com.emotion.dto.request.TopicInteractionPageRequest;
import com.emotion.dto.request.TopicInteractionUpdateRequest;
import com.emotion.dto.response.TopicInteractionResponse;
import com.emotion.entity.TopicInteraction;
import com.emotion.mapper.TopicInteractionMapper;
import com.emotion.service.TopicInteractionService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Collections;
import java.time.format.DateTimeFormatter;
/**
* 话题互动服务实现类
@@ -24,257 +26,138 @@ import java.util.Collections;
@Service
public class TopicInteractionServiceImpl extends ServiceImpl<TopicInteractionMapper, TopicInteraction> implements TopicInteractionService {
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Override
public IPage<TopicInteraction> getPage(BasePageRequest request) {
public PageResult<TopicInteractionResponse> getPageWithResponse(TopicInteractionPageRequest request) {
Page<TopicInteraction> page = new Page<>(request.getCurrent(), request.getSize());
LambdaQueryWrapper<TopicInteraction> wrapper = new LambdaQueryWrapper<>();
// 根据关键词查询
if (StringUtils.hasText(request.getKeyword())) {
wrapper.and(w -> w.like(TopicInteraction::getContent, request.getKeyword())
.or().like(TopicInteraction::getUserInput, request.getKeyword())
.or().like(TopicInteraction::getAiResponse, request.getKeyword()));
}
// 根据话题ID查询
if (StringUtils.hasText(request.getTopicId())) {
wrapper.eq(TopicInteraction::getTopicId, request.getTopicId());
}
// 根据用户ID查询
if (StringUtils.hasText(request.getUserId())) {
wrapper.eq(TopicInteraction::getCreateBy, request.getUserId());
}
// 根据互动类型查询
if (StringUtils.hasText(request.getInteractionType())) {
wrapper.eq(TopicInteraction::getType, request.getInteractionType());
}
wrapper.eq(TopicInteraction::getIsDeleted, 0).orderByDesc(TopicInteraction::getCreateTime);
return this.page(page, wrapper);
Page<TopicInteraction> resultPage = this.page(page, wrapper);
// 转换为响应对象
PageResult<TopicInteractionResponse> pageResult = new PageResult<>();
pageResult.setCurrent(resultPage.getCurrent());
pageResult.setSize(resultPage.getSize());
pageResult.setTotal(resultPage.getTotal());
pageResult.setPages(resultPage.getPages());
pageResult.setRecords(resultPage.getRecords().stream()
.map(this::convertToResponse)
.toList());
return pageResult;
}
@Override
public IPage<TopicInteraction> getPageByTopicId(BasePageRequest request, String topicId) {
Page<TopicInteraction> page = new Page<>(request.getCurrent(), request.getSize());
LambdaQueryWrapper<TopicInteraction> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(TopicInteraction::getTopicId, topicId)
.eq(TopicInteraction::getIsDeleted, 0)
.orderByDesc(TopicInteraction::getCreateTime);
return this.page(page, wrapper);
public TopicInteractionResponse getTopicInteractionResponseById(String id) {
TopicInteraction topicInteraction = this.getById(id);
if (topicInteraction == null || topicInteraction.getIsDeleted() == 1) {
return null;
}
return convertToResponse(topicInteraction);
}
@Override
public IPage<TopicInteraction> getPageByUserId(BasePageRequest request, String userId) {
Page<TopicInteraction> page = new Page<>(request.getCurrent(), request.getSize());
LambdaQueryWrapper<TopicInteraction> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(TopicInteraction::getCreateBy, userId)
.eq(TopicInteraction::getIsDeleted, 0)
.orderByDesc(TopicInteraction::getCreateTime);
return this.page(page, wrapper);
public TopicInteractionResponse createTopicInteractionWithResponse(TopicInteractionCreateRequest request) {
TopicInteraction topicInteraction = new TopicInteraction();
BeanUtils.copyProperties(request, topicInteraction);
// 设置用户ID为当前登录用户
topicInteraction.setCreateBy(getCurrentUserId());
this.save(topicInteraction);
return convertToResponse(topicInteraction);
}
@Override
public List<TopicInteraction> getByTopicId(String topicId) {
LambdaQueryWrapper<TopicInteraction> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(TopicInteraction::getTopicId, topicId)
.eq(TopicInteraction::getIsDeleted, 0)
.orderByDesc(TopicInteraction::getCreateTime);
return this.list(wrapper);
public TopicInteractionResponse updateTopicInteractionWithResponse(TopicInteractionUpdateRequest request) {
TopicInteraction topicInteraction = this.getById(request.getId());
if (topicInteraction == null || topicInteraction.getIsDeleted() == 1) {
return null;
}
// 只更新非空字段
if (StringUtils.hasText(request.getTopicId())) {
topicInteraction.setTopicId(request.getTopicId());
}
if (StringUtils.hasText(request.getInteractionType())) {
topicInteraction.setType(request.getInteractionType());
}
if (StringUtils.hasText(request.getContent())) {
topicInteraction.setContent(request.getContent());
}
if (StringUtils.hasText(request.getUserInput())) {
topicInteraction.setUserInput(request.getUserInput());
}
if (StringUtils.hasText(request.getAiResponse())) {
topicInteraction.setAiResponse(request.getAiResponse());
}
if (request.getRating() != null) {
topicInteraction.setRating(request.getRating());
}
if (StringUtils.hasText(request.getFeedback())) {
topicInteraction.setFeedback(request.getFeedback());
}
this.updateById(topicInteraction);
return convertToResponse(topicInteraction);
}
@Override
public List<TopicInteraction> getByUserId(String userId) {
LambdaQueryWrapper<TopicInteraction> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(TopicInteraction::getCreateBy, userId)
.eq(TopicInteraction::getIsDeleted, 0)
.orderByDesc(TopicInteraction::getCreateTime);
return this.list(wrapper);
public boolean deleteTopicInteraction(String id) {
TopicInteraction topicInteraction = this.getById(id);
if (topicInteraction == null || topicInteraction.getIsDeleted() == 1) {
return false;
}
topicInteraction.setIsDeleted(1);
return this.updateById(topicInteraction);
}
@Override
public List<TopicInteraction> getByInteractionType(String interactionType) {
LambdaQueryWrapper<TopicInteraction> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(TopicInteraction::getType, interactionType)
.eq(TopicInteraction::getIsDeleted, 0)
.orderByDesc(TopicInteraction::getCreateTime);
return this.list(wrapper);
/**
* 将实体对象转换为响应对象
*/
private TopicInteractionResponse convertToResponse(TopicInteraction topicInteraction) {
if (topicInteraction == null) {
return null;
}
TopicInteractionResponse response = new TopicInteractionResponse();
BeanUtils.copyProperties(topicInteraction, response);
response.setId(topicInteraction.getId());
if (topicInteraction.getCreateTime() != null) {
response.setCreateTime(topicInteraction.getCreateTime().format(FORMATTER));
}
if (topicInteraction.getUpdateTime() != null) {
response.setUpdateTime(topicInteraction.getUpdateTime().format(FORMATTER));
}
return response;
}
@Override
public List<TopicInteraction> getByTopicIdAndInteractionType(String topicId, String interactionType) {
LambdaQueryWrapper<TopicInteraction> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(TopicInteraction::getTopicId, topicId)
.eq(TopicInteraction::getType, interactionType)
.eq(TopicInteraction::getIsDeleted, 0)
.orderByDesc(TopicInteraction::getCreateTime);
return this.list(wrapper);
}
@Override
public List<TopicInteraction> getByUserIdAndInteractionType(String userId, String interactionType) {
LambdaQueryWrapper<TopicInteraction> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(TopicInteraction::getCreateBy, userId)
.eq(TopicInteraction::getType, interactionType)
.eq(TopicInteraction::getIsDeleted, 0)
.orderByDesc(TopicInteraction::getCreateTime);
return this.list(wrapper);
}
@Override
public List<TopicInteraction> getByTopicIdAndUserId(String topicId, String userId) {
LambdaQueryWrapper<TopicInteraction> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(TopicInteraction::getTopicId, topicId)
.eq(TopicInteraction::getCreateBy, userId)
.eq(TopicInteraction::getIsDeleted, 0)
.orderByDesc(TopicInteraction::getCreateTime);
return this.list(wrapper);
}
@Override
public List<TopicInteraction> getByTimeRange(LocalDateTime startTime, LocalDateTime endTime) {
LambdaQueryWrapper<TopicInteraction> wrapper = new LambdaQueryWrapper<>();
wrapper.between(TopicInteraction::getCreateTime, startTime, endTime)
.eq(TopicInteraction::getIsDeleted, 0)
.orderByDesc(TopicInteraction::getCreateTime);
return this.list(wrapper);
}
@Override
public Long countByTopicId(String topicId) {
LambdaQueryWrapper<TopicInteraction> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(TopicInteraction::getTopicId, topicId)
.eq(TopicInteraction::getIsDeleted, 0);
return this.count(wrapper);
}
@Override
public Long countByUserId(String userId) {
LambdaQueryWrapper<TopicInteraction> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(TopicInteraction::getCreateBy, userId)
.eq(TopicInteraction::getIsDeleted, 0);
return this.count(wrapper);
}
@Override
public Long countByInteractionType(String interactionType) {
LambdaQueryWrapper<TopicInteraction> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(TopicInteraction::getType, interactionType)
.eq(TopicInteraction::getIsDeleted, 0);
return this.count(wrapper);
}
@Override
public Long countByTopicIdAndInteractionType(String topicId, String interactionType) {
LambdaQueryWrapper<TopicInteraction> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(TopicInteraction::getTopicId, topicId)
.eq(TopicInteraction::getType, interactionType)
.eq(TopicInteraction::getIsDeleted, 0);
return this.count(wrapper);
}
@Override
public Long countByUserIdAndInteractionType(String userId, String interactionType) {
LambdaQueryWrapper<TopicInteraction> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(TopicInteraction::getCreateBy, userId)
.eq(TopicInteraction::getType, interactionType)
.eq(TopicInteraction::getIsDeleted, 0);
return this.count(wrapper);
}
@Override
public List<TopicInteraction> getRecentByTopicId(String topicId, Integer limit) {
LambdaQueryWrapper<TopicInteraction> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(TopicInteraction::getTopicId, topicId)
.eq(TopicInteraction::getIsDeleted, 0)
.orderByDesc(TopicInteraction::getCreateTime)
.last("LIMIT " + limit);
return this.list(wrapper);
}
@Override
public List<TopicInteraction> getRecentByUserId(String userId, Integer limit) {
LambdaQueryWrapper<TopicInteraction> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(TopicInteraction::getCreateBy, userId)
.eq(TopicInteraction::getIsDeleted, 0)
.orderByDesc(TopicInteraction::getCreateTime)
.last("LIMIT " + limit);
return this.list(wrapper);
}
@Override
public List<TopicInteraction> getPopularInteractions(Integer limit) {
// TopicInteraction实体中没有likes字段,暂时返回最新互动
LambdaQueryWrapper<TopicInteraction> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(TopicInteraction::getIsDeleted, 0)
.orderByDesc(TopicInteraction::getCreateTime)
.last("LIMIT " + limit);
return this.list(wrapper);
}
@Override
public List<TopicInteraction> getPopularInteractionsByTopicId(String topicId, Integer limit) {
// TopicInteraction实体中没有likes字段,暂时返回最新互动
LambdaQueryWrapper<TopicInteraction> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(TopicInteraction::getTopicId, topicId)
.eq(TopicInteraction::getIsDeleted, 0)
.orderByDesc(TopicInteraction::getCreateTime)
.last("LIMIT " + limit);
return this.list(wrapper);
}
@Override
public List<TopicInteraction> getByLikesRange(Integer minLikes, Integer maxLikes) {
// TopicInteraction实体中没有likes字段,暂时返回空列表
return Collections.emptyList();
}
@Override
public boolean hasUserInteracted(String topicId, String userId) {
LambdaQueryWrapper<TopicInteraction> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(TopicInteraction::getTopicId, topicId)
.eq(TopicInteraction::getCreateBy, userId)
.eq(TopicInteraction::getIsDeleted, 0);
return this.count(wrapper) > 0;
}
@Override
public TopicInteraction getUserInteractionByType(String topicId, String userId, String interactionType) {
LambdaQueryWrapper<TopicInteraction> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(TopicInteraction::getTopicId, topicId)
.eq(TopicInteraction::getCreateBy, userId)
.eq(TopicInteraction::getType, interactionType)
.eq(TopicInteraction::getIsDeleted, 0)
.orderByDesc(TopicInteraction::getCreateTime)
.last("LIMIT 1");
return this.getOne(wrapper);
}
@Override
public boolean updateLikes(String id, Integer increment) {
// TopicInteraction实体中没有likes字段,暂时返回false
return false;
}
@Override
public List<TopicInteraction> searchByContent(String keyword) {
LambdaQueryWrapper<TopicInteraction> wrapper = new LambdaQueryWrapper<>();
wrapper.and(w -> w.like(TopicInteraction::getContent, keyword)
.or().like(TopicInteraction::getUserInput, keyword)
.or().like(TopicInteraction::getAiResponse, keyword))
.eq(TopicInteraction::getIsDeleted, 0)
.orderByDesc(TopicInteraction::getCreateTime);
return this.list(wrapper);
}
@Override
public List<TopicInteraction> searchByTopicIdAndContent(String topicId, String keyword) {
LambdaQueryWrapper<TopicInteraction> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(TopicInteraction::getTopicId, topicId)
.and(w -> w.like(TopicInteraction::getContent, keyword)
.or().like(TopicInteraction::getUserInput, keyword)
.or().like(TopicInteraction::getAiResponse, keyword))
.eq(TopicInteraction::getIsDeleted, 0)
.orderByDesc(TopicInteraction::getCreateTime);
return this.list(wrapper);
}
@Override
public TopicInteraction createTopicInteraction(String topicId, String userId, String interactionType,
String content, String attachments) {
TopicInteraction interaction = new TopicInteraction();
interaction.setTopicId(topicId);
interaction.setType(interactionType);
interaction.setContent(content);
interaction.setUserInput(content);
interaction.setCreateBy(userId);
this.save(interaction);
return interaction;
/**
* 获取当前登录用户ID(模拟实现)
*/
private String getCurrentUserId() {
// 实际项目中应从token中获取用户ID
return "current_user_id";
}
}
@@ -1,19 +1,27 @@
package com.emotion.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.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.emotion.common.BasePageRequest;
import com.emotion.common.PageResult;
import com.emotion.dto.request.UserCreateRequest;
import com.emotion.dto.request.UserPageRequest;
import com.emotion.dto.request.UserUpdateRequest;
import com.emotion.dto.request.UserProfileUpdateRequest;
import com.emotion.dto.response.UserResponse;
import com.emotion.entity.User;
import com.emotion.mapper.UserMapper;
import com.emotion.service.UserService;
import com.emotion.util.UserContextHolder;
import org.springframework.beans.BeanUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;
/**
* 用户服务实现类
@@ -26,12 +34,14 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
private final PasswordEncoder passwordEncoder;
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public UserServiceImpl(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
}
@Override
public IPage<User> getPage(BasePageRequest request) {
public PageResult<UserResponse> getPageWithResponse(UserPageRequest request) {
Page<User> page = new Page<>(request.getCurrent(), request.getSize());
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
@@ -42,6 +52,36 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
.or().like(User::getEmail, request.getKeyword()));
}
// 账号查询
if (StringUtils.hasText(request.getAccount())) {
wrapper.eq(User::getAccount, request.getAccount());
}
// 用户名查询
if (StringUtils.hasText(request.getUsername())) {
wrapper.like(User::getUsername, request.getUsername());
}
// 邮箱查询
if (StringUtils.hasText(request.getEmail())) {
wrapper.eq(User::getEmail, request.getEmail());
}
// 手机号查询
if (StringUtils.hasText(request.getPhone())) {
wrapper.eq(User::getPhone, request.getPhone());
}
// 状态查询
if (request.getStatus() != null) {
wrapper.eq(User::getStatus, request.getStatus());
}
// 会员等级查询
if (StringUtils.hasText(request.getMemberLevel())) {
wrapper.eq(User::getMemberLevel, request.getMemberLevel());
}
wrapper.eq(User::getIsDeleted, 0);
// 排序
@@ -55,160 +95,172 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
wrapper.orderByDesc(User::getCreateTime);
}
return this.page(page, wrapper);
Page<User> resultPage = this.page(page, wrapper);
List<UserResponse> userResponses = resultPage.getRecords().stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
PageResult<UserResponse> pageResult = new PageResult<>();
pageResult.setCurrent(resultPage.getCurrent());
pageResult.setSize(resultPage.getSize());
pageResult.setTotal(resultPage.getTotal());
pageResult.setPages(resultPage.getPages());
pageResult.setRecords(userResponses);
return pageResult;
}
@Override
public User getByAccount(String account) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getAccount, account)
.eq(User::getIsDeleted, 0);
return this.getOne(wrapper);
public UserResponse getUserResponseById(String id) {
User user = this.getById(id);
if (user == null || user.getIsDeleted() == 1) {
return null;
}
return convertToResponse(user);
}
@Override
public User getByUsername(String username) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getUsername, username)
.eq(User::getIsDeleted, 0);
return this.getOne(wrapper);
}
@Override
public User getByEmail(String email) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getEmail, email)
.eq(User::getIsDeleted, 0);
return this.getOne(wrapper);
}
@Override
public User getByPhone(String phone) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getPhone, phone)
.eq(User::getIsDeleted, 0);
return this.getOne(wrapper);
}
@Override
public User getByThirdParty(String thirdPartyId, String thirdPartyType) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getThirdPartyId, thirdPartyId)
.eq(User::getThirdPartyType, thirdPartyType)
.eq(User::getIsDeleted, 0);
return this.getOne(wrapper);
}
@Override
public List<User> getByStatus(Integer status) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getStatus, status)
.eq(User::getIsDeleted, 0)
.orderByDesc(User::getCreateTime);
return this.list(wrapper);
}
@Override
public List<User> getByMemberLevel(String memberLevel) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getMemberLevel, memberLevel)
.eq(User::getIsDeleted, 0)
.orderByDesc(User::getCreateTime);
return this.list(wrapper);
}
@Override
public List<User> getActiveUsers(Integer days) {
LocalDateTime startTime = LocalDateTime.now().minusDays(days);
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.ge(User::getLastActiveTime, startTime)
.eq(User::getIsDeleted, 0)
.orderByDesc(User::getLastActiveTime);
return this.list(wrapper);
}
@Override
public List<User> getNewUsers(Integer days) {
LocalDateTime startTime = LocalDateTime.now().minusDays(days);
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.ge(User::getCreateTime, startTime)
.eq(User::getIsDeleted, 0)
.orderByDesc(User::getCreateTime);
return this.list(wrapper);
}
@Override
public boolean updateLastActiveTime(String userId, LocalDateTime lastActiveTime) {
public UserResponse createUserWithResponse(UserCreateRequest request) {
User user = new User();
user.setId(userId);
user.setLastActiveTime(lastActiveTime);
return this.updateById(user);
}
@Override
public boolean updateStatus(String userId, Integer status) {
User user = new User();
user.setId(userId);
user.setStatus(status);
return this.updateById(user);
}
@Override
public boolean updateTotalDays(String userId, Integer totalDays) {
User user = new User();
user.setId(userId);
user.setTotalDays(totalDays);
return this.updateById(user);
}
@Override
public Long countByStatus(Integer status) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getStatus, status)
.eq(User::getIsDeleted, 0);
return this.count(wrapper);
}
@Override
public Long countByMemberLevel(String memberLevel) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getMemberLevel, memberLevel)
.eq(User::getIsDeleted, 0);
return this.count(wrapper);
}
@Override
public User createUser(String account, String username, String password, String email, String phone) {
User user = new User();
user.setAccount(account);
user.setUsername(username);
user.setPassword(passwordEncoder.encode(password));
user.setEmail(email);
user.setPhone(phone);
user.setNickname(username);
user.setAccount(request.getAccount());
user.setUsername(request.getUsername());
user.setPassword(passwordEncoder.encode(request.getPassword()));
user.setEmail(request.getEmail());
user.setPhone(request.getPhone());
user.setNickname(request.getUsername());
user.setMemberLevel("free");
user.setStatus(1);
user.setIsVerified(0);
user.setLastActiveTime(LocalDateTime.now());
this.save(user);
return user;
return convertToResponse(user);
}
@Override
public boolean validatePassword(String userId, String password) {
User user = this.getById(userId);
if (user == null) {
public UserResponse updateUserWithResponse(UserUpdateRequest request) {
User user = this.getById(request.getId());
if (user == null || user.getIsDeleted() == 1) {
return null;
}
// 只更新非空字段
if (StringUtils.hasText(request.getUsername())) {
user.setUsername(request.getUsername());
}
if (StringUtils.hasText(request.getNickname())) {
user.setNickname(request.getNickname());
}
if (StringUtils.hasText(request.getEmail())) {
user.setEmail(request.getEmail());
}
if (StringUtils.hasText(request.getPhone())) {
user.setPhone(request.getPhone());
}
if (StringUtils.hasText(request.getAvatar())) {
user.setAvatar(request.getAvatar());
}
if (request.getBirthDate() != null) {
user.setBirthDate(request.getBirthDate());
}
if (StringUtils.hasText(request.getLocation())) {
user.setLocation(request.getLocation());
}
if (StringUtils.hasText(request.getBio())) {
user.setBio(request.getBio());
}
if (request.getStatus() != null) {
user.setStatus(request.getStatus());
}
if (StringUtils.hasText(request.getMemberLevel())) {
user.setMemberLevel(request.getMemberLevel());
}
this.updateById(user);
return convertToResponse(user);
}
@Override
public UserResponse updateCurrentUserProfileWithResponse(UserProfileUpdateRequest request) {
// 从UserContextHolder获取当前用户ID
String currentUserId = UserContextHolder.getCurrentUserId();
if (currentUserId == null) {
return null;
}
User user = this.getById(currentUserId);
if (user == null || user.getIsDeleted() == 1) {
return null;
}
// 只更新非空字段
if (StringUtils.hasText(request.getNickname())) {
user.setNickname(request.getNickname());
}
if (StringUtils.hasText(request.getEmail())) {
user.setEmail(request.getEmail());
}
if (StringUtils.hasText(request.getPhone())) {
user.setPhone(request.getPhone());
}
if (StringUtils.hasText(request.getAvatar())) {
user.setAvatar(request.getAvatar());
}
if (request.getBirthDate() != null) {
user.setBirthDate(request.getBirthDate());
}
if (StringUtils.hasText(request.getLocation())) {
user.setLocation(request.getLocation());
}
if (StringUtils.hasText(request.getBio())) {
user.setBio(request.getBio());
}
this.updateById(user);
return convertToResponse(user);
}
@Override
public UserResponse getCurrentUserProfileWithResponse() {
// 从UserContextHolder获取当前用户ID
String currentUserId = UserContextHolder.getCurrentUserId();
if (currentUserId == null) {
return null;
}
User user = this.getById(currentUserId);
if (user == null || user.getIsDeleted() == 1) {
return null;
}
return convertToResponse(user);
}
@Override
public boolean deleteUser(String id) {
User user = this.getById(id);
if (user == null || user.getIsDeleted() == 1) {
return false;
}
return passwordEncoder.matches(password, user.getPassword());
}
@Override
public boolean updatePassword(String userId, String newPassword) {
User user = new User();
user.setId(userId);
user.setPassword(passwordEncoder.encode(newPassword));
user.setIsDeleted(1);
return this.updateById(user);
}
/**
* 转换为响应对象
*/
private UserResponse convertToResponse(User user) {
UserResponse response = new UserResponse();
BeanUtils.copyProperties(user, response);
response.setId(user.getId());
if (user.getCreateTime() != null) {
response.setCreateTime(user.getCreateTime().format(DATE_TIME_FORMATTER));
}
if (user.getUpdateTime() != null) {
response.setUpdateTime(user.getUpdateTime().format(DATE_TIME_FORMATTER));
}
if (user.getLastActiveTime() != null) {
response.setLastActiveTime(user.getLastActiveTime().format(DATE_TIME_FORMATTER));
}
return response;
}
}
@@ -1,19 +1,27 @@
package com.emotion.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.emotion.common.BasePageRequest;
import com.emotion.common.PageResult;
import com.emotion.dto.request.UserStatsCreateRequest;
import com.emotion.dto.request.UserStatsIncrementRequest;
import com.emotion.dto.request.UserStatsPageRequest;
import com.emotion.dto.request.UserStatsUpdateValueRequest;
import com.emotion.dto.response.UserStatsResponse;
import com.emotion.entity.UserStats;
import com.emotion.mapper.UserStatsMapper;
import com.emotion.service.UserStatsService;
import com.emotion.util.SnowflakeIdGenerator;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Collections;
import java.util.stream.Collectors;
/**
* 用户统计服务实现类
@@ -24,193 +32,164 @@ import java.util.Collections;
@Service
public class UserStatsServiceImpl extends ServiceImpl<UserStatsMapper, UserStats> implements UserStatsService {
private final SnowflakeIdGenerator snowflakeIdGenerator;
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public UserStatsServiceImpl(SnowflakeIdGenerator snowflakeIdGenerator) {
this.snowflakeIdGenerator = snowflakeIdGenerator;
}
@Override
public IPage<UserStats> getPage(BasePageRequest request) {
public PageResult<UserStatsResponse> getPageWithResponse(UserStatsPageRequest request) {
Page<UserStats> page = new Page<>(request.getCurrent(), request.getSize());
LambdaQueryWrapper<UserStats> wrapper = new LambdaQueryWrapper<>();
// 关键词搜索
if (StringUtils.hasText(request.getKeyword())) {
wrapper.like(UserStats::getUserId, request.getKeyword());
wrapper.like(UserStats::getUserId, request.getKeyword())
.or().like(UserStats::getStatsType, request.getKeyword());
}
wrapper.eq(UserStats::getIsDeleted, 0).orderByDesc(UserStats::getCreateTime);
return this.page(page, wrapper);
}
@Override
public UserStats getByUserId(String userId) {
LambdaQueryWrapper<UserStats> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(UserStats::getUserId, userId)
.eq(UserStats::getIsDeleted, 0);
return this.getOne(wrapper);
}
// 用户ID查询
if (StringUtils.hasText(request.getUserId())) {
wrapper.eq(UserStats::getUserId, request.getUserId());
}
@Override
public List<UserStats> getByStatsType(String statsType) {
// UserStats实体中没有statsType字段,暂时返回空列表
return Collections.emptyList();
}
// 统计类型查询
if (StringUtils.hasText(request.getStatsType())) {
wrapper.eq(UserStats::getStatsType, request.getStatsType());
}
@Override
public UserStats getByUserIdAndStatsType(String userId, String statsType) {
// UserStats实体中没有statsType字段,暂时返回null
return null;
}
wrapper.eq(UserStats::getIsDeleted, 0);
@Override
public List<UserStats> getByTimeRange(LocalDateTime startTime, LocalDateTime endTime) {
LambdaQueryWrapper<UserStats> wrapper = new LambdaQueryWrapper<>();
wrapper.between(UserStats::getCreateTime, startTime, endTime)
.eq(UserStats::getIsDeleted, 0)
.orderByDesc(UserStats::getCreateTime);
return this.list(wrapper);
}
@Override
public List<UserStats> getByValueRange(Double minValue, Double maxValue) {
// UserStats实体中没有统一的value字段,暂时返回空列表
return Collections.emptyList();
}
@Override
public Long countByStatsType(String statsType) {
// UserStats实体中没有statsType字段,暂时返回0
return 0L;
}
@Override
public Double getAvgValueByStatsType(String statsType) {
// 这里需要自定义SQL查询平均值,暂时返回0
return 0.0;
}
@Override
public Double getMaxValueByStatsType(String statsType) {
// 这里需要自定义SQL查询最大值,暂时返回0
return 0.0;
}
@Override
public Double getMinValueByStatsType(String statsType) {
// 这里需要自定义SQL查询最小值,暂时返回0
return 0.0;
}
@Override
public List<UserStats> getAllStatsByUserId(String userId) {
LambdaQueryWrapper<UserStats> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(UserStats::getUserId, userId)
.eq(UserStats::getIsDeleted, 0)
.orderByDesc(UserStats::getCreateTime);
return this.list(wrapper);
}
@Override
public List<UserStats> getTopUsersByStatsType(String statsType, Integer limit) {
// 这里需要自定义SQL查询,暂时返回空列表
return Collections.emptyList();
}
@Override
public Long getUserRankByStatsType(String userId, String statsType) {
// 这里需要自定义SQL查询排名,暂时返回0
return 0L;
}
@Override
public boolean updateStatsValue(String userId, String statsType, Double value) {
// UserStats实体中没有statsType字段,暂时返回false
return false;
}
@Override
public boolean incrementStatsValue(String userId, String statsType, Double increment) {
// UserStats实体中没有statsType字段,暂时返回false
return false;
}
@Override
public boolean batchUpdateStats(String userId, List<UserStats> statsList) {
for (UserStats stats : statsList) {
stats.setUserId(userId);
if (this.getById(stats.getId()) != null) {
this.updateById(stats);
// 排序
if (StringUtils.hasText(request.getOrderBy())) {
if ("asc".equalsIgnoreCase(request.getOrderDirection())) {
wrapper.orderByAsc(UserStats::getCreateTime);
} else {
this.save(stats);
wrapper.orderByDesc(UserStats::getCreateTime);
}
} else {
wrapper.orderByDesc(UserStats::getCreateTime);
}
return true;
Page<UserStats> resultPage = this.page(page, wrapper);
List<UserStatsResponse> responses = resultPage.getRecords().stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
PageResult<UserStatsResponse> pageResult = new PageResult<>();
pageResult.setCurrent(resultPage.getCurrent());
pageResult.setSize(resultPage.getSize());
pageResult.setTotal(resultPage.getTotal());
pageResult.setPages(resultPage.getPages());
pageResult.setRecords(responses);
return pageResult;
}
@Override
public boolean updateStatsValue(UserStatsUpdateValueRequest request) {
LambdaUpdateWrapper<UserStats> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(UserStats::getUserId, request.getUserId())
.eq(UserStats::getStatsType, request.getStatsType())
.eq(UserStats::getIsDeleted, 0)
.set(UserStats::getValue, request.getValue())
.set(UserStats::getUpdateTime, LocalDateTime.now());
return this.update(wrapper);
}
@Override
public boolean incrementStatsValue(UserStatsIncrementRequest request) {
LambdaUpdateWrapper<UserStats> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(UserStats::getUserId, request.getUserId())
.eq(UserStats::getStatsType, request.getStatsType())
.eq(UserStats::getIsDeleted, 0)
.setSql("value = value + " + request.getIncrement())
.set(UserStats::getUpdateTime, LocalDateTime.now());
return this.update(wrapper);
}
@Override
public boolean recalculateUserStats(String userId) {
// 这里需要根据业务逻辑重新计算用户统计
// 暂时返回true
// 这里应该根据业务逻辑重新计算用户统计数据
// 示例:更新用户的总活跃天数、总发帖数等
return true;
}
@Override
public boolean recalculateAllUserStats() {
// 这里需要根据业务逻辑重新计算所有用户统计
// 暂时返回true
// 这里应该重新计算所有用户统计数据
return true;
}
@Override
public List<UserStats> getByPeriod(String period) {
// UserStats实体中没有period字段,暂时返回空列表
return Collections.emptyList();
}
@Override
public List<UserStats> getByUserIdAndPeriod(String userId, String period) {
// UserStats实体中没有period字段,暂时返回空列表
return Collections.emptyList();
}
@Override
public UserStats createOrUpdateUserStats(String userId, String statsType, Double value, String period) {
// 先尝试查找现有记录
UserStats existingStats = getByUserId(userId);
if (existingStats != null) {
// 更新现有记录
// 这里需要根据statsType更新对应的字段
this.updateById(existingStats);
return existingStats;
} else {
// 创建新记录
UserStats newStats = new UserStats();
newStats.setUserId(userId);
newStats.setTotalConversations(0);
newStats.setTotalMessages(0);
newStats.setTotalEmotionsRecorded(0);
newStats.setTopicsCompleted(0);
newStats.setAchievementsUnlocked(0);
newStats.setTotalPoints(0);
newStats.setConsecutiveDays(0);
newStats.setMaxConsecutiveDays(0);
newStats.setLocationsVisited(0);
newStats.setPostsCreated(0);
newStats.setCommentsMade(0);
newStats.setLikesReceived(0);
newStats.setSocialInteractions(0);
this.save(newStats);
return newStats;
}
public UserStatsResponse createOrUpdateUserStatsWithResponse(UserStatsCreateRequest request) {
UserStats stats = createOrUpdateUserStats(request.getUserId(), request.getStatsType(), request.getValue(),
request.getPeriod());
return convertToResponse(stats);
}
@Override
public boolean deleteExpiredStats(Integer days) {
LocalDateTime expireTime = LocalDateTime.now().minusDays(days);
LambdaQueryWrapper<UserStats> wrapper = new LambdaQueryWrapper<>();
LambdaUpdateWrapper<UserStats> wrapper = new LambdaUpdateWrapper<>();
wrapper.lt(UserStats::getCreateTime, expireTime)
.set(UserStats::getIsDeleted, 1)
.set(UserStats::getUpdateTime, LocalDateTime.now());
return this.update(wrapper);
}
/**
* 创建或更新用户统计
*/
private UserStats createOrUpdateUserStats(String userId, String statsType, Double value, String period) {
UserStats stats = getByUserIdAndStatsType(userId, statsType);
if (stats == null) {
stats = new UserStats();
stats.setId(snowflakeIdGenerator.nextIdAsString());
stats.setUserId(userId);
stats.setStatsType(statsType);
stats.setValue(value);
stats.setPeriod(period);
stats.setCreateTime(LocalDateTime.now());
stats.setUpdateTime(LocalDateTime.now());
stats.setIsDeleted(0);
this.save(stats);
} else {
stats.setValue(value);
stats.setPeriod(period);
stats.setUpdateTime(LocalDateTime.now());
this.updateById(stats);
}
return stats;
}
/**
* 根据用户ID和统计类型获取统计信息
*/
private UserStats getByUserIdAndStatsType(String userId, String statsType) {
LambdaQueryWrapper<UserStats> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(UserStats::getUserId, userId)
.eq(UserStats::getStatsType, statsType)
.eq(UserStats::getIsDeleted, 0);
return this.getOne(wrapper);
}
UserStats updateStats = new UserStats();
updateStats.setIsDeleted(1);
return this.update(updateStats, wrapper);
/**
* 转换为响应对象
*/
private UserStatsResponse convertToResponse(UserStats stats) {
UserStatsResponse response = new UserStatsResponse();
BeanUtils.copyProperties(stats, response);
response.setId(stats.getId());
if (stats.getCreateTime() != null) {
response.setCreateTime(stats.getCreateTime().format(DATE_TIME_FORMATTER));
}
if (stats.getUpdateTime() != null) {
response.setUpdateTime(stats.getUpdateTime().format(DATE_TIME_FORMATTER));
}
return response;
}
}