优化
This commit is contained in:
@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.emotion.common.Result;
|
||||
import com.emotion.entity.EmotionRecord;
|
||||
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;
|
||||
@@ -11,7 +12,6 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
@@ -23,7 +23,7 @@ import java.util.*;
|
||||
* @date 2025-07-22
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/emotion-records")
|
||||
@RequestMapping("/emotion-records")
|
||||
@Tag(name = "情绪记录管理", description = "用户情绪记录的增删改查功能")
|
||||
public class EmotionRecordController {
|
||||
|
||||
@@ -64,16 +64,18 @@ public class EmotionRecordController {
|
||||
/**
|
||||
* 获取用户情绪记录列表
|
||||
*/
|
||||
@Operation(summary = "获取用户情绪记录列表", description = "分页获取指定用户的情绪记录,按创建时间倒序")
|
||||
@GetMapping("/user/{userId}")
|
||||
@Operation(summary = "获取用户情绪记录列表", description = "分页获取当前用户的情绪记录,按创建时间倒序")
|
||||
@GetMapping("/user")
|
||||
public Result<IPage<EmotionRecord>> getRecordList(
|
||||
@Parameter(description = "用户ID") @PathVariable String userId,
|
||||
@Parameter(description = "页码,从1开始") @RequestParam(defaultValue = "1") Integer current,
|
||||
@Parameter(description = "每页大小") @RequestParam(defaultValue = "10") Integer size) {
|
||||
|
||||
log.info("获取用户情绪记录列表: userId={}, current={}, size={}", userId, current, size);
|
||||
|
||||
try {
|
||||
// 从上下文中获取当前用户ID
|
||||
String userId = CurrentUserUtil.requireCurrentUserId();
|
||||
|
||||
log.info("获取用户情绪记录列表: userId={}, current={}, size={}", userId, current, size);
|
||||
|
||||
IPage<EmotionRecord> page = emotionRecordService.getByUserIdWithPage(userId, current, size);
|
||||
|
||||
log.info("获取用户情绪记录成功: userId={}, total={}, records={}",
|
||||
@@ -81,12 +83,44 @@ public class EmotionRecordController {
|
||||
|
||||
return Result.success(page);
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
log.warn("用户认证失败: {}", e.getMessage());
|
||||
return Result.error(e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("获取用户情绪记录失败: userId={}", userId, e);
|
||||
log.error("获取用户情绪记录失败", e);
|
||||
return Result.error("获取情绪记录失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户最近情绪记录
|
||||
*/
|
||||
@Operation(summary = "获取用户最近情绪记录", description = "获取当前用户最近的情绪记录列表")
|
||||
@GetMapping("/user/recent")
|
||||
public Result<List<EmotionRecord>> getRecentRecords(
|
||||
@Parameter(description = "限制数量") @RequestParam(defaultValue = "5") Integer limit) {
|
||||
|
||||
try {
|
||||
// 从上下文中获取当前用户ID
|
||||
String userId = CurrentUserUtil.requireCurrentUserId();
|
||||
|
||||
log.info("获取用户最近情绪记录: userId={}, limit={}", userId, limit);
|
||||
|
||||
List<EmotionRecord> records = emotionRecordService.getRecentByUserId(userId, limit);
|
||||
|
||||
log.info("获取用户最近情绪记录成功: userId={}, records={}", userId, records.size());
|
||||
|
||||
return Result.success(records);
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
log.warn("用户认证失败: {}", e.getMessage());
|
||||
return Result.error(e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("获取用户最近情绪记录失败", e);
|
||||
return Result.error("获取最近记录失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取情绪记录详情
|
||||
*/
|
||||
|
||||
@@ -2,8 +2,8 @@ package com.emotion.controller;
|
||||
|
||||
import com.emotion.common.Result;
|
||||
import com.emotion.service.AIChatService;
|
||||
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 lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -13,13 +13,13 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* 情绪总结控制器
|
||||
*
|
||||
*
|
||||
* @author emotion-museum
|
||||
* @date 2025-07-25
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/emotion-summary")
|
||||
@RequestMapping("/emotion-summary")
|
||||
@Tag(name = "情绪总结管理", description = "用户情绪记录总结和分析功能")
|
||||
public class EmotionSummaryController {
|
||||
|
||||
@@ -27,39 +27,46 @@ public class EmotionSummaryController {
|
||||
private AIChatService aiChatService;
|
||||
|
||||
@Operation(summary = "生成用户当天的情绪记录总结", description = "基于用户当天的聊天记录生成情绪分析和记录")
|
||||
@PostMapping("/generate/{userId}")
|
||||
public Result<Map<String, Object>> generateEmotionSummary(
|
||||
@Parameter(description = "用户ID") @PathVariable String userId) {
|
||||
|
||||
log.info("收到生成情绪记录总结请求: userId={}", userId);
|
||||
|
||||
@PostMapping("/generate")
|
||||
public Result<Map<String, Object>> generateEmotionSummary() {
|
||||
|
||||
try {
|
||||
// 从上下文中获取当前用户ID
|
||||
String userId = CurrentUserUtil.requireCurrentUserId();
|
||||
|
||||
log.info("收到生成情绪记录总结请求: userId={}", userId);
|
||||
|
||||
// 调用AI服务生成情绪总结
|
||||
Map<String, Object> result = aiChatService.generateEmotionSummary(userId);
|
||||
|
||||
|
||||
if ((Boolean) result.get("success")) {
|
||||
log.info("情绪记录总结生成成功: userId={}", userId);
|
||||
return Result.success(result, "情绪记录总结生成成功");
|
||||
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("生成情绪记录总结时发生异常: userId={}", userId, e);
|
||||
log.error("生成情绪记录总结时发生异常", e);
|
||||
return Result.error("生成情绪记录总结失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Operation(summary = "获取用户情绪记录总结状态", description = "检查用户今天是否已经生成过情绪记录")
|
||||
@GetMapping("/status/{userId}")
|
||||
public Result<Map<String, Object>> getEmotionSummaryStatus(
|
||||
@Parameter(description = "用户ID") @PathVariable String userId) {
|
||||
|
||||
log.info("查询用户情绪记录总结状态: userId={}", userId);
|
||||
|
||||
@GetMapping("/status")
|
||||
public Result<Map<String, Object>> getEmotionSummaryStatus() {
|
||||
|
||||
try {
|
||||
// 从上下文中获取当前用户ID
|
||||
String userId = CurrentUserUtil.requireCurrentUserId();
|
||||
|
||||
log.info("查询用户情绪记录总结状态: userId={}", userId);
|
||||
|
||||
// 这里可以添加检查用户今天是否已经生成过情绪记录的逻辑
|
||||
// 暂时返回基本状态信息
|
||||
Map<String, Object> status = Map.of(
|
||||
@@ -67,11 +74,14 @@ public class EmotionSummaryController {
|
||||
"canGenerate", true,
|
||||
"message", "可以生成情绪记录总结"
|
||||
);
|
||||
|
||||
|
||||
return Result.success(status);
|
||||
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
log.warn("用户认证失败: {}", e.getMessage());
|
||||
return Result.error(e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("查询情绪记录总结状态时发生异常: userId={}", userId, e);
|
||||
log.error("查询情绪记录总结状态时发生异常", e);
|
||||
return Result.error("查询状态失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.emotion.dto.request.MessageCreateRequest;
|
||||
import com.emotion.dto.response.MessageResponse;
|
||||
import com.emotion.entity.Message;
|
||||
import com.emotion.service.MessageService;
|
||||
import com.emotion.util.CurrentUserUtil;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@@ -126,36 +127,76 @@ public class MessageController {
|
||||
/**
|
||||
* 根据用户ID分页查询消息
|
||||
*/
|
||||
@GetMapping("/user/{userId}/page")
|
||||
public Result<PageResult<MessageResponse>> getPageByUserId(@PathVariable String userId,
|
||||
@Valid PageRequest request) {
|
||||
IPage<Message> page = messageService.getByUserIdWithPage(userId, Math.toIntExact(request.getCurrent()), Math.toIntExact(request.getSize()));
|
||||
List<MessageResponse> responses = page.getRecords().stream()
|
||||
.map(this::convertToResponse)
|
||||
.collect(Collectors.toList());
|
||||
@GetMapping("/user/page")
|
||||
public Result<PageResult<MessageResponse>> getPageByUserId(@Valid PageRequest request) {
|
||||
|
||||
PageResult<MessageResponse> pageResult = new PageResult<>();
|
||||
pageResult.setCurrent(page.getCurrent());
|
||||
pageResult.setSize(page.getSize());
|
||||
pageResult.setTotal(page.getTotal());
|
||||
pageResult.setPages(page.getPages());
|
||||
pageResult.setRecords(responses);
|
||||
try {
|
||||
// 从上下文中获取当前用户ID
|
||||
String userId = CurrentUserUtil.requireCurrentUserId();
|
||||
|
||||
return Result.success(pageResult);
|
||||
IPage<Message> page = messageService.getByUserIdWithPage(userId, Math.toIntExact(request.getCurrent()),
|
||||
Math.toIntExact(request.getSize()));
|
||||
List<MessageResponse> responses = page.getRecords().stream()
|
||||
.map(this::convertToResponse)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
PageResult<MessageResponse> pageResult = new PageResult<>();
|
||||
pageResult.setCurrent(page.getCurrent());
|
||||
pageResult.setSize(page.getSize());
|
||||
pageResult.setTotal(page.getTotal());
|
||||
pageResult.setPages(page.getPages());
|
||||
pageResult.setRecords(responses);
|
||||
|
||||
return Result.success(pageResult);
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID和关键词搜索消息
|
||||
*/
|
||||
@GetMapping("/user/{userId}/search")
|
||||
public Result<List<MessageResponse>> searchByUserId(@PathVariable String userId,
|
||||
@GetMapping("/user/search")
|
||||
public Result<List<MessageResponse>> searchByUserId(
|
||||
@RequestParam String keyword,
|
||||
@RequestParam(defaultValue = "50") Integer limit) {
|
||||
List<Message> messages = messageService.searchByUserIdAndKeyword(userId, keyword, limit);
|
||||
List<MessageResponse> responses = messages.stream()
|
||||
.map(this::convertToResponse)
|
||||
.collect(Collectors.toList());
|
||||
return Result.success(responses);
|
||||
|
||||
try {
|
||||
// 从上下文中获取当前用户ID
|
||||
String userId = CurrentUserUtil.requireCurrentUserId();
|
||||
|
||||
List<Message> messages = messageService.searchByUserIdAndKeyword(userId, keyword, limit);
|
||||
List<MessageResponse> responses = messages.stream()
|
||||
.map(this::convertToResponse)
|
||||
.collect(Collectors.toList());
|
||||
return Result.success(responses);
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户最近的聊天记录
|
||||
*/
|
||||
@GetMapping("/user/recent")
|
||||
public Result<List<MessageResponse>> getRecentMessages(
|
||||
@RequestParam(defaultValue = "10") Integer limit) {
|
||||
|
||||
try {
|
||||
// 从上下文中获取当前用户ID
|
||||
String userId = CurrentUserUtil.requireCurrentUserId();
|
||||
|
||||
List<Message> messages = messageService.getRecentByUserId(userId, limit);
|
||||
List<MessageResponse> responses = messages.stream()
|
||||
.map(this::convertToResponse)
|
||||
.collect(Collectors.toList());
|
||||
return Result.success(responses);
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -145,5 +145,28 @@ public class Message extends BaseEntity {
|
||||
@TableField("metadata")
|
||||
private String metadata;
|
||||
|
||||
/**
|
||||
* 用户ID (注册用户或访客用户)
|
||||
*/
|
||||
@TableField("user_id")
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* 用户类型 (registered/guest)
|
||||
*/
|
||||
@TableField("user_type")
|
||||
private String userType;
|
||||
|
||||
/**
|
||||
* Coze消息角色 (user/assistant/system)
|
||||
*/
|
||||
@TableField("coze_role")
|
||||
private String cozeRole;
|
||||
|
||||
/**
|
||||
* Coze消息内容类型 (text/image/file等)
|
||||
*/
|
||||
@TableField("coze_content_type")
|
||||
private String cozeContentType;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.emotion.interceptor;
|
||||
|
||||
import com.emotion.util.JwtUtil;
|
||||
import com.emotion.util.UserContextHolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -64,19 +65,32 @@ public class JwtAuthInterceptor implements HandlerInterceptor {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 从token中获取用户信息并设置到请求属性中
|
||||
// 从token中获取用户信息并设置到请求属性和上下文中
|
||||
String userId = jwtUtil.getUserIdFromToken(token);
|
||||
String username = jwtUtil.getUsernameFromToken(token);
|
||||
|
||||
|
||||
// 设置到请求属性中(兼容现有代码)
|
||||
request.setAttribute("userId", userId);
|
||||
request.setAttribute("username", username);
|
||||
request.setAttribute("token", token);
|
||||
|
||||
|
||||
// 设置到线程本地上下文中(推荐使用)
|
||||
UserContextHolder.setCurrentUserId(userId);
|
||||
UserContextHolder.setCurrentUsername(username);
|
||||
UserContextHolder.setCurrentToken(token);
|
||||
|
||||
log.debug("Token验证成功,用户: {} ({})", username, userId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
||||
// 请求完成后清除用户上下文,防止内存泄漏
|
||||
UserContextHolder.clear();
|
||||
log.debug("请求完成,已清除用户上下文");
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为公开接口(不需要认证)
|
||||
*/
|
||||
@@ -88,11 +102,8 @@ public class JwtAuthInterceptor implements HandlerInterceptor {
|
||||
"/api/auth/captcha",
|
||||
"/api/auth/refresh-token",
|
||||
"/api/health",
|
||||
"/api/ws/chat",
|
||||
"/api/emotion-records", // 情绪记录接口
|
||||
"/api/emotion-summary", // 情绪总结接口
|
||||
"/message", // 消息接口
|
||||
"/swagger-ui",
|
||||
"/api/ws/chat",
|
||||
"/swagger-ui",
|
||||
"/v3/api-docs",
|
||||
"/actuator"
|
||||
};
|
||||
|
||||
@@ -68,4 +68,16 @@ public interface MessageMapper extends BaseMapper<Message> {
|
||||
List<Message> searchByUserIdAndKeyword(@Param("userId") String userId,
|
||||
@Param("keyword") String keyword,
|
||||
@Param("limit") Integer limit);
|
||||
|
||||
/**
|
||||
* 根据用户ID获取最近的消息
|
||||
*/
|
||||
@Select("SELECT m.* FROM message m " +
|
||||
"INNER JOIN conversation c ON m.conversation_id = c.id " +
|
||||
"WHERE c.user_id = #{userId} " +
|
||||
"AND m.is_deleted = 0 " +
|
||||
"ORDER BY m.create_time DESC " +
|
||||
"LIMIT #{limit}")
|
||||
List<Message> getRecentByUserId(@Param("userId") String userId,
|
||||
@Param("limit") Integer limit);
|
||||
}
|
||||
|
||||
@@ -55,7 +55,12 @@ public interface MessageService extends IService<Message> {
|
||||
* 根据用户ID和关键词搜索消息
|
||||
*/
|
||||
List<Message> searchByUserIdAndKeyword(String userId, String keyword, Integer limit);
|
||||
|
||||
|
||||
/**
|
||||
* 根据用户ID获取最近的消息
|
||||
*/
|
||||
List<Message> getRecentByUserId(String userId, Integer limit);
|
||||
|
||||
/**
|
||||
* 查询会话的最后一条消息
|
||||
*/
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.emotion.dto.websocket.ChatRequest;
|
||||
import com.emotion.dto.websocket.ConnectRequest;
|
||||
import com.emotion.dto.websocket.WebSocketMessage;
|
||||
import com.emotion.entity.Message;
|
||||
import com.emotion.entity.Conversation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||
@@ -219,50 +220,84 @@ public class WebSocketService {
|
||||
// 使用线程池异步处理AI响应
|
||||
new Thread(() -> {
|
||||
try {
|
||||
String userId = request.getSenderId();
|
||||
String conversationId = request.getConversationId();
|
||||
|
||||
// 如果没有会话ID,创建新会话
|
||||
if (conversationId == null || conversationId.trim().isEmpty()) {
|
||||
conversationId = createNewConversation(userId, request);
|
||||
request.setConversationId(conversationId);
|
||||
}
|
||||
|
||||
// 确保会话存在并更新活跃时间
|
||||
ensureConversationExists(conversationId, userId, request);
|
||||
|
||||
// 保存用户消息到数据库
|
||||
Message userMessage = new Message();
|
||||
userMessage.setConversationId(request.getConversationId());
|
||||
userMessage.setCreateBy(request.getSenderId());
|
||||
userMessage.setConversationId(conversationId);
|
||||
userMessage.setUserId(userId);
|
||||
userMessage
|
||||
.setUserType(request.getSenderType() == ChatRequest.SenderType.USER ? "registered" : "guest");
|
||||
userMessage.setContent(request.getContent());
|
||||
userMessage.setType(request.getMessageType().name());
|
||||
userMessage.setSender(request.getSenderType().name());
|
||||
userMessage.setType("text");
|
||||
userMessage.setSender("user");
|
||||
userMessage.setCozeRole("user");
|
||||
userMessage.setCozeContentType("text");
|
||||
messageService.createMessage(userMessage);
|
||||
|
||||
// 调用AI服务
|
||||
String aiReply = aiChatService.sendChatMessage(
|
||||
request.getConversationId(),
|
||||
request.getContent(),
|
||||
request.getSenderId()
|
||||
conversationId,
|
||||
request.getContent(),
|
||||
userId
|
||||
);
|
||||
|
||||
// 构建AI回复消息
|
||||
WebSocketMessage aiMessage = WebSocketMessage.builder()
|
||||
.messageId(UUID.randomUUID().toString())
|
||||
.conversationId(request.getConversationId())
|
||||
.type(WebSocketMessage.MessageType.TEXT)
|
||||
.content(aiReply)
|
||||
.senderId("ai")
|
||||
.senderType(WebSocketMessage.SenderType.AI)
|
||||
.status(WebSocketMessage.MessageStatus.SENT)
|
||||
.createTime(LocalDateTime.now())
|
||||
.build();
|
||||
|
||||
// 保存AI回复到数据库
|
||||
Message aiDbMessage = new Message();
|
||||
aiDbMessage.setConversationId(request.getConversationId());
|
||||
aiDbMessage.setCreateBy("ai");
|
||||
aiDbMessage.setContent(aiReply);
|
||||
aiDbMessage.setType("text");
|
||||
aiDbMessage.setSender("ai");
|
||||
messageService.createMessage(aiDbMessage);
|
||||
|
||||
// 发送AI回复
|
||||
messagingTemplate.convertAndSendToUser(request.getSenderId(), "/queue/messages", aiMessage);
|
||||
// 如果AI回复包含换行符,分割成多条消息
|
||||
String[] replyParts = aiReply.split("\\n\\n|\\n");
|
||||
|
||||
if (request.getConversationId() != null) {
|
||||
messagingTemplate.convertAndSend("/topic/conversation/" + request.getConversationId(), aiMessage);
|
||||
for (String part : replyParts) {
|
||||
if (part.trim().isEmpty())
|
||||
continue;
|
||||
|
||||
// 构建AI回复消息
|
||||
WebSocketMessage aiMessage = WebSocketMessage.builder()
|
||||
.messageId(UUID.randomUUID().toString())
|
||||
.conversationId(conversationId)
|
||||
.type(WebSocketMessage.MessageType.TEXT)
|
||||
.content(part.trim())
|
||||
.senderId("ai")
|
||||
.senderType(WebSocketMessage.SenderType.AI)
|
||||
.status(WebSocketMessage.MessageStatus.SENT)
|
||||
.createTime(LocalDateTime.now())
|
||||
.build();
|
||||
|
||||
// 保存AI回复到数据库
|
||||
Message aiDbMessage = new Message();
|
||||
aiDbMessage.setConversationId(conversationId);
|
||||
aiDbMessage.setUserId(userId);
|
||||
aiDbMessage.setUserType(
|
||||
request.getSenderType() == ChatRequest.SenderType.USER ? "registered" : "guest");
|
||||
aiDbMessage.setContent(part.trim());
|
||||
aiDbMessage.setType("text");
|
||||
aiDbMessage.setSender("ai");
|
||||
aiDbMessage.setCozeRole("assistant");
|
||||
aiDbMessage.setCozeContentType("text");
|
||||
messageService.createMessage(aiDbMessage);
|
||||
|
||||
// 发送AI回复
|
||||
messagingTemplate.convertAndSendToUser(userId, "/queue/messages", aiMessage);
|
||||
|
||||
if (conversationId != null) {
|
||||
messagingTemplate.convertAndSend("/topic/conversation/" + conversationId, aiMessage);
|
||||
}
|
||||
|
||||
// 添加短暂延迟,模拟自然对话
|
||||
Thread.sleep(500);
|
||||
}
|
||||
|
||||
|
||||
// 更新会话的最后活跃时间和消息数量
|
||||
updateConversationActivity(conversationId);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("AI响应处理失败", e);
|
||||
sendErrorMessage(request.getSenderId(), "AI服务暂时不可用,请稍后重试");
|
||||
@@ -293,4 +328,85 @@ public class WebSocketService {
|
||||
public int getOnlineUserCount() {
|
||||
return onlineUsers.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建新会话
|
||||
*/
|
||||
private String createNewConversation(String userId, ChatRequest request) {
|
||||
try {
|
||||
String conversationId = "conv_" + System.currentTimeMillis() + "_" + UUID.randomUUID().toString().substring(0, 8);
|
||||
|
||||
Conversation conversation = Conversation.builder()
|
||||
.userId(userId)
|
||||
.userType(request.getSenderType() == ChatRequest.SenderType.USER ? "registered" : "guest")
|
||||
.title("新对话")
|
||||
.type("chat")
|
||||
.conversationStatus("active")
|
||||
.startTime(LocalDateTime.now())
|
||||
.lastActiveTime(LocalDateTime.now())
|
||||
.messageCount(0)
|
||||
.build();
|
||||
|
||||
// 设置ID
|
||||
conversation.setId(conversationId);
|
||||
|
||||
conversationService.save(conversation);
|
||||
log.info("创建新会话: conversationId={}, userId={}", conversationId, userId);
|
||||
|
||||
return conversationId;
|
||||
} catch (Exception e) {
|
||||
log.error("创建新会话失败: userId={}", userId, e);
|
||||
throw new RuntimeException("创建会话失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 确保会话存在并更新活跃时间
|
||||
*/
|
||||
private void ensureConversationExists(String conversationId, String userId, ChatRequest request) {
|
||||
try {
|
||||
Conversation conversation = conversationService.getById(conversationId);
|
||||
if (conversation == null) {
|
||||
// 如果会话不存在,创建一个
|
||||
conversation = Conversation.builder()
|
||||
.userId(userId)
|
||||
.userType(request.getSenderType() == ChatRequest.SenderType.USER ? "registered" : "guest")
|
||||
.title("对话")
|
||||
.type("chat")
|
||||
.conversationStatus("active")
|
||||
.startTime(LocalDateTime.now())
|
||||
.lastActiveTime(LocalDateTime.now())
|
||||
.messageCount(0)
|
||||
.build();
|
||||
|
||||
// 设置ID
|
||||
conversation.setId(conversationId);
|
||||
|
||||
conversationService.save(conversation);
|
||||
log.info("创建会话: conversationId={}, userId={}", conversationId, userId);
|
||||
} else {
|
||||
// 更新最后活跃时间
|
||||
conversation.setLastActiveTime(LocalDateTime.now());
|
||||
conversationService.updateById(conversation);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("确保会话存在失败: conversationId={}, userId={}", conversationId, userId, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新会话活跃状态
|
||||
*/
|
||||
private void updateConversationActivity(String conversationId) {
|
||||
try {
|
||||
Conversation conversation = conversationService.getById(conversationId);
|
||||
if (conversation != null) {
|
||||
conversation.setLastActiveTime(LocalDateTime.now());
|
||||
conversation.setMessageCount((conversation.getMessageCount() != null ? conversation.getMessageCount() : 0) + 1);
|
||||
conversationService.updateById(conversation);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("更新会话活跃状态失败: conversationId={}", conversationId, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,11 +6,13 @@ import com.emotion.entity.Message;
|
||||
import com.emotion.entity.Conversation;
|
||||
import com.emotion.entity.CozeApiCall;
|
||||
import com.emotion.entity.EmotionRecord;
|
||||
import com.emotion.entity.EmotionAnalysis;
|
||||
import com.emotion.service.AIChatService;
|
||||
import com.emotion.service.MessageService;
|
||||
import com.emotion.service.ConversationService;
|
||||
import com.emotion.service.CozeApiCallService;
|
||||
import com.emotion.service.EmotionRecordService;
|
||||
import com.emotion.service.EmotionAnalysisService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@@ -59,6 +61,9 @@ public class AiChatServiceImpl implements AIChatService {
|
||||
@Autowired
|
||||
private EmotionRecordService emotionRecordService;
|
||||
|
||||
@Autowired
|
||||
private EmotionAnalysisService emotionAnalysisService;
|
||||
|
||||
@Value("${emotion.coze.api.token:}")
|
||||
private String cozeApiToken;
|
||||
|
||||
@@ -941,7 +946,7 @@ public class AiChatServiceImpl implements AIChatService {
|
||||
log.info("情绪分析总结生成完成: {}", emotionSummary);
|
||||
|
||||
// 解析AI返回的情绪分析结果
|
||||
EmotionAnalysisResult analysisResult = parseEmotionSummary(emotionSummary);
|
||||
EmotionAnalysis analysisResult = parseEmotionSummary(emotionSummary);
|
||||
|
||||
// 创建情绪记录
|
||||
EmotionRecord emotionRecord = createEmotionRecord(userId, analysisResult, chatHistory);
|
||||
@@ -1011,37 +1016,39 @@ public class AiChatServiceImpl implements AIChatService {
|
||||
/**
|
||||
* 解析情绪分析总结结果
|
||||
*/
|
||||
private EmotionAnalysisResult parseEmotionSummary(String summary) {
|
||||
private EmotionAnalysis parseEmotionSummary(String summary) {
|
||||
try {
|
||||
// 尝试从AI回复中提取JSON
|
||||
String jsonStr = extractJsonFromSummary(summary);
|
||||
if (jsonStr != null) {
|
||||
JSONObject json = JSON.parseObject(jsonStr);
|
||||
|
||||
EmotionAnalysisResult result = new EmotionAnalysisResult();
|
||||
result.setPrimaryEmotion(json.getString("primaryEmotion"));
|
||||
result.setIntensity(json.getDoubleValue("intensity"));
|
||||
result.setTriggers(json.getString("triggers"));
|
||||
result.setEmotionTrend(json.getString("emotionTrend"));
|
||||
result.setSuggestions(json.getString("suggestions"));
|
||||
result.setSummary(json.getString("summary"));
|
||||
|
||||
return result;
|
||||
return EmotionAnalysis.builder()
|
||||
.primaryEmotion(json.getString("primaryEmotion"))
|
||||
.intensity(BigDecimal.valueOf(json.getDoubleValue("intensity")))
|
||||
.keywords(json.getString("triggers"))
|
||||
.suggestion(json.getString("suggestions"))
|
||||
.text(summary)
|
||||
.polarity(determinePolarity(json.getString("primaryEmotion")))
|
||||
.confidence(BigDecimal.valueOf(0.85))
|
||||
.analysisTime(LocalDateTime.now())
|
||||
.build();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("解析情绪分析结果失败,使用默认值: {}", e.getMessage());
|
||||
}
|
||||
|
||||
// 如果解析失败,返回默认结果
|
||||
EmotionAnalysisResult defaultResult = new EmotionAnalysisResult();
|
||||
defaultResult.setPrimaryEmotion("平静");
|
||||
defaultResult.setIntensity(0.5);
|
||||
defaultResult.setTriggers("日常对话");
|
||||
defaultResult.setEmotionTrend("相对稳定");
|
||||
defaultResult.setSuggestions("保持当前的积极状态");
|
||||
defaultResult.setSummary(summary);
|
||||
|
||||
return defaultResult;
|
||||
return EmotionAnalysis.builder()
|
||||
.primaryEmotion("平静")
|
||||
.intensity(BigDecimal.valueOf(0.5))
|
||||
.keywords("日常对话")
|
||||
.suggestion("保持当前的积极状态")
|
||||
.text(summary)
|
||||
.polarity("neutral")
|
||||
.confidence(BigDecimal.valueOf(0.5))
|
||||
.analysisTime(LocalDateTime.now())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1063,14 +1070,14 @@ public class AiChatServiceImpl implements AIChatService {
|
||||
/**
|
||||
* 创建情绪记录
|
||||
*/
|
||||
private EmotionRecord createEmotionRecord(String userId, EmotionAnalysisResult analysisResult, String chatHistory) {
|
||||
private EmotionRecord createEmotionRecord(String userId, EmotionAnalysis analysisResult, String chatHistory) {
|
||||
EmotionRecord record = EmotionRecord.builder()
|
||||
.userId(userId)
|
||||
.recordDate(LocalDate.now())
|
||||
.emotionType(analysisResult.getPrimaryEmotion())
|
||||
.intensity(BigDecimal.valueOf(analysisResult.getIntensity()))
|
||||
.triggers(analysisResult.getTriggers())
|
||||
.description(analysisResult.getSummary())
|
||||
.intensity(analysisResult.getIntensity())
|
||||
.triggers(analysisResult.getKeywords())
|
||||
.description(analysisResult.getText())
|
||||
.notes("基于当天聊天记录自动生成的情绪分析")
|
||||
.tags("AI分析,聊天记录,情绪总结")
|
||||
.build();
|
||||
@@ -1078,37 +1085,14 @@ public class AiChatServiceImpl implements AIChatService {
|
||||
emotionRecordService.save(record);
|
||||
log.info("情绪记录创建成功: recordId={}", record.getId());
|
||||
|
||||
// 设置情绪分析记录的关联ID并保存
|
||||
analysisResult.setUserId(userId);
|
||||
analysisResult.setMessageId(record.getId()); // 关联到情绪记录ID
|
||||
|
||||
emotionAnalysisService.save(analysisResult);
|
||||
log.info("情绪分析记录创建成功: analysisId={}", analysisResult.getId());
|
||||
|
||||
return record;
|
||||
}
|
||||
|
||||
/**
|
||||
* 情绪分析结果内部类
|
||||
*/
|
||||
public static class EmotionAnalysisResult {
|
||||
private String primaryEmotion;
|
||||
private Double intensity;
|
||||
private String triggers;
|
||||
private String emotionTrend;
|
||||
private String suggestions;
|
||||
private String summary;
|
||||
|
||||
// Getters and Setters
|
||||
public String getPrimaryEmotion() { return primaryEmotion; }
|
||||
public void setPrimaryEmotion(String primaryEmotion) { this.primaryEmotion = primaryEmotion; }
|
||||
|
||||
public Double getIntensity() { return intensity; }
|
||||
public void setIntensity(Double intensity) { this.intensity = intensity; }
|
||||
|
||||
public String getTriggers() { return triggers; }
|
||||
public void setTriggers(String triggers) { this.triggers = triggers; }
|
||||
|
||||
public String getEmotionTrend() { return emotionTrend; }
|
||||
public void setEmotionTrend(String emotionTrend) { this.emotionTrend = emotionTrend; }
|
||||
|
||||
public String getSuggestions() { return suggestions; }
|
||||
public void setSuggestions(String suggestions) { this.suggestions = suggestions; }
|
||||
|
||||
public String getSummary() { return summary; }
|
||||
public void setSummary(String summary) { this.summary = summary; }
|
||||
}
|
||||
}
|
||||
@@ -195,4 +195,10 @@ public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> impl
|
||||
// 通过conversation表关联查询用户的消息,根据关键词搜索
|
||||
return this.baseMapper.searchByUserIdAndKeyword(userId, keyword, limit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Message> getRecentByUserId(String userId, Integer limit) {
|
||||
// 获取用户最近的消息,按时间倒序
|
||||
return this.baseMapper.getRecentByUserId(userId, limit);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.emotion.util;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 当前用户工具类
|
||||
* 提供便捷的方法获取当前登录用户信息
|
||||
*
|
||||
* @author emotion-museum
|
||||
* @date 2025-07-25
|
||||
*/
|
||||
@Slf4j
|
||||
public class CurrentUserUtil {
|
||||
|
||||
/**
|
||||
* 获取当前用户ID
|
||||
*
|
||||
* @return 当前用户ID,如果未登录则返回null
|
||||
*/
|
||||
public static String getCurrentUserId() {
|
||||
return UserContextHolder.getCurrentUserId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户名
|
||||
*
|
||||
* @return 当前用户名,如果未登录则返回null
|
||||
*/
|
||||
public static String getCurrentUsername() {
|
||||
return UserContextHolder.getCurrentUsername();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户Token
|
||||
*
|
||||
* @return 当前用户Token,如果未登录则返回null
|
||||
*/
|
||||
public static String getCurrentToken() {
|
||||
return UserContextHolder.getCurrentToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查当前是否有用户登录
|
||||
*
|
||||
* @return 是否有用户登录
|
||||
*/
|
||||
public static boolean isUserLoggedIn() {
|
||||
return UserContextHolder.hasUserContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户ID,如果未登录则抛出异常
|
||||
*
|
||||
* @return 当前用户ID
|
||||
* @throws IllegalStateException 如果用户未登录
|
||||
*/
|
||||
public static String requireCurrentUserId() {
|
||||
String userId = getCurrentUserId();
|
||||
if (userId == null || userId.trim().isEmpty()) {
|
||||
throw new IllegalStateException("用户未登录或认证失败");
|
||||
}
|
||||
return userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户名,如果未登录则抛出异常
|
||||
*
|
||||
* @return 当前用户名
|
||||
* @throws IllegalStateException 如果用户未登录
|
||||
*/
|
||||
public static String requireCurrentUsername() {
|
||||
String username = getCurrentUsername();
|
||||
if (username == null || username.trim().isEmpty()) {
|
||||
throw new IllegalStateException("用户未登录或认证失败");
|
||||
}
|
||||
return username;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户上下文摘要信息
|
||||
*
|
||||
* @return 用户上下文摘要
|
||||
*/
|
||||
public static String getContextSummary() {
|
||||
return UserContextHolder.getContextSummary();
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,11 @@ public class UserContextHolder {
|
||||
*/
|
||||
private static final ThreadLocal<String> REQUEST_ID_HOLDER = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* Token线程本地变量
|
||||
*/
|
||||
private static final ThreadLocal<String> TOKEN_HOLDER = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* 设置当前用户ID
|
||||
*
|
||||
@@ -125,12 +130,31 @@ public class UserContextHolder {
|
||||
|
||||
/**
|
||||
* 获取请求ID
|
||||
*
|
||||
*
|
||||
* @return 请求ID
|
||||
*/
|
||||
public static String getRequestId() {
|
||||
return REQUEST_ID_HOLDER.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前Token
|
||||
*
|
||||
* @param token Token
|
||||
*/
|
||||
public static void setCurrentToken(String token) {
|
||||
TOKEN_HOLDER.set(token);
|
||||
log.debug("设置当前Token: {}", token != null ? "***" : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前Token
|
||||
*
|
||||
* @return Token
|
||||
*/
|
||||
public static String getCurrentToken() {
|
||||
return TOKEN_HOLDER.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置用户上下文信息
|
||||
@@ -188,6 +212,13 @@ public class UserContextHolder {
|
||||
REQUEST_ID_HOLDER.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除当前Token
|
||||
*/
|
||||
public static void clearToken() {
|
||||
TOKEN_HOLDER.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有用户上下文信息
|
||||
*/
|
||||
@@ -197,6 +228,7 @@ public class UserContextHolder {
|
||||
clearUserType();
|
||||
clearClientIp();
|
||||
clearRequestId();
|
||||
clearToken();
|
||||
log.debug("清除所有用户上下文信息");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
# Coze API 配置示例
|
||||
# 请根据您的实际情况修改以下配置
|
||||
|
||||
emotion:
|
||||
coze:
|
||||
api:
|
||||
# Coze API 访问令牌 - 从 https://www.coze.cn/docs/developer_guides/pat 获取
|
||||
token: "your-coze-api-token-here"
|
||||
|
||||
# Coze API 基础URL
|
||||
base-url: "https://api.coze.cn"
|
||||
|
||||
# 聊天相关配置
|
||||
chat:
|
||||
talk:
|
||||
# 聊天机器人ID - 从您的 Coze 工作空间获取
|
||||
bot-id: "your-chat-bot-id-here"
|
||||
# 工作流ID(可选)- 如果使用工作流模式
|
||||
workflow-id: "your-chat-workflow-id-here"
|
||||
|
||||
summary:
|
||||
# 总结机器人ID(可选)- 如果有专门的总结机器人
|
||||
bot-id: "your-summary-bot-id-here"
|
||||
# 总结工作流ID(可选)
|
||||
workflow-id: "your-summary-workflow-id-here"
|
||||
|
||||
# 请求超时配置(毫秒)
|
||||
timeout: 30000
|
||||
|
||||
# 重试配置
|
||||
retry-count: 3
|
||||
retry-delay: 1000
|
||||
|
||||
# 配置说明:
|
||||
# 1. token: 个人访问令牌,需要在 Coze 平台创建
|
||||
# 2. bot-id: 机器人ID,在发布机器人时选择"发布到API"获得
|
||||
# 3. workflow-id: 工作流ID,如果使用工作流模式则需要配置
|
||||
# 4. base-url: 通常为 https://api.coze.cn,国际版可能不同
|
||||
# 5. 确保机器人已发布并启用API访问
|
||||
|
||||
# 重要提醒:
|
||||
# - 请勿将真实的 token 和 ID 提交到版本控制系统
|
||||
# - 建议使用环境变量或配置中心管理敏感信息
|
||||
# - 测试时可以先使用简单的聊天机器人验证配置
|
||||
@@ -74,39 +74,39 @@ DROP TABLE IF EXISTS user;
|
||||
-- 1. 用户表 (user)
|
||||
-- ============================================================================
|
||||
CREATE TABLE user (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
account VARCHAR(50) UNIQUE, -- 账号
|
||||
password VARCHAR(255) , -- 密码(加密后)
|
||||
username VARCHAR(50) UNIQUE, -- 用户名
|
||||
email VARCHAR(100) UNIQUE, -- 邮箱
|
||||
phone VARCHAR(20) UNIQUE, -- 手机号
|
||||
avatar VARCHAR(500), -- 头像URL
|
||||
nickname VARCHAR(50) , -- 昵称
|
||||
birth_date DATE, -- 生日
|
||||
location VARCHAR(100), -- 所在地
|
||||
bio TEXT, -- 个人简介
|
||||
member_level VARCHAR(20) DEFAULT 'free', -- 会员等级
|
||||
total_days INT DEFAULT 0, -- 使用天数
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
account VARCHAR(50) UNIQUE COMMENT '账号', -- 账号
|
||||
password VARCHAR(255) COMMENT '密码(加密后)', -- 密码(加密后)
|
||||
username VARCHAR(50) UNIQUE COMMENT '用户名', -- 用户名
|
||||
email VARCHAR(100) UNIQUE COMMENT '邮箱', -- 邮箱
|
||||
phone VARCHAR(20) UNIQUE COMMENT '手机号', -- 手机号
|
||||
avatar VARCHAR(500) COMMENT '头像URL', -- 头像URL
|
||||
nickname VARCHAR(50) COMMENT '昵称', -- 昵称
|
||||
birth_date DATE COMMENT '生日', -- 生日
|
||||
location VARCHAR(100) COMMENT '所在地', -- 所在地
|
||||
bio TEXT COMMENT '个人简介', -- 个人简介
|
||||
member_level VARCHAR(20) DEFAULT 'free' COMMENT '会员等级', -- 会员等级
|
||||
total_days INT DEFAULT 0 COMMENT '使用天数', -- 使用天数
|
||||
-- 成长数据
|
||||
self_awareness DECIMAL(5, 2) DEFAULT 50.00, -- 自我感知
|
||||
emotional_resilience DECIMAL(5, 2) DEFAULT 50.00, -- 情绪韧性
|
||||
action_power DECIMAL(5, 2) DEFAULT 50.00, -- 行动力
|
||||
empathy DECIMAL(5, 2) DEFAULT 50.00, -- 共情力
|
||||
life_enthusiasm DECIMAL(5, 2) DEFAULT 50.00, -- 生活热度
|
||||
self_awareness DECIMAL(5, 2) DEFAULT 50.00 COMMENT '自我感知', -- 自我感知
|
||||
emotional_resilience DECIMAL(5, 2) DEFAULT 50.00 COMMENT '情绪韧性', -- 情绪韧性
|
||||
action_power DECIMAL(5, 2) DEFAULT 50.00 COMMENT '行动力', -- 行动力
|
||||
empathy DECIMAL(5, 2) DEFAULT 50.00 COMMENT '共情力', -- 共情力
|
||||
life_enthusiasm DECIMAL(5, 2) DEFAULT 50.00 COMMENT '生活热度', -- 生活热度
|
||||
-- 状态字段
|
||||
status TINYINT DEFAULT 1, -- 状态: 0-禁用, 1-正常
|
||||
is_verified TINYINT DEFAULT 0, -- 是否已验证: 0-未验证, 1-已验证
|
||||
last_active_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 最后活跃时间
|
||||
status TINYINT DEFAULT 1 COMMENT '状态: 0-禁用, 1-正常', -- 状态: 0-禁用, 1-正常
|
||||
is_verified TINYINT DEFAULT 0 COMMENT '是否已验证: 0-未验证, 1-已验证', -- 是否已验证: 0-未验证, 1-已验证
|
||||
last_active_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '最后活跃时间', -- 最后活跃时间
|
||||
-- 第三方登录字段
|
||||
third_party_id VARCHAR(128), -- 第三方平台ID
|
||||
third_party_type VARCHAR(32), -- 第三方平台类型: wechat, qq, wechat-mp
|
||||
third_party_id VARCHAR(128) COMMENT '第三方平台ID', -- 第三方平台ID
|
||||
third_party_type VARCHAR(32) COMMENT '第三方平台类型: wechat, qq, wechat-mp', -- 第三方平台类型: wechat, qq, wechat-mp
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户表';
|
||||
|
||||
-- ============================================================================
|
||||
@@ -114,41 +114,41 @@ CREATE TABLE user (
|
||||
-- 关联说明: user_id 关联 user.id,通过代码逻辑维护关联关系
|
||||
-- ============================================================================
|
||||
CREATE TABLE conversation (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
user_id VARCHAR(36) , -- 用户ID (关联user.id)
|
||||
user_type VARCHAR(20) DEFAULT 'registered', -- 用户类型: registered-注册用户, guest-访客用户
|
||||
title VARCHAR(200), -- 对话标题
|
||||
type VARCHAR(50) DEFAULT 'emotion_chat', -- 对话类型
|
||||
status VARCHAR(20) DEFAULT 'active', -- 状态: active-活跃, ended-结束, archived-归档
|
||||
coze_conversation_id VARCHAR(100), -- Coze对话ID
|
||||
bot_id VARCHAR(50), -- 使用的Bot ID
|
||||
workflow_id VARCHAR(50), -- 使用的Workflow ID
|
||||
initial_message TEXT, -- 初始消息
|
||||
context TEXT, -- 上下文信息
|
||||
primary_emotion VARCHAR(50), -- 主要情绪
|
||||
emotion_intensity DECIMAL(3, 2), -- 情绪强度
|
||||
emotion_trend VARCHAR(50), -- 情绪趋势
|
||||
keywords JSON, -- 关键词
|
||||
ai_insights TEXT, -- AI洞察
|
||||
confidence DECIMAL(3, 2), -- 分析置信度
|
||||
start_time DATETIME, -- 开始时间
|
||||
end_time DATETIME, -- 结束时间
|
||||
last_active_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 最后活跃时间
|
||||
message_count INT DEFAULT 0, -- 消息数量
|
||||
total_tokens INT DEFAULT 0, -- 总Token使用量
|
||||
total_cost DECIMAL(10, 4) DEFAULT 0.0000, -- 总费用
|
||||
client_ip VARCHAR(45), -- 客户端IP地址 (支持IPv6)
|
||||
user_agent TEXT, -- 用户代理信息
|
||||
summary TEXT, -- 对话摘要
|
||||
tags JSON, -- 标签
|
||||
metadata JSON, -- 扩展元数据
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
user_id VARCHAR(36) COMMENT '用户ID (关联user.id)', -- 用户ID (关联user.id)
|
||||
user_type VARCHAR(20) DEFAULT 'registered' COMMENT '用户类型: registered-注册用户, guest-访客用户', -- 用户类型: registered-注册用户, guest-访客用户
|
||||
title VARCHAR(200) COMMENT '对话标题', -- 对话标题
|
||||
type VARCHAR(50) DEFAULT 'emotion_chat' COMMENT '对话类型', -- 对话类型
|
||||
status VARCHAR(20) DEFAULT 'active' COMMENT '状态: active-活跃, ended-结束, archived-归档', -- 状态: active-活跃, ended-结束, archived-归档
|
||||
coze_conversation_id VARCHAR(100) COMMENT 'Coze对话ID', -- Coze对话ID
|
||||
bot_id VARCHAR(50) COMMENT '使用的Bot ID', -- 使用的Bot ID
|
||||
workflow_id VARCHAR(50) COMMENT '使用的Workflow ID', -- 使用的Workflow ID
|
||||
initial_message TEXT COMMENT '初始消息', -- 初始消息
|
||||
context TEXT COMMENT '上下文信息', -- 上下文信息
|
||||
primary_emotion VARCHAR(50) COMMENT '主要情绪', -- 主要情绪
|
||||
emotion_intensity DECIMAL(3, 2) COMMENT '情绪强度', -- 情绪强度
|
||||
emotion_trend VARCHAR(50) COMMENT '情绪趋势', -- 情绪趋势
|
||||
keywords JSON COMMENT '关键词', -- 关键词
|
||||
ai_insights TEXT COMMENT 'AI洞察', -- AI洞察
|
||||
confidence DECIMAL(3, 2) COMMENT '分析置信度', -- 分析置信度
|
||||
start_time DATETIME COMMENT '开始时间', -- 开始时间
|
||||
end_time DATETIME COMMENT '结束时间', -- 结束时间
|
||||
last_active_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '最后活跃时间', -- 最后活跃时间
|
||||
message_count INT DEFAULT 0 COMMENT '消息数量', -- 消息数量
|
||||
total_tokens INT DEFAULT 0 COMMENT '总Token使用量', -- 总Token使用量
|
||||
total_cost DECIMAL(10, 4) DEFAULT 0.0000 COMMENT '总费用', -- 总费用
|
||||
client_ip VARCHAR(45) COMMENT '客户端IP地址 (支持IPv6)', -- 客户端IP地址 (支持IPv6)
|
||||
user_agent TEXT COMMENT '用户代理信息', -- 用户代理信息
|
||||
summary TEXT COMMENT '对话摘要', -- 对话摘要
|
||||
tags JSON COMMENT '标签', -- 标签
|
||||
metadata JSON COMMENT '扩展元数据', -- 扩展元数据
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '对话表';
|
||||
|
||||
-- ============================================================================
|
||||
@@ -156,368 +156,372 @@ CREATE TABLE conversation (
|
||||
-- 关联说明: conversation_id 关联 conversation.id,通过代码逻辑维护关联关系
|
||||
-- ============================================================================
|
||||
CREATE TABLE message (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
conversation_id VARCHAR(36) , -- 对话ID (关联conversation.id)
|
||||
content TEXT , -- 消息内容
|
||||
type VARCHAR(50) DEFAULT 'text', -- 消息类型
|
||||
sender VARCHAR(20) , -- 发送者: user-用户, assistant-AI助手
|
||||
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, -- 消息时间戳
|
||||
coze_chat_id VARCHAR(50), -- Coze平台的聊天ID
|
||||
coze_message_id VARCHAR(50), -- Coze平台的消息ID
|
||||
status VARCHAR(20) DEFAULT 'sent', -- 消息状态: sending/sent/failed/processing
|
||||
error_message TEXT, -- 错误信息
|
||||
emotion_score DECIMAL(3, 2), -- 情绪评分
|
||||
emotion_type VARCHAR(50), -- 情绪类型
|
||||
emotion_confidence DECIMAL(3, 2), -- 情绪分析置信度
|
||||
prompt_tokens INT DEFAULT 0, -- 输入Token数
|
||||
completion_tokens INT DEFAULT 0, -- 输出Token数
|
||||
total_tokens INT DEFAULT 0, -- 总Token数
|
||||
api_cost DECIMAL(10, 6) DEFAULT 0.000000, -- API调用费用
|
||||
is_read TINYINT DEFAULT 0, -- 是否已读: 0-未读, 1-已读
|
||||
parent_message_id VARCHAR(36), -- 父消息ID(用于回复链)
|
||||
emotion_analysis JSON, -- 情绪分析结果
|
||||
metadata JSON, -- 扩展元数据
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
conversation_id VARCHAR(36) COMMENT '对话ID (关联conversation.id)', -- 对话ID (关联conversation.id)
|
||||
content TEXT COMMENT '消息内容', -- 消息内容
|
||||
type VARCHAR(50) DEFAULT 'text' COMMENT '消息类型', -- 消息类型
|
||||
sender VARCHAR(20) COMMENT '发送者: user-用户, assistant-AI助手', -- 发送者: user-用户, assistant-AI助手
|
||||
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '消息时间戳', -- 消息时间戳
|
||||
coze_chat_id VARCHAR(50) COMMENT 'Coze平台的聊天ID', -- Coze平台的聊天ID
|
||||
coze_message_id VARCHAR(50) COMMENT 'Coze平台的消息ID', -- Coze平台的消息ID
|
||||
status VARCHAR(20) DEFAULT 'sent' COMMENT '消息状态: sending/sent/failed/processing', -- 消息状态: sending/sent/failed/processing
|
||||
error_message TEXT COMMENT '错误信息', -- 错误信息
|
||||
emotion_score DECIMAL(3, 2) COMMENT '情绪评分', -- 情绪评分
|
||||
emotion_type VARCHAR(50) COMMENT '情绪类型', -- 情绪类型
|
||||
emotion_confidence DECIMAL(3, 2) COMMENT '情绪分析置信度', -- 情绪分析置信度
|
||||
prompt_tokens INT DEFAULT 0 COMMENT '输入Token数', -- 输入Token数
|
||||
completion_tokens INT DEFAULT 0 COMMENT '输出Token数', -- 输出Token数
|
||||
total_tokens INT DEFAULT 0 COMMENT '总Token数', -- 总Token数
|
||||
api_cost DECIMAL(10, 6) DEFAULT 0.000000 COMMENT 'API调用费用', -- API调用费用
|
||||
is_read TINYINT DEFAULT 0 COMMENT '是否已读: 0-未读, 1-已读', -- 是否已读: 0-未读, 1-已读
|
||||
parent_message_id VARCHAR(36) COMMENT '父消息ID(用于回复链)', -- 父消息ID(用于回复链)
|
||||
emotion_analysis JSON COMMENT '情绪分析结果', -- 情绪分析结果
|
||||
metadata JSON COMMENT '扩展元数据', -- 扩展元数据
|
||||
user_id VARCHAR(36) COMMENT '用户ID (注册用户或访客用户)', -- 用户ID (注册用户或访客用户)
|
||||
user_type VARCHAR(20) COMMENT '用户类型 (registered/guest)', -- 用户类型 (registered/guest)
|
||||
coze_role VARCHAR(20) COMMENT 'Coze消息角色 (user/assistant/system)', -- Coze消息角色 (user/assistant/system)
|
||||
coze_content_type VARCHAR(50) COMMENT 'Coze消息内容类型 (text/image/file等)', -- Coze消息内容类型 (text/image/file等)
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '消息表';
|
||||
|
||||
-- ============================================================================
|
||||
-- 4. Coze API调用记录表 (coze_api_call) - 优化版本
|
||||
-- ============================================================================
|
||||
CREATE TABLE coze_api_call (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
conversation_id VARCHAR(36), -- 对话ID
|
||||
message_id VARCHAR(36), -- 消息ID
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
conversation_id VARCHAR(36) COMMENT '对话ID', -- 对话ID
|
||||
message_id VARCHAR(36) COMMENT '消息ID', -- 消息ID
|
||||
-- Coze API 信息
|
||||
coze_chat_id VARCHAR(50), -- Coze聊天ID
|
||||
coze_conversation_id VARCHAR(50), -- Coze对话ID
|
||||
bot_id VARCHAR(50) , -- Bot ID
|
||||
workflow_id VARCHAR(50), -- Workflow ID
|
||||
user_id VARCHAR(36) , -- 用户ID
|
||||
coze_chat_id VARCHAR(50) COMMENT 'Coze聊天ID', -- Coze聊天ID
|
||||
coze_conversation_id VARCHAR(50) COMMENT 'Coze对话ID', -- Coze对话ID
|
||||
bot_id VARCHAR(50) COMMENT 'Bot ID', -- Bot ID
|
||||
workflow_id VARCHAR(50) COMMENT 'Workflow ID', -- Workflow ID
|
||||
user_id VARCHAR(36) COMMENT '用户ID', -- 用户ID
|
||||
-- 请求信息
|
||||
request_type VARCHAR(20) , -- 请求类型: chat/stream/retrieve/messages
|
||||
request_url VARCHAR(500), -- 请求URL
|
||||
request_body JSON, -- 请求体
|
||||
request_headers JSON, -- 请求头
|
||||
request_type VARCHAR(20) COMMENT '请求类型: chat/stream/retrieve/messages', -- 请求类型: chat/stream/retrieve/messages
|
||||
request_url VARCHAR(500) COMMENT '请求URL', -- 请求URL
|
||||
request_body JSON COMMENT '请求体', -- 请求体
|
||||
request_headers JSON COMMENT '请求头', -- 请求头
|
||||
-- 用户消息内容
|
||||
user_message TEXT, -- 用户输入的消息内容
|
||||
user_message_type VARCHAR(20) DEFAULT 'text', -- 用户消息类型: text/image/file
|
||||
user_message TEXT COMMENT '用户输入的消息内容', -- 用户输入的消息内容
|
||||
user_message_type VARCHAR(20) DEFAULT 'text' COMMENT '用户消息类型: text/image/file', -- 用户消息类型: text/image/file
|
||||
-- AI回复内容
|
||||
ai_reply TEXT, -- AI回复的消息内容
|
||||
ai_reply_type VARCHAR(20) DEFAULT 'text', -- AI回复类型: text/image/file
|
||||
ai_reply TEXT COMMENT 'AI回复的消息内容', -- AI回复的消息内容
|
||||
ai_reply_type VARCHAR(20) DEFAULT 'text' COMMENT 'AI回复类型: text/image/file', -- AI回复类型: text/image/file
|
||||
-- 响应信息
|
||||
response_status INT, -- HTTP状态码
|
||||
response_body JSON, -- 响应体
|
||||
response_headers JSON, -- 响应头
|
||||
response_status INT COMMENT 'HTTP状态码', -- HTTP状态码
|
||||
response_body JSON COMMENT '响应体', -- 响应体
|
||||
response_headers JSON COMMENT '响应头', -- 响应头
|
||||
-- 轮询信息
|
||||
poll_count INT DEFAULT 0, -- 轮询次数
|
||||
poll_start_time DATETIME, -- 轮询开始时间
|
||||
poll_end_time DATETIME, -- 轮询结束时间
|
||||
final_status VARCHAR(20), -- 最终状态: completed/failed/timeout
|
||||
poll_count INT DEFAULT 0 COMMENT '轮询次数', -- 轮询次数
|
||||
poll_start_time DATETIME COMMENT '轮询开始时间', -- 轮询开始时间
|
||||
poll_end_time DATETIME COMMENT '轮询结束时间', -- 轮询结束时间
|
||||
final_status VARCHAR(20) COMMENT '最终状态: completed/failed/timeout', -- 最终状态: completed/failed/timeout
|
||||
-- 状态和时间
|
||||
status VARCHAR(20) , -- 调用状态: pending/success/failed/timeout
|
||||
start_time DATETIME , -- 开始时间
|
||||
end_time DATETIME, -- 结束时间
|
||||
duration_ms INT, -- 耗时(毫秒)
|
||||
status VARCHAR(20) COMMENT '调用状态: pending/success/failed/timeout', -- 调用状态: pending/success/failed/timeout
|
||||
start_time DATETIME COMMENT '开始时间', -- 开始时间
|
||||
end_time DATETIME COMMENT '结束时间', -- 结束时间
|
||||
duration_ms INT COMMENT '耗时(毫秒)', -- 耗时(毫秒)
|
||||
-- 使用统计
|
||||
prompt_tokens INT DEFAULT 0, -- 输入Token数
|
||||
completion_tokens INT DEFAULT 0, -- 输出Token数
|
||||
total_tokens INT DEFAULT 0, -- 总Token数
|
||||
cost DECIMAL(10, 6) DEFAULT 0.000000, -- 费用
|
||||
prompt_tokens INT DEFAULT 0 COMMENT '输入Token数', -- 输入Token数
|
||||
completion_tokens INT DEFAULT 0 COMMENT '输出Token数', -- 输出Token数
|
||||
total_tokens INT DEFAULT 0 COMMENT '总Token数', -- 总Token数
|
||||
cost DECIMAL(10, 6) DEFAULT 0.000000 COMMENT '费用', -- 费用
|
||||
-- 功能调用信息
|
||||
function_calls JSON, -- 函数调用记录
|
||||
function_results JSON, -- 函数调用结果
|
||||
function_calls JSON COMMENT '函数调用记录', -- 函数调用记录
|
||||
function_results JSON COMMENT '函数调用结果', -- 函数调用结果
|
||||
-- 错误信息
|
||||
error_code VARCHAR(50), -- 错误代码
|
||||
error_message TEXT, -- 错误信息
|
||||
error_code VARCHAR(50) COMMENT '错误代码', -- 错误代码
|
||||
error_message TEXT COMMENT '错误信息', -- 错误信息
|
||||
-- 扩展信息
|
||||
client_ip VARCHAR(45), -- 客户端IP
|
||||
user_agent TEXT, -- 用户代理
|
||||
session_id VARCHAR(100), -- 会话ID
|
||||
trace_id VARCHAR(100), -- 追踪ID
|
||||
metadata JSON, -- 扩展元数据
|
||||
client_ip VARCHAR(45) COMMENT '客户端IP', -- 客户端IP
|
||||
user_agent TEXT COMMENT '用户代理', -- 用户代理
|
||||
session_id VARCHAR(100) COMMENT '会话ID', -- 会话ID
|
||||
trace_id VARCHAR(100) COMMENT '追踪ID', -- 追踪ID
|
||||
metadata JSON COMMENT '扩展元数据', -- 扩展元数据
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'Coze API调用记录表 - 完整版本';
|
||||
|
||||
-- ============================================================================
|
||||
-- 5. 情绪分析表 (emotion_analysis)
|
||||
-- ============================================================================
|
||||
CREATE TABLE emotion_analysis (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
user_id VARCHAR(36) , -- 用户ID
|
||||
message_id VARCHAR(36), -- 关联消息ID
|
||||
text TEXT , -- 分析文本
|
||||
primary_emotion VARCHAR(50), -- 主要情绪
|
||||
intensity DECIMAL(3, 2), -- 情绪强度
|
||||
polarity VARCHAR(20), -- 情绪极性: positive-积极, negative-消极, neutral-中性
|
||||
confidence DECIMAL(3, 2), -- 置信度
|
||||
emotions JSON, -- 情绪分布详情
|
||||
keywords JSON, -- 关键词列表
|
||||
suggestion TEXT, -- 建议
|
||||
analysis_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 分析时间
|
||||
metadata JSON, -- 扩展元数据
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
user_id VARCHAR(36) COMMENT '用户ID', -- 用户ID
|
||||
message_id VARCHAR(36) COMMENT '关联消息ID', -- 关联消息ID
|
||||
text TEXT COMMENT '分析文本', -- 分析文本
|
||||
primary_emotion VARCHAR(50) COMMENT '主要情绪', -- 主要情绪
|
||||
intensity DECIMAL(3, 2) COMMENT '情绪强度', -- 情绪强度
|
||||
polarity VARCHAR(20) COMMENT '情绪极性: positive-积极, negative-消极, neutral-中性', -- 情绪极性: positive-积极, negative-消极, neutral-中性
|
||||
confidence DECIMAL(3, 2) COMMENT '置信度', -- 置信度
|
||||
emotions JSON COMMENT '情绪分布详情', -- 情绪分布详情
|
||||
keywords JSON COMMENT '关键词列表', -- 关键词列表
|
||||
suggestion TEXT COMMENT '建议', -- 建议
|
||||
analysis_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '分析时间', -- 分析时间
|
||||
metadata JSON COMMENT '扩展元数据', -- 扩展元数据
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '情绪分析表';
|
||||
|
||||
-- ============================================================================
|
||||
-- 6. 情绪记录表 (emotion_record)
|
||||
-- ============================================================================
|
||||
CREATE TABLE emotion_record (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
user_id VARCHAR(36) , -- 用户ID
|
||||
record_date DATE , -- 记录日期
|
||||
emotion_type VARCHAR(50) , -- 情绪类型
|
||||
intensity DECIMAL(3, 2) , -- 情绪强度
|
||||
triggers TEXT, -- 触发因素
|
||||
description TEXT, -- 描述
|
||||
tags JSON, -- 标签
|
||||
weather VARCHAR(50), -- 天气
|
||||
location VARCHAR(100), -- 地点
|
||||
activity VARCHAR(100), -- 活动
|
||||
people VARCHAR(200), -- 相关人物
|
||||
notes TEXT, -- 备注
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
user_id VARCHAR(36) COMMENT '用户ID', -- 用户ID
|
||||
record_date DATE COMMENT '记录日期', -- 记录日期
|
||||
emotion_type VARCHAR(50) COMMENT '情绪类型', -- 情绪类型
|
||||
intensity DECIMAL(3, 2) COMMENT '情绪强度', -- 情绪强度
|
||||
triggers TEXT COMMENT '触发因素', -- 触发因素
|
||||
description TEXT COMMENT '描述', -- 描述
|
||||
tags JSON COMMENT '标签', -- 标签
|
||||
weather VARCHAR(50) COMMENT '天气', -- 天气
|
||||
location VARCHAR(100) COMMENT '地点', -- 地点
|
||||
activity VARCHAR(100) COMMENT '活动', -- 活动
|
||||
people VARCHAR(200) COMMENT '相关人物', -- 相关人物
|
||||
notes TEXT COMMENT '备注', -- 备注
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '情绪记录表';
|
||||
|
||||
-- ============================================================================
|
||||
-- 7. 成长课题表 (growth_topic)
|
||||
-- ============================================================================
|
||||
CREATE TABLE growth_topic (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
title VARCHAR(100) , -- 课题标题
|
||||
category VARCHAR(50) , -- 分类
|
||||
difficulty VARCHAR(20) , -- 难度: easy-简单, medium-中等, hard-困难
|
||||
description TEXT, -- 描述
|
||||
content TEXT, -- 内容
|
||||
duration_days INT, -- 持续天数
|
||||
unlock_conditions JSON, -- 解锁条件
|
||||
is_unlocked TINYINT DEFAULT 1, -- 是否解锁
|
||||
progress DECIMAL(5, 2) DEFAULT 0.00, -- 进度百分比
|
||||
completed_time DATETIME, -- 完成时间
|
||||
rewards JSON, -- 奖励
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
title VARCHAR(100) COMMENT '课题标题', -- 课题标题
|
||||
category VARCHAR(50) COMMENT '分类', -- 分类
|
||||
difficulty VARCHAR(20) COMMENT '难度: easy-简单, medium-中等, hard-困难', -- 难度: easy-简单, medium-中等, hard-困难
|
||||
description TEXT COMMENT '描述', -- 描述
|
||||
content TEXT COMMENT '内容', -- 内容
|
||||
duration_days INT COMMENT '持续天数', -- 持续天数
|
||||
unlock_conditions JSON COMMENT '解锁条件', -- 解锁条件
|
||||
is_unlocked TINYINT DEFAULT 1 COMMENT '是否解锁', -- 是否解锁
|
||||
progress DECIMAL(5, 2) DEFAULT 0.00 COMMENT '进度百分比', -- 进度百分比
|
||||
completed_time DATETIME COMMENT '完成时间', -- 完成时间
|
||||
rewards JSON COMMENT '奖励', -- 奖励
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '成长课题表';
|
||||
|
||||
-- ============================================================================
|
||||
-- 8. 课题互动表 (topic_interaction)
|
||||
-- ============================================================================
|
||||
CREATE TABLE topic_interaction (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
topic_id VARCHAR(36) , -- 课题ID
|
||||
type VARCHAR(50) , -- 互动类型
|
||||
content TEXT, -- 内容
|
||||
user_input TEXT, -- 用户输入
|
||||
ai_response TEXT, -- AI回应
|
||||
rating INT, -- 评分
|
||||
feedback TEXT, -- 反馈
|
||||
completed_time DATETIME, -- 完成时间
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
topic_id VARCHAR(36) COMMENT '课题ID', -- 课题ID
|
||||
type VARCHAR(50) COMMENT '互动类型', -- 互动类型
|
||||
content TEXT COMMENT '内容', -- 内容
|
||||
user_input TEXT COMMENT '用户输入', -- 用户输入
|
||||
ai_response TEXT COMMENT 'AI回应', -- AI回应
|
||||
rating INT COMMENT '评分', -- 评分
|
||||
feedback TEXT COMMENT '反馈', -- 反馈
|
||||
completed_time DATETIME COMMENT '完成时间', -- 完成时间
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '课题互动表';
|
||||
|
||||
-- ============================================================================
|
||||
-- 9. 地点标记表 (location_pin)
|
||||
-- ============================================================================
|
||||
CREATE TABLE location_pin (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
name VARCHAR(100) , -- 地点名称
|
||||
type VARCHAR(50) , -- 地点类型
|
||||
category VARCHAR(50), -- 地点分类
|
||||
latitude DECIMAL(10, 8) , -- 纬度
|
||||
longitude DECIMAL(11, 8) , -- 经度
|
||||
address VARCHAR(200), -- 地址
|
||||
description TEXT, -- 描述
|
||||
created_by VARCHAR(36), -- 创建者
|
||||
likes INT DEFAULT 0, -- 点赞数
|
||||
visits INT DEFAULT 0, -- 访问数
|
||||
is_bookmarked TINYINT DEFAULT 0, -- 是否收藏
|
||||
last_visit_time DATETIME, -- 最后访问时间
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
name VARCHAR(100) COMMENT '地点名称', -- 地点名称
|
||||
type VARCHAR(50) COMMENT '地点类型', -- 地点类型
|
||||
category VARCHAR(50) COMMENT '地点分类', -- 地点分类
|
||||
latitude DECIMAL(10, 8) COMMENT '纬度', -- 纬度
|
||||
longitude DECIMAL(11, 8) COMMENT '经度', -- 经度
|
||||
address VARCHAR(200) COMMENT '地址', -- 地址
|
||||
description TEXT COMMENT '描述', -- 描述
|
||||
created_by VARCHAR(36) COMMENT '创建者', -- 创建者
|
||||
likes INT DEFAULT 0 COMMENT '点赞数', -- 点赞数
|
||||
visits INT DEFAULT 0 COMMENT '访问数', -- 访问数
|
||||
is_bookmarked TINYINT DEFAULT 0 COMMENT '是否收藏', -- 是否收藏
|
||||
last_visit_time DATETIME COMMENT '最后访问时间', -- 最后访问时间
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '地点标记表';
|
||||
|
||||
-- ============================================================================
|
||||
-- 10. 社区帖子表 (community_post)
|
||||
-- ============================================================================
|
||||
CREATE TABLE community_post (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
user_id VARCHAR(36) , -- 用户ID
|
||||
location_id VARCHAR(36), -- 地点ID
|
||||
title VARCHAR(200), -- 标题
|
||||
content TEXT , -- 内容
|
||||
type VARCHAR(50) , -- 帖子类型
|
||||
images JSON, -- 图片列表
|
||||
tags JSON, -- 标签
|
||||
likes INT DEFAULT 0, -- 点赞数
|
||||
view_count INT DEFAULT 0, -- 浏览数
|
||||
comment_count INT DEFAULT 0, -- 评论数
|
||||
is_private TINYINT DEFAULT 0, -- 是否私密
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
user_id VARCHAR(36) COMMENT '用户ID', -- 用户ID
|
||||
location_id VARCHAR(36) COMMENT '地点ID', -- 地点ID
|
||||
title VARCHAR(200) COMMENT '标题', -- 标题
|
||||
content TEXT COMMENT '内容', -- 内容
|
||||
type VARCHAR(50) COMMENT '帖子类型', -- 帖子类型
|
||||
images JSON COMMENT '图片列表', -- 图片列表
|
||||
tags JSON COMMENT '标签', -- 标签
|
||||
likes INT DEFAULT 0 COMMENT '点赞数', -- 点赞数
|
||||
view_count INT DEFAULT 0 COMMENT '浏览数', -- 浏览数
|
||||
comment_count INT DEFAULT 0 COMMENT '评论数', -- 评论数
|
||||
is_private TINYINT DEFAULT 0 COMMENT '是否私密', -- 是否私密
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社区帖子表';
|
||||
|
||||
-- ============================================================================
|
||||
-- 11. 评论表 (comment)
|
||||
-- ============================================================================
|
||||
CREATE TABLE comment (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
post_id VARCHAR(36) , -- 帖子ID
|
||||
user_id VARCHAR(36) , -- 用户ID
|
||||
content TEXT , -- 评论内容
|
||||
reply_to_id VARCHAR(36), -- 回复的评论ID
|
||||
likes INT DEFAULT 0, -- 点赞数
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
post_id VARCHAR(36) COMMENT '帖子ID', -- 帖子ID
|
||||
user_id VARCHAR(36) COMMENT '用户ID', -- 用户ID
|
||||
content TEXT COMMENT '评论内容', -- 评论内容
|
||||
reply_to_id VARCHAR(36) COMMENT '回复的评论ID', -- 回复的评论ID
|
||||
likes INT DEFAULT 0 COMMENT '点赞数', -- 点赞数
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '评论表';
|
||||
|
||||
-- ============================================================================
|
||||
-- 12. 成就表 (achievement)
|
||||
-- ============================================================================
|
||||
CREATE TABLE achievement (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
title VARCHAR(100) , -- 成就标题
|
||||
description TEXT, -- 描述
|
||||
category VARCHAR(50) , -- 分类
|
||||
icon VARCHAR(200), -- 图标
|
||||
rarity VARCHAR(20) , -- 稀有度
|
||||
condition_type VARCHAR(50), -- 条件类型
|
||||
condition_value JSON, -- 条件值
|
||||
rewards JSON, -- 奖励
|
||||
unlocked_time DATETIME, -- 解锁时间
|
||||
progress DECIMAL(5, 2) DEFAULT 0.00, -- 进度
|
||||
is_hidden TINYINT DEFAULT 0, -- 是否隐藏
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
title VARCHAR(100) COMMENT '成就标题', -- 成就标题
|
||||
description TEXT COMMENT '描述', -- 描述
|
||||
category VARCHAR(50) COMMENT '分类', -- 分类
|
||||
icon VARCHAR(200) COMMENT '图标', -- 图标
|
||||
rarity VARCHAR(20) COMMENT '稀有度', -- 稀有度
|
||||
condition_type VARCHAR(50) COMMENT '条件类型', -- 条件类型
|
||||
condition_value JSON COMMENT '条件值', -- 条件值
|
||||
rewards JSON COMMENT '奖励', -- 奖励
|
||||
unlocked_time DATETIME COMMENT '解锁时间', -- 解锁时间
|
||||
progress DECIMAL(5, 2) DEFAULT 0.00 COMMENT '进度', -- 进度
|
||||
is_hidden TINYINT DEFAULT 0 COMMENT '是否隐藏', -- 是否隐藏
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '成就表';
|
||||
|
||||
-- ============================================================================
|
||||
-- 13. 奖励表 (reward)
|
||||
-- ============================================================================
|
||||
CREATE TABLE reward (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
topic_id VARCHAR(36), -- 课题ID
|
||||
achievement_id VARCHAR(36), -- 成就ID
|
||||
type VARCHAR(50) , -- 奖励类型
|
||||
name VARCHAR(100) , -- 奖励名称
|
||||
description TEXT, -- 描述
|
||||
icon VARCHAR(200), -- 图标
|
||||
rarity VARCHAR(20), -- 稀有度
|
||||
value JSON, -- 奖励值
|
||||
earned_time DATETIME, -- 获得时间
|
||||
is_new TINYINT DEFAULT 1, -- 是否新获得
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
topic_id VARCHAR(36) COMMENT '课题ID', -- 课题ID
|
||||
achievement_id VARCHAR(36) COMMENT '成就ID', -- 成就ID
|
||||
type VARCHAR(50) COMMENT '奖励类型', -- 奖励类型
|
||||
name VARCHAR(100) COMMENT '奖励名称', -- 奖励名称
|
||||
description TEXT COMMENT '描述', -- 描述
|
||||
icon VARCHAR(200) COMMENT '图标', -- 图标
|
||||
rarity VARCHAR(20) COMMENT '稀有度', -- 稀有度
|
||||
value JSON COMMENT '奖励值', -- 奖励值
|
||||
earned_time DATETIME COMMENT '获得时间', -- 获得时间
|
||||
is_new TINYINT DEFAULT 1 COMMENT '是否新获得', -- 是否新获得
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '奖励表';
|
||||
|
||||
-- ============================================================================
|
||||
-- 14. 访客用户表 (guest_user)
|
||||
-- ============================================================================
|
||||
CREATE TABLE guest_user (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
guest_user_id VARCHAR(50) UNIQUE, -- 访客用户ID (格式: guest_xxx)
|
||||
ip_address VARCHAR(45) , -- 客户端IP地址 (支持IPv6)
|
||||
user_agent TEXT, -- 用户代理信息
|
||||
nickname VARCHAR(50), -- 访客昵称
|
||||
avatar VARCHAR(500), -- 访客头像
|
||||
last_active_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 最后活跃时间
|
||||
conversation_count INT DEFAULT 0, -- 会话数量
|
||||
message_count INT DEFAULT 0, -- 消息数量
|
||||
location VARCHAR(100), -- IP地址的地理位置信息
|
||||
device_info VARCHAR(200), -- 设备信息
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
guest_user_id VARCHAR(50) UNIQUE COMMENT '访客用户ID (格式: guest_xxx)', -- 访客用户ID (格式: guest_xxx)
|
||||
ip_address VARCHAR(45) COMMENT '客户端IP地址 (支持IPv6)', -- 客户端IP地址 (支持IPv6)
|
||||
user_agent TEXT COMMENT '用户代理信息', -- 用户代理信息
|
||||
nickname VARCHAR(50) COMMENT '访客昵称', -- 访客昵称
|
||||
avatar VARCHAR(500) COMMENT '访客头像', -- 访客头像
|
||||
last_active_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '最后活跃时间', -- 最后活跃时间
|
||||
conversation_count INT DEFAULT 0 COMMENT '会话数量', -- 会话数量
|
||||
message_count INT DEFAULT 0 COMMENT '消息数量', -- 消息数量
|
||||
location VARCHAR(100) COMMENT 'IP地址的地理位置信息', -- IP地址的地理位置信息
|
||||
device_info VARCHAR(200) COMMENT '设备信息', -- 设备信息
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '访客用户表';
|
||||
|
||||
-- ============================================================================
|
||||
-- 15. 用户统计表 (user_stats)
|
||||
-- ============================================================================
|
||||
CREATE TABLE user_stats (
|
||||
id VARCHAR(36) PRIMARY KEY, -- UUID主键
|
||||
user_id VARCHAR(36) UNIQUE, -- 用户ID
|
||||
total_conversations INT DEFAULT 0, -- 总对话数
|
||||
total_messages INT DEFAULT 0, -- 总消息数
|
||||
total_emotions_recorded INT DEFAULT 0, -- 总情绪记录数
|
||||
topics_completed INT DEFAULT 0, -- 完成的课题数
|
||||
achievements_unlocked INT DEFAULT 0, -- 解锁的成就数
|
||||
total_points INT DEFAULT 0, -- 总积分
|
||||
consecutive_days INT DEFAULT 0, -- 连续使用天数
|
||||
max_consecutive_days INT DEFAULT 0, -- 最大连续天数
|
||||
locations_visited INT DEFAULT 0, -- 访问的地点数
|
||||
posts_created INT DEFAULT 0, -- 创建的帖子数
|
||||
comments_made INT DEFAULT 0, -- 评论数
|
||||
likes_received INT DEFAULT 0, -- 收到的点赞数
|
||||
social_interactions INT DEFAULT 0, -- 社交互动数
|
||||
id VARCHAR(36) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
|
||||
user_id VARCHAR(36) UNIQUE COMMENT '用户ID', -- 用户ID
|
||||
total_conversations INT DEFAULT 0 COMMENT '总对话数', -- 总对话数
|
||||
total_messages INT DEFAULT 0 COMMENT '总消息数', -- 总消息数
|
||||
total_emotions_recorded INT DEFAULT 0 COMMENT '总情绪记录数', -- 总情绪记录数
|
||||
topics_completed INT DEFAULT 0 COMMENT '完成的课题数', -- 完成的课题数
|
||||
achievements_unlocked INT DEFAULT 0 COMMENT '解锁的成就数', -- 解锁的成就数
|
||||
total_points INT DEFAULT 0 COMMENT '总积分', -- 总积分
|
||||
consecutive_days INT DEFAULT 0 COMMENT '连续使用天数', -- 连续使用天数
|
||||
max_consecutive_days INT DEFAULT 0 COMMENT '最大连续天数', -- 最大连续天数
|
||||
locations_visited INT DEFAULT 0 COMMENT '访问的地点数', -- 访问的地点数
|
||||
posts_created INT DEFAULT 0 COMMENT '创建的帖子数', -- 创建的帖子数
|
||||
comments_made INT DEFAULT 0 COMMENT '评论数', -- 评论数
|
||||
likes_received INT DEFAULT 0 COMMENT '收到的点赞数', -- 收到的点赞数
|
||||
social_interactions INT DEFAULT 0 COMMENT '社交互动数', -- 社交互动数
|
||||
-- 公共字段
|
||||
create_by VARCHAR(36), -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
|
||||
update_by VARCHAR(36), -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0, -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) -- 备注
|
||||
create_by VARCHAR(36) COMMENT '创建人ID', -- 创建人ID
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- 创建时间
|
||||
update_by VARCHAR(36) COMMENT '更新人ID', -- 更新人ID
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', -- 更新时间
|
||||
is_deleted TINYINT DEFAULT 0 COMMENT '是否删除: 0-未删除, 1-已删除', -- 是否删除: 0-未删除, 1-已删除
|
||||
remarks VARCHAR(500) COMMENT '备注' -- 备注
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户统计表';
|
||||
|
||||
-- ============================================================================
|
||||
|
||||
Reference in New Issue
Block a user