代码优化

This commit is contained in:
2025-10-13 10:43:08 +08:00
parent b6818b179c
commit bc3ed2d872
40 changed files with 3189 additions and 788 deletions
@@ -6,10 +6,14 @@ import com.emotion.dto.request.RegisterRequest;
import com.emotion.dto.request.RefreshTokenRequest;
import com.emotion.dto.response.AuthResponse;
import com.emotion.dto.response.CaptchaResponse;
import com.emotion.dto.response.SmsCodeResponse;
import com.emotion.dto.response.UserInfoResponse;
import com.emotion.service.AuthService;
import com.emotion.service.TokenService;
import com.emotion.util.UserContextUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@@ -24,6 +28,7 @@ import javax.validation.Valid;
*/
@RestController
@RequestMapping("/auth")
@Tag(name = "认证管理", description = "用户注册、登录、验证码等认证相关接口")
public class AuthController {
@Autowired
@@ -33,18 +38,20 @@ public class AuthController {
private TokenService tokenService;
/**
* 用户登录
* 用户登录(简化版:手机号+验证码,不存在则自动注册)
*/
@PostMapping("/login")
@Operation(summary = "用户登录", description = "使用手机号和短信验证码登录,若用户不存在则自动注册")
public Result<AuthResponse> login(@Valid @RequestBody LoginRequest request) {
AuthResponse response = authService.login(request);
return Result.success("登录成功", response);
}
/**
* 用户注册
* 用户注册(简化版:仅需手机号、密码和短信验证码)
*/
@PostMapping("/register")
@Operation(summary = "用户注册", description = "使用手机号、密码和短信验证码进行注册")
public Result<AuthResponse> register(@Valid @RequestBody RegisterRequest request) {
AuthResponse response = authService.register(request);
return Result.success("注册成功", response);
@@ -60,14 +67,27 @@ public class AuthController {
}
/**
* 生成验证码
* 生成验证码(图形验证码,用于登录)
*/
@GetMapping("/captcha")
@Operation(summary = "获取图形验证码", description = "用于登录时的图形验证码")
public Result<CaptchaResponse> generateCaptcha() {
CaptchaResponse response = authService.generateCaptcha();
return Result.success(response);
}
/**
* 获取短信验证码(用于注册)
*/
@GetMapping("/sms-code")
@Operation(summary = "获取短信验证码", description = "用于注册时的短信验证码")
public Result<SmsCodeResponse> getSmsCode(
@Parameter(description = "手机号", required = true)
@RequestParam String phone) {
SmsCodeResponse response = authService.sendSmsCode(phone);
return Result.success("验证码已发送", response);
}
/**
* 用户登出
*/
@@ -1,44 +1,60 @@
package com.emotion.controller;
import com.emotion.common.Result;
import com.emotion.dto.request.TokenRequest;
import com.emotion.dto.response.UserInfoResponse;
import com.emotion.service.TokenService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
/**
* Token控制器
* 提供基于请求头Authorization的token验证和用户信息获取功能
*
* @author emotion-museum
* @date 2025-07-23
*/
@RestController
@RequestMapping("/token")
@Tag(name = "Token管理", description = "Token验证和用户信息获取")
public class TokenController {
@Autowired
private TokenService tokenService;
/**
* 通过token获取用户信息
* 通过请求头中的token获取用户信息
* Token应该在请求头中以 "Authorization: Bearer {token}" 的形式传递
*/
@PostMapping("/user-info")
public Result<UserInfoResponse> getUserInfoByToken(@RequestBody @Validated TokenRequest request) {
UserInfoResponse userInfo = tokenService.getUserInfoByToken(request.getToken());
@GetMapping("/user-info")
@Operation(summary = "获取用户信息", description = "通过请求头中的token获取当前用户信息")
public Result<UserInfoResponse> getUserInfoByToken(HttpServletRequest request) {
UserInfoResponse userInfo = tokenService.getUserInfoByToken(request);
return Result.success(userInfo);
}
/**
* 通过token获取用户名
* 通过请求头中的token获取用户名
* Token应该在请求头中以 "Authorization: Bearer {token}" 的形式传递
*/
@PostMapping("/username")
public Result<String> getUsernameByToken(@RequestBody @Validated TokenRequest request) {
String username = tokenService.getUsernameByToken(request.getToken());
@GetMapping("/username")
@Operation(summary = "获取用户名", description = "通过请求头中的token获取当前用户名")
public Result<String> getUsernameByToken(HttpServletRequest request) {
String username = tokenService.getUsernameByToken(request);
return Result.success(username);
}
/**
* 验证token并返回用户ID
* 验证请求头中的token并返回用户ID
* Token应该在请求头中以 "Authorization: Bearer {token}" 的形式传递
*/
@PostMapping("/validate")
public Result<String> validateTokenAndGetUserId(@RequestBody @Validated TokenRequest request) {
String userId = tokenService.validateTokenAndGetUserId(request.getToken());
@GetMapping("/validate")
@Operation(summary = "验证Token", description = "验证请求头中的token并返回用户ID")
public Result<String> validateTokenAndGetUserId(HttpServletRequest request) {
String userId = tokenService.validateTokenAndGetUserId(request);
return Result.success(userId);
}
}
}
@@ -4,38 +4,31 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
/**
* 登录请求
*
* 简化版:仅需手机号和短信验证码
*
* @author emotion-museum
* @date 2025-07-23
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class LoginRequest extends BaseRequest {
/**
*
* 手机
*/
@NotBlank(message = "号不能为空")
private String account;
@NotBlank(message = "手机号不能为空")
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
private String phone;
/**
*
*/
@NotBlank(message = "密码不能为空")
private String password;
/**
* 验证码
* 短信验证
*/
@NotBlank(message = "验证码不能为空")
private String captcha;
/**
* 验证码key
*/
@NotBlank(message = "验证码key不能为空")
private String captchaKey;
@Size(min = 6, max = 6, message = "验证码必须为6位")
private String smsCode;
}
@@ -3,72 +3,39 @@ 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;
/**
* 注册请求
*
* 简化版:仅需要手机号、密码和验证码
*
* @author emotion-museum
* @date 2025-07-23
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class RegisterRequest extends BaseRequest {
/**
* 账号
* 手机号(作为账号
*/
@NotBlank(message = "号不能为空")
@Size(min = 3, max = 20, message = "账号长度必须在3-20个字符之间")
private String account;
@NotBlank(message = "手机号不能为空")
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
private String phone;
/**
* 密码
*/
@NotBlank(message = "密码不能为空")
@Size(min = 6, max = 20, message = "密码长度必须在6-20个字符之间")
private String password;
/**
* 确认密
*/
@NotBlank(message = "确认密码不能为空")
private String confirmPassword;
/**
* 用户名
*/
private String username;
/**
* 昵称
*/
private String nickname;
/**
* 邮箱
*/
@Email(message = "邮箱格式不正确")
private String email;
/**
* 手机号
*/
@Pattern(regexp = "^$|^1[3-9]\\d{9}$", message = "手机号格式不正确")
private String phone;
/**
* 验证码
* 短信验证
*/
@NotBlank(message = "验证码不能为空")
private String captcha;
/**
* 验证码key
*/
@NotBlank(message = "验证码key不能为空")
private String captchaKey;
@Size(min = 6, max = 6, message = "验证码必须为6位")
private String smsCode;
}
@@ -1,16 +0,0 @@
package com.emotion.dto.request;
import javax.validation.constraints.NotBlank;
public class TokenRequest {
@NotBlank(message = "token不能为空")
private String token;
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
}
@@ -0,0 +1,35 @@
package com.emotion.dto.response;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 短信验证码响应
*
* @author emotion-museum
* @date 2025-10-06
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SmsCodeResponse {
/**
* 验证码(开发环境返回,生产环境不返回)
*/
private String code;
/**
* 过期时间(秒)
*/
private Long expiresIn;
/**
* 提示信息
*/
private String message;
}
@@ -1,62 +0,0 @@
package com.emotion.dto.response;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDateTime;
/**
* WebSocket响应对象
*
* @author emotion-museum
* @date 2025-09-08
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class WebSocketResponse extends BaseResponse {
/**
* 消息ID
*/
private String messageId;
/**
* 会话ID
*/
private String conversationId;
/**
* 消息类型
*/
private String type;
/**
* 消息内容
*/
private String content;
/**
* 发送者ID
*/
private String senderId;
/**
* 发送者类型
*/
private String senderType;
/**
* 消息状态
*/
private String status;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 扩展数据
*/
private Object data;
}
@@ -22,7 +22,7 @@ import java.time.LocalDateTime;
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@TableName("achievement")
@TableName("t_achievement")
public class Achievement extends BaseEntity {
/**
@@ -19,7 +19,7 @@ import lombok.EqualsAndHashCode;
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@TableName("comment")
@TableName("t_comment")
public class Comment extends BaseEntity {
/**
@@ -19,7 +19,7 @@ import lombok.EqualsAndHashCode;
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@TableName("community_post")
@TableName("t_community_post")
public class CommunityPost extends BaseEntity {
/**
@@ -22,7 +22,7 @@ import java.time.LocalDateTime;
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@TableName("conversation")
@TableName("t_conversation")
public class Conversation extends BaseEntity {
/**
@@ -22,7 +22,7 @@ import java.time.LocalDateTime;
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@TableName("coze_api_call")
@TableName("t_coze_api_call")
public class CozeApiCall extends BaseEntity {
/**
@@ -22,7 +22,7 @@ import java.time.LocalDateTime;
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@TableName("diary_comment")
@TableName("t_diary_comment")
public class DiaryComment extends BaseEntity {
/**
@@ -22,7 +22,7 @@ import java.time.LocalDateTime;
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@TableName("diary_post")
@TableName("t_diary_post")
public class DiaryPost extends BaseEntity {
/**
@@ -22,7 +22,7 @@ import java.time.LocalDateTime;
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@TableName("emotion_analysis")
@TableName("t_emotion_analysis")
public class EmotionAnalysis extends BaseEntity {
/**
@@ -22,7 +22,7 @@ import java.time.LocalDate;
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@TableName("emotion_record")
@TableName("t_emotion_record")
public class EmotionRecord extends BaseEntity {
/**
@@ -22,7 +22,7 @@ import java.time.LocalDateTime;
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@TableName("growth_topic")
@TableName("t_growth_topic")
public class GrowthTopic extends BaseEntity {
/**
@@ -21,7 +21,7 @@ import java.time.LocalDateTime;
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@TableName("guest_user")
@TableName("t_guest_user")
public class GuestUser extends BaseEntity {
/**
@@ -22,7 +22,7 @@ import java.time.LocalDateTime;
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@TableName("location_pin")
@TableName("t_location_pin")
public class LocationPin extends BaseEntity {
/**
@@ -22,7 +22,7 @@ import java.time.LocalDateTime;
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@TableName("message")
@TableName("t_message")
public class Message extends BaseEntity {
/**
@@ -21,7 +21,7 @@ import java.time.LocalDateTime;
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@TableName("reward")
@TableName("t_reward")
public class Reward extends BaseEntity {
/**
@@ -21,7 +21,7 @@ import java.time.LocalDateTime;
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@TableName("topic_interaction")
@TableName("t_topic_interaction")
public class TopicInteraction extends BaseEntity {
/**
@@ -23,7 +23,7 @@ import java.time.LocalDateTime;
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@TableName("user")
@TableName("t_user")
public class User extends BaseEntity {
/**
@@ -19,7 +19,7 @@ import lombok.EqualsAndHashCode;
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@TableName("user_stats")
@TableName("t_user_stats")
public class UserStats extends BaseEntity {
/**
@@ -4,6 +4,7 @@ import com.emotion.dto.request.LoginRequest;
import com.emotion.dto.request.RegisterRequest;
import com.emotion.dto.response.AuthResponse;
import com.emotion.dto.response.CaptchaResponse;
import com.emotion.dto.response.SmsCodeResponse;
import com.emotion.dto.response.UserInfoResponse;
import javax.servlet.http.HttpServletRequest;
@@ -136,4 +137,21 @@ public interface AuthService {
* @return 是否存在
*/
boolean existsByPhone(String phone);
/**
* 发送短信验证码
*
* @param phone 手机号
* @return 短信验证码响应
*/
SmsCodeResponse sendSmsCode(String phone);
/**
* 验证短信验证码
*
* @param phone 手机号
* @param code 验证码
* @return 是否验证成功
*/
boolean validateSmsCode(String phone, String code);
}
@@ -9,14 +9,16 @@ import com.emotion.dto.request.UserProfileUpdateRequest;
import com.emotion.dto.response.UserResponse;
import com.emotion.entity.User;
import java.time.LocalDateTime;
/**
* 用户服务接口
*
*
* @author emotion-museum
* @date 2025-07-23
*/
public interface UserService extends IService<User> {
/**
* 分页查询用户响应
*/
@@ -51,4 +53,39 @@ public interface UserService extends IService<User> {
* 删除用户
*/
boolean deleteUser(String id);
/**
* 根据账号获取用户
*/
User getByAccount(String account);
/**
* 根据邮箱获取用户
*/
User getByEmail(String email);
/**
* 根据手机号获取用户
*/
User getByPhone(String phone);
/**
* 创建用户
*
* @param account 账号
* @param username 用户名
* @param password 密码(明文,会在方法内加密)
* @param email 邮箱(可为null
* @param phone 手机号(可为null
* @return 创建的用户
*/
User createUser(String account, String username, String password, String email, String phone);
/**
* 更新用户最后活跃时间
*
* @param userId 用户ID
* @param lastActiveTime 最后活跃时间
*/
void updateLastActiveTime(String userId, LocalDateTime lastActiveTime);
}
@@ -4,6 +4,7 @@ import com.emotion.dto.request.LoginRequest;
import com.emotion.dto.request.RegisterRequest;
import com.emotion.dto.response.AuthResponse;
import com.emotion.dto.response.CaptchaResponse;
import com.emotion.dto.response.SmsCodeResponse;
import com.emotion.dto.response.UserInfoResponse;
import com.emotion.entity.User;
import com.emotion.exception.AuthException;
@@ -61,34 +62,36 @@ public class AuthServiceImpl implements AuthService {
private TokenUtil tokenUtil;
private static final String CAPTCHA_PREFIX = "captcha:";
private static final String SMS_CODE_PREFIX = "sms_code:";
private static final String TOKEN_PREFIX = "token:";
private static final String REFRESH_TOKEN_PREFIX = "refresh_token:";
private static final int CAPTCHA_EXPIRE_MINUTES = 5;
private static final int SMS_CODE_EXPIRE_MINUTES = 5;
private static final int TOKEN_EXPIRE_HOURS = 24;
private static final int REFRESH_TOKEN_EXPIRE_DAYS = 7;
private static final String DEFAULT_SMS_CODE = "123456";
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Override
public AuthResponse login(LoginRequest request) {
// 验证验证码
if (!validateCaptcha(request.getCaptchaKey(), request.getCaptcha())) {
// 验证短信验证码
if (!validateSmsCode(request.getPhone(), request.getSmsCode())) {
throw new CaptchaException("验证码错误或已过期");
}
// 根据号查询用户
User user = userService.getByAccount(request.getAccount());
// 根据手机号查询用户
User user = userService.getByPhone(request.getPhone());
// 如果用户不存在,则自动注册
if (user == null) {
throw new AuthException("账号不存在");
}
// 验证密码(这里应该使用加密后的密码比较)
if (!verifyPassword(request.getPassword(), user.getPassword())) {
throw new AuthException("密码错误");
}
// 检查用户状态
if (user.getStatus() != 1) {
throw new AuthException("账号已被禁用");
log.info("用户不存在,自动注册: phone={}", request.getPhone());
user = autoRegisterUser(request.getPhone());
} else {
// 检查用户状态
if (user.getStatus() != 1) {
throw new AuthException("账号已被禁用");
}
log.info("用户登录: phone={}, userId={}", request.getPhone(), user.getId());
}
// 生成令牌
@@ -111,61 +114,31 @@ public class AuthServiceImpl implements AuthService {
@Override
public AuthResponse register(RegisterRequest request) {
// 验证验证码
if (!validateCaptcha(request.getCaptchaKey(), request.getCaptcha())) {
// 验证短信验证码
if (!validateSmsCode(request.getPhone(), request.getSmsCode())) {
throw new CaptchaException("验证码错误或已过期");
}
// 验证密码确认
if (!request.getPassword().equals(request.getConfirmPassword())) {
throw new BusinessException("密码与确认密码不一致");
// 检查手机号是否已存在
if (userService.getByPhone(request.getPhone()) != null) {
throw new BusinessException("手机号已被注册");
}
// 检查账号是否已存在
if (userService.getByAccount(request.getAccount()) != null) {
throw new BusinessException("账号已存在");
}
// 生成随机用户名:开心 + 6位随机大小写字母和数字
String username = generateRandomUsername();
// 检查邮箱是否已存在(只有当邮箱不为空时才检查)
if (StringUtils.hasText(request.getEmail()) && userService.getByEmail(request.getEmail()) != null) {
throw new BusinessException("邮箱已被使用");
}
// 检查手机号是否已存在(只有当手机号不为空时才检查)
if (StringUtils.hasText(request.getPhone()) && userService.getByPhone(request.getPhone()) != null) {
throw new BusinessException("手机号已被使用");
}
// 处理用户名:如果为空则使用账号
String username = StringUtils.hasText(request.getUsername()) ? request.getUsername() : request.getAccount();
// 处理邮箱:如果为空字符串则设为null
String email = StringUtils.hasText(request.getEmail()) ? request.getEmail() : null;
// 处理手机号:如果为空字符串则设为null
String phone = StringUtils.hasText(request.getPhone()) ? request.getPhone() : null;
// 使用手机号作为账号
String account = request.getPhone();
// 创建用户(密码在UserService中加密,这里不需要预先加密)
User user = userService.createUser(
request.getAccount(),
account,
username,
request.getPassword(),
email,
phone
null, // 邮箱为空
request.getPhone()
);
// 设置昵称(如果昵称为空则使用用户名)
if (StringUtils.hasText(request.getNickname())) {
user.setNickname(request.getNickname());
} else if (StringUtils.hasText(username)) {
user.setNickname(username);
}
// 如果有昵称变更,更新用户信息
if (StringUtils.hasText(user.getNickname())) {
userService.updateById(user);
}
// 生成令牌
String accessToken = generateAccessToken(user);
String refreshToken = generateRefreshToken(user);
@@ -178,6 +151,7 @@ public class AuthServiceImpl implements AuthService {
response.setUserInfo(convertToUserInfoResponse(user));
response.setLoginTime(LocalDateTime.now().format(DATE_TIME_FORMATTER));
log.info("用户注册成功: phone={}, username={}", request.getPhone(), username);
return response;
}
@@ -510,4 +484,132 @@ public class AuthServiceImpl implements AuthService {
User user = userService.getByPhone(phone);
return user != null;
}
@Override
public SmsCodeResponse sendSmsCode(String phone) {
// 验证手机号格式
if (!StringUtils.hasText(phone) || !phone.matches("^1[3-9]\\d{9}$")) {
throw new BusinessException("手机号格式不正确");
}
// 检查手机号是否已注册,用于提示信息
boolean isRegistered = existsByPhone(phone);
String message;
if (isRegistered) {
message = "验证码已发送,用于登录验证,有效期" + SMS_CODE_EXPIRE_MINUTES + "分钟";
} else {
message = "验证码已发送,用于注册验证,有效期" + SMS_CODE_EXPIRE_MINUTES + "分钟";
}
// TODO: 接入真实的短信服务商(阿里云、腾讯云等)
// 目前使用固定验证码 123456
String code = DEFAULT_SMS_CODE;
// 将验证码存储到Redis,有效期5分钟
String key = SMS_CODE_PREFIX + phone;
redisTemplate.opsForValue().set(key, code, SMS_CODE_EXPIRE_MINUTES, TimeUnit.MINUTES);
log.info("发送短信验证码: phone={}, code={}, isRegistered={}", phone, code, isRegistered);
// 构建响应
return SmsCodeResponse.builder()
.code(code) // 开发环境返回验证码,生产环境应该删除此行
.expiresIn((long) SMS_CODE_EXPIRE_MINUTES * 60)
.message(message)
.build();
}
@Override
public boolean validateSmsCode(String phone, String code) {
if (!StringUtils.hasText(phone) || !StringUtils.hasText(code)) {
return false;
}
String key = SMS_CODE_PREFIX + phone;
String storedCode = (String) redisTemplate.opsForValue().get(key);
if (storedCode == null) {
log.warn("短信验证码不存在或已过期: phone={}", phone);
return false;
}
boolean isValid = storedCode.equals(code);
// 验证成功后删除验证码(一次性使用)
if (isValid) {
redisTemplate.delete(key);
log.info("短信验证码验证成功: phone={}", phone);
} else {
log.warn("短信验证码错误: phone={}, expected={}, actual={}", phone, storedCode, code);
}
return isValid;
}
/**
* 生成随机用户名
* 格式:开心 + 6位随机大小写字母和数字
*
* @return 随机用户名
*/
private String generateRandomUsername() {
String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuilder sb = new StringBuilder("开心");
for (int i = 0; i < 6; i++) {
int index = random.nextInt(chars.length());
sb.append(chars.charAt(index));
}
return sb.toString();
}
/**
* 自动注册用户(用于登录时用户不存在的情况)
*
* @param phone 手机号
* @return 新创建的用户
*/
private User autoRegisterUser(String phone) {
// 生成随机用户名:开心 + 6位随机大小写字母和数字
String username = generateRandomUsername();
// 使用手机号作为账号
String account = phone;
// 生成随机密码(用户可以后续修改)
String randomPassword = generateRandomPassword();
// 创建用户
User user = userService.createUser(
account,
username,
randomPassword,
null, // 邮箱为空
phone
);
log.info("自动注册用户成功: phone={}, username={}, userId={}", phone, username, user.getId());
return user;
}
/**
* 生成随机密码
* 格式:8位随机大小写字母和数字
*
* @return 随机密码
*/
private String generateRandomPassword() {
String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 8; i++) {
int index = random.nextInt(chars.length());
sb.append(chars.charAt(index));
}
return sb.toString();
}
}
@@ -245,6 +245,69 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
return this.updateById(user);
}
@Override
public User getByAccount(String account) {
if (!StringUtils.hasText(account)) {
return null;
}
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getAccount, account)
.eq(User::getIsDeleted, 0);
return this.getOne(wrapper);
}
@Override
public User getByEmail(String email) {
if (!StringUtils.hasText(email)) {
return null;
}
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getEmail, email)
.eq(User::getIsDeleted, 0);
return this.getOne(wrapper);
}
@Override
public User getByPhone(String phone) {
if (!StringUtils.hasText(phone)) {
return null;
}
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getPhone, phone)
.eq(User::getIsDeleted, 0);
return this.getOne(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.setNickname(username); // 默认昵称与用户名相同
user.setPassword(passwordEncoder.encode(password)); // 加密密码
user.setEmail(email);
user.setPhone(phone);
user.setMemberLevel("free"); // 默认免费会员
user.setStatus(1); // 默认启用
user.setIsVerified(0); // 默认未验证
user.setLastActiveTime(LocalDateTime.now());
this.save(user);
return user;
}
@Override
public void updateLastActiveTime(String userId, LocalDateTime lastActiveTime) {
if (!StringUtils.hasText(userId) || lastActiveTime == null) {
return;
}
User user = this.getById(userId);
if (user != null && user.getIsDeleted() == 0) {
user.setLastActiveTime(lastActiveTime);
this.updateById(user);
}
}
/**
* 转换为响应对象
*/
@@ -8,9 +8,9 @@ spring:
# 数据库配置 - 本地MySQL
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://47.111.10.27:3306/emotion?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true
url: jdbc:mysql://localhost:3306/emotion_museum?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: EmotionMuseum2025*#
password: 123456
hikari:
minimum-idle: 5
maximum-pool-size: 20
@@ -8,9 +8,9 @@ spring:
# 数据库配置 - 生产MySQL
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://47.111.10.27:3306/emotion?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true
username: emotion
password: EmotionDB2024!
url: jdbc:mysql://101.200.208.45:3306/emotion_museum?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: EmotionMuseum2025*#
hikari:
minimum-idle: 10
maximum-pool-size: 50
@@ -24,7 +24,7 @@ spring:
# Redis配置 - 生产Redis
redis:
host: localhost
host: 101.200.208.45
port: 6379
timeout: 5000ms
database: 0
@@ -8,7 +8,7 @@ spring:
# 数据库配置 - 测试MySQL
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://47.111.10.27:3306/emotion?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true
url: jdbc:mysql://101.200.208.45:3306/emotion_museum?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: EmotionMuseum2025*#
hikari:
@@ -24,7 +24,7 @@ spring:
# Redis配置 - 测试Redis
redis:
host: localhost
host: 101.200.208.45
port: 6379
timeout: 3000ms
database: 1
@@ -22,11 +22,11 @@ SET
time_zone = "+00:00";
-- 创建数据库
CREATE DATABASE IF NOT EXISTS emotion DEFAULT CHARACTER
CREATE DATABASE IF NOT EXISTS emotion_museum DEFAULT CHARACTER
SET
utf8mb4 COLLATE utf8mb4_unicode_ci;
USE emotion;
USE emotion_museum;
-- ============================================================================
-- 数据库设计原则
@@ -40,40 +40,44 @@ USE emotion;
-- 删除现有表(开发阶段确保表结构最新)
-- 警告: 这会删除所有数据!
-- ============================================================================
DROP TABLE IF EXISTS user_stats;
DROP TABLE IF EXISTS t_user_stats;
DROP TABLE IF EXISTS guest_user;
DROP TABLE IF EXISTS t_guest_user;
DROP TABLE IF EXISTS reward;
DROP TABLE IF EXISTS t_reward;
DROP TABLE IF EXISTS achievement;
DROP TABLE IF EXISTS t_achievement;
DROP TABLE IF EXISTS comment;
DROP TABLE IF EXISTS t_comment;
DROP TABLE IF EXISTS community_post;
DROP TABLE IF EXISTS t_community_post;
DROP TABLE IF EXISTS location_pin;
DROP TABLE IF EXISTS t_location_pin;
DROP TABLE IF EXISTS topic_interaction;
DROP TABLE IF EXISTS t_topic_interaction;
DROP TABLE IF EXISTS growth_topic;
DROP TABLE IF EXISTS t_growth_topic;
DROP TABLE IF EXISTS emotion_record;
DROP TABLE IF EXISTS t_emotion_record;
DROP TABLE IF EXISTS emotion_analysis;
DROP TABLE IF EXISTS t_emotion_analysis;
DROP TABLE IF EXISTS coze_api_call;
DROP TABLE IF EXISTS t_coze_api_call;
DROP TABLE IF EXISTS message;
DROP TABLE IF EXISTS t_message;
DROP TABLE IF EXISTS conversation;
DROP TABLE IF EXISTS t_conversation;
DROP TABLE IF EXISTS user;
DROP TABLE IF EXISTS t_diary_post;
DROP TABLE IF EXISTS t_diary_comment;
DROP TABLE IF EXISTS t_user;
-- ============================================================================
-- 1. 用户表 (user)
-- ============================================================================
CREATE TABLE user (
CREATE TABLE t_user (
id VARCHAR(64) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
account VARCHAR(50) UNIQUE COMMENT '账号', -- 账号
password VARCHAR(255) COMMENT '密码(加密后)', -- 密码(加密后)
@@ -107,15 +111,15 @@ CREATE TABLE user (
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 = '用户表';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户表 (t_user)';
-- ============================================================================
-- 2. 对话表 (conversation)
-- 关联说明: user_id 关联 user.id,通过代码逻辑维护关联关系
-- 2. 对话表 (t_conversation)
-- 关联说明: user_id 关联 t_user.id,通过代码逻辑维护关联关系
-- ============================================================================
CREATE TABLE conversation (
CREATE TABLE t_conversation (
id VARCHAR(64) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
user_id VARCHAR(64) COMMENT '用户ID (关联user.id)', -- 用户ID (关联user.id)
user_id VARCHAR(64) COMMENT '用户ID (关联t_user.id)', -- 用户ID (关联t_user.id)
user_type VARCHAR(20) DEFAULT 'registered' COMMENT '用户类型: registered-注册用户, guest-访客用户', -- 用户类型: registered-注册用户, guest-访客用户
title VARCHAR(200) COMMENT '对话标题', -- 对话标题
type VARCHAR(50) DEFAULT 'emotion_chat' COMMENT '对话类型', -- 对话类型
@@ -149,15 +153,15 @@ CREATE TABLE conversation (
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 = '对话表';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '对话表 (t_conversation)';
-- ============================================================================
-- 3. 消息表 (message)
-- 关联说明: conversation_id 关联 conversation.id,通过代码逻辑维护关联关系
-- 3. 消息表 (t_message)
-- 关联说明: conversation_id 关联 t_conversation.id,通过代码逻辑维护关联关系
-- ============================================================================
CREATE TABLE message (
CREATE TABLE t_message (
id VARCHAR(64) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
conversation_id VARCHAR(64) COMMENT '对话ID (关联conversation.id)', -- 对话ID (关联conversation.id)
conversation_id VARCHAR(64) COMMENT '对话ID (关联t_conversation.id)', -- 对话ID (关联t_conversation.id)
content TEXT COMMENT '消息内容', -- 消息内容
type VARCHAR(50) DEFAULT 'text' COMMENT '消息类型', -- 消息类型
sender VARCHAR(20) COMMENT '发送者: user-用户, assistant-AI助手', -- 发送者: user-用户, assistant-AI助手
@@ -188,12 +192,12 @@ CREATE TABLE message (
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 = '消息表';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '消息表 (t_message)';
-- ============================================================================
-- 4. Coze API调用记录表 (coze_api_call) - 优化版本
-- ============================================================================
CREATE TABLE coze_api_call (
CREATE TABLE t_coze_api_call (
id VARCHAR(64) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
conversation_id VARCHAR(64) COMMENT '对话ID', -- 对话ID
message_id VARCHAR(64) COMMENT '消息ID', -- 消息ID
@@ -252,12 +256,12 @@ CREATE TABLE coze_api_call (
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调用记录表 - 完整版本';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'Coze API调用记录表 - 完整版本 (t_coze_api_call)';
-- ============================================================================
-- 5. 情绪分析表 (emotion_analysis)
-- ============================================================================
CREATE TABLE emotion_analysis (
CREATE TABLE t_emotion_analysis (
id VARCHAR(64) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
user_id VARCHAR(64) COMMENT '用户ID', -- 用户ID
message_id VARCHAR(64) COMMENT '关联消息ID', -- 关联消息ID
@@ -278,12 +282,12 @@ CREATE TABLE emotion_analysis (
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 = '情绪分析表';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '情绪分析表 (t_emotion_analysis)';
-- ============================================================================
-- 6. 情绪记录表 (emotion_record)
-- ============================================================================
CREATE TABLE emotion_record (
CREATE TABLE t_emotion_record (
id VARCHAR(64) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
user_id VARCHAR(64) COMMENT '用户ID', -- 用户ID
record_date DATE COMMENT '记录日期', -- 记录日期
@@ -304,12 +308,12 @@ CREATE TABLE emotion_record (
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 = '情绪记录表';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '情绪记录表 (t_emotion_record)';
-- ============================================================================
-- 7. 成长课题表 (growth_topic)
-- ============================================================================
CREATE TABLE growth_topic (
CREATE TABLE t_growth_topic (
id VARCHAR(64) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
title VARCHAR(100) COMMENT '课题标题', -- 课题标题
category VARCHAR(50) COMMENT '分类', -- 分类
@@ -329,12 +333,12 @@ CREATE TABLE growth_topic (
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 = '成长课题表';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '成长课题表 (t_growth_topic)';
-- ============================================================================
-- 8. 课题互动表 (topic_interaction)
-- ============================================================================
CREATE TABLE topic_interaction (
CREATE TABLE t_topic_interaction (
id VARCHAR(64) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
topic_id VARCHAR(64) COMMENT '课题ID', -- 课题ID
type VARCHAR(50) COMMENT '互动类型', -- 互动类型
@@ -351,12 +355,12 @@ CREATE TABLE topic_interaction (
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 = '课题互动表';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '课题互动表 (t_topic_interaction)';
-- ============================================================================
-- 9. 地点标记表 (location_pin)
-- ============================================================================
CREATE TABLE location_pin (
CREATE TABLE t_location_pin (
id VARCHAR(64) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
name VARCHAR(100) COMMENT '地点名称', -- 地点名称
type VARCHAR(50) COMMENT '地点类型', -- 地点类型
@@ -365,7 +369,6 @@ CREATE TABLE location_pin (
longitude DECIMAL(11, 8) COMMENT '经度', -- 经度
address VARCHAR(200) COMMENT '地址', -- 地址
description TEXT COMMENT '描述', -- 描述
created_by VARCHAR(64) COMMENT '创建者', -- 创建者
likes INT DEFAULT 0 COMMENT '点赞数', -- 点赞数
visits INT DEFAULT 0 COMMENT '访问数', -- 访问数
is_bookmarked TINYINT DEFAULT 0 COMMENT '是否收藏', -- 是否收藏
@@ -377,12 +380,12 @@ CREATE TABLE location_pin (
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 = '地点标记表';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '地点标记表 (t_location_pin)';
-- ============================================================================
-- 10. 社区帖子表 (community_post)
-- ============================================================================
CREATE TABLE community_post (
CREATE TABLE t_community_post (
id VARCHAR(64) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
user_id VARCHAR(64) COMMENT '用户ID', -- 用户ID
location_id VARCHAR(64) COMMENT '地点ID', -- 地点ID
@@ -402,12 +405,12 @@ CREATE TABLE community_post (
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 = '社区帖子表';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '社区帖子表 (t_community_post)';
-- ============================================================================
-- 11. 评论表 (comment)
-- ============================================================================
CREATE TABLE comment (
CREATE TABLE t_comment (
id VARCHAR(64) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
post_id VARCHAR(64) COMMENT '帖子ID', -- 帖子ID
user_id VARCHAR(64) COMMENT '用户ID', -- 用户ID
@@ -421,12 +424,12 @@ CREATE TABLE comment (
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 = '评论表';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '评论表 (t_comment)';
-- ============================================================================
-- 12. 成就表 (achievement)
-- ============================================================================
CREATE TABLE achievement (
CREATE TABLE t_achievement (
id VARCHAR(64) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
title VARCHAR(100) COMMENT '成就标题', -- 成就标题
description TEXT COMMENT '描述', -- 描述
@@ -446,12 +449,12 @@ CREATE TABLE achievement (
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 = '成就表';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '成就表 (t_achievement)';
-- ============================================================================
-- 13. 奖励表 (reward)
-- ============================================================================
CREATE TABLE reward (
CREATE TABLE t_reward (
id VARCHAR(64) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
topic_id VARCHAR(64) COMMENT '课题ID', -- 课题ID
achievement_id VARCHAR(64) COMMENT '成就ID', -- 成就ID
@@ -470,12 +473,12 @@ CREATE TABLE reward (
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 = '奖励表';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '奖励表 (t_reward)';
-- ============================================================================
-- 14. 用户统计表 (user_stats)
-- ============================================================================
CREATE TABLE user_stats (
CREATE TABLE t_user_stats (
id VARCHAR(64) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
user_id VARCHAR(64) UNIQUE COMMENT '用户ID', -- 用户ID
total_conversations INT DEFAULT 0 COMMENT '总对话数', -- 总对话数
@@ -508,15 +511,15 @@ CREATE TABLE user_stats (
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 = '用户统计表';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户统计表 (t_user_stats)';
-- ============================================================================
-- 16. 用户日记表 (diary_post) - 类似朋友圈功能
-- 关联说明: user_id 关联 user.id,通过代码逻辑维护关联关系
-- 16. 用户日记表 (t_diary_post) - 类似朋友圈功能
-- 关联说明: user_id 关联 t_user.id,通过代码逻辑维护关联关系
-- ============================================================================
CREATE TABLE diary_post (
CREATE TABLE t_diary_post (
id VARCHAR(64) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
user_id VARCHAR(64) COMMENT '用户ID (关联user.id)', -- 用户ID (关联user.id)
user_id VARCHAR(64) COMMENT '用户ID (关联t_user.id)', -- 用户ID (关联t_user.id)
title VARCHAR(200) COMMENT '日记标题', -- 日记标题
content TEXT COMMENT '日记内容', -- 日记内容
images JSON COMMENT '图片列表 (存储图片URL数组)', -- 图片列表 (存储图片URL数组)
@@ -553,16 +556,16 @@ CREATE TABLE diary_post (
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 = '用户日记表 - 类似朋友圈功能';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户日记表 - 类似朋友圈功能 (t_diary_post)';
-- ============================================================================
-- 17. 日记评论表 (diary_comment)
-- 关联说明: diary_id 关联 diary_post.iduser_id 关联 user.id,通过代码逻辑维护关联关系
-- 17. 日记评论表 (t_diary_comment)
-- 关联说明: diary_id 关联 t_diary_post.iduser_id 关联 t_user.id,通过代码逻辑维护关联关系
-- ============================================================================
CREATE TABLE diary_comment (
CREATE TABLE t_diary_comment (
id VARCHAR(64) PRIMARY KEY COMMENT 'UUID主键', -- UUID主键
diary_id VARCHAR(64) COMMENT '日记ID (关联diary_post.id)', -- 日记ID (关联diary_post.id)
user_id VARCHAR(64) COMMENT '评论用户ID (关联user.id)', -- 评论用户ID (关联user.id)
diary_id VARCHAR(64) COMMENT '日记ID (关联t_diary_post.id)', -- 日记ID (关联t_diary_post.id)
user_id VARCHAR(64) COMMENT '评论用户ID (关联t_user.id)', -- 评论用户ID (关联t_user.id)
parent_comment_id VARCHAR(64) COMMENT '父评论ID (用于回复功能)', -- 父评论ID (用于回复功能)
content TEXT COMMENT '评论内容', -- 评论内容
images JSON COMMENT '评论图片 (存储图片URL数组)', -- 评论图片 (存储图片URL数组)
@@ -585,12 +588,12 @@ CREATE TABLE diary_comment (
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 = '日记评论表';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '日记评论表 (t_diary_comment)';
-- ============================================================================
-- 18. 访客用户表 (guest_user)
-- ============================================================================
CREATE TABLE guest_user (
CREATE TABLE t_guest_user (
id VARCHAR(64) 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)
@@ -609,414 +612,243 @@ CREATE TABLE guest_user (
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 = '访客用户表';
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '访客用户表 (t_guest_user)';
-- ============================================================================
-- 创建索引以提高查询性能
-- 注意: MySQL的CREATE INDEX不支持IF NOT EXISTS
-- 如果索引已存在,重复执行会产生警告但不会中断脚本执行
-- ============================================================================
-- user表索引
CREATE INDEX idx_user_account ON user (account);
CREATE INDEX idx_user_username ON user (username);
CREATE INDEX idx_user_email ON user (email);
CREATE INDEX idx_user_phone ON user (phone);
CREATE INDEX idx_user_last_active_time ON user (last_active_time);
CREATE INDEX idx_user_create_time ON user (create_time);
CREATE INDEX idx_user_member_level ON user (member_level);
CREATE INDEX idx_user_status ON user (status);
CREATE INDEX idx_user_is_verified ON user (is_verified);
CREATE INDEX idx_user_create_by ON user (create_by);
CREATE INDEX idx_user_update_by ON user (update_by);
CREATE INDEX idx_user_is_deleted ON user (is_deleted);
CREATE INDEX idx_user_third_party_id ON user (third_party_id);
CREATE INDEX idx_user_third_party_type ON user (third_party_type);
-- conversation表索引
CREATE INDEX idx_conversation_user_id ON conversation (user_id);
CREATE INDEX idx_conversation_start_time ON conversation (start_time);
CREATE INDEX idx_conversation_user_id_start_time ON conversation (user_id, start_time);
CREATE INDEX idx_conversation_primary_emotion ON conversation (primary_emotion);
CREATE INDEX idx_conversation_end_time ON conversation (end_time);
CREATE INDEX idx_conversation_create_time ON conversation (create_time);
CREATE INDEX idx_conversation_coze_conversation_id ON conversation (coze_conversation_id);
CREATE INDEX idx_conversation_status ON conversation (status);
CREATE INDEX idx_conversation_last_active_time ON conversation (last_active_time);
CREATE INDEX idx_conversation_create_by ON conversation (create_by);
CREATE INDEX idx_conversation_update_by ON conversation (update_by);
CREATE INDEX idx_conversation_is_deleted ON conversation (is_deleted);
CREATE INDEX idx_conversation_user_type ON conversation (user_type);
CREATE INDEX idx_conversation_emotion_trend ON conversation (emotion_trend);
CREATE INDEX idx_conversation_confidence ON conversation (confidence);
CREATE INDEX idx_conversation_client_ip ON conversation (client_ip);
-- message表索引
CREATE INDEX idx_message_conversation_id ON message (conversation_id);
CREATE INDEX idx_message_timestamp ON message (timestamp);
CREATE INDEX idx_message_conversation_id_timestamp ON message (conversation_id, timestamp);
CREATE INDEX idx_message_sender ON message (sender);
CREATE INDEX idx_message_type ON message (type);
CREATE INDEX idx_message_is_read ON message (is_read);
CREATE INDEX idx_message_create_time ON message (create_time);
CREATE INDEX idx_message_coze_chat_id ON message (coze_chat_id);
CREATE INDEX idx_message_status ON message (status);
CREATE INDEX idx_message_parent_message_id ON message (parent_message_id);
CREATE INDEX idx_message_create_by ON message (create_by);
CREATE INDEX idx_message_update_by ON message (update_by);
CREATE INDEX idx_message_is_deleted ON message (is_deleted);
-- coze_api_call表索引
CREATE INDEX idx_coze_api_call_conversation_id ON coze_api_call (conversation_id);
CREATE INDEX idx_coze_api_call_message_id ON coze_api_call (message_id);
CREATE INDEX idx_coze_api_call_coze_chat_id ON coze_api_call (coze_chat_id);
CREATE INDEX idx_coze_api_call_bot_id ON coze_api_call (bot_id);
CREATE INDEX idx_coze_api_call_user_id ON coze_api_call (user_id);
CREATE INDEX idx_coze_api_call_status ON coze_api_call (status);
CREATE INDEX idx_coze_api_call_final_status ON coze_api_call (final_status);
CREATE INDEX idx_coze_api_call_start_time ON coze_api_call (start_time);
CREATE INDEX idx_coze_api_call_request_type ON coze_api_call (request_type);
CREATE INDEX idx_coze_api_call_client_ip ON coze_api_call (client_ip);
CREATE INDEX idx_coze_api_call_session_id ON coze_api_call (session_id);
CREATE INDEX idx_coze_api_call_trace_id ON coze_api_call (trace_id);
CREATE INDEX idx_coze_api_call_user_status ON coze_api_call (user_id, status);
CREATE INDEX idx_coze_api_call_conversation_time ON coze_api_call (conversation_id, start_time);
-- emotion_analysis表索引
CREATE INDEX idx_emotion_analysis_user_id ON emotion_analysis (user_id);
CREATE INDEX idx_emotion_analysis_message_id ON emotion_analysis (message_id);
CREATE INDEX idx_emotion_analysis_primary_emotion ON emotion_analysis (primary_emotion);
CREATE INDEX idx_emotion_analysis_analysis_time ON emotion_analysis (analysis_time);
CREATE INDEX idx_emotion_analysis_create_time ON emotion_analysis (create_time);
CREATE INDEX idx_emotion_analysis_create_by ON emotion_analysis (create_by);
CREATE INDEX idx_emotion_analysis_update_by ON emotion_analysis (update_by);
CREATE INDEX idx_emotion_analysis_is_deleted ON emotion_analysis (is_deleted);
-- emotion_record表索引
CREATE INDEX idx_emotion_record_user_id ON emotion_record (user_id);
CREATE INDEX idx_emotion_record_date ON emotion_record (record_date);
CREATE INDEX idx_emotion_record_emotion_type ON emotion_record (emotion_type);
CREATE INDEX idx_emotion_record_user_id_date ON emotion_record (user_id, record_date);
CREATE INDEX idx_emotion_record_user_id_emotion_type ON emotion_record (user_id, emotion_type);
CREATE INDEX idx_emotion_record_intensity ON emotion_record (intensity);
CREATE INDEX idx_emotion_record_create_time ON emotion_record (create_time);
CREATE INDEX idx_emotion_record_create_by ON emotion_record (create_by);
CREATE INDEX idx_emotion_record_update_by ON emotion_record (update_by);
CREATE INDEX idx_emotion_record_is_deleted ON emotion_record (is_deleted);
-- growth_topic表索引
CREATE INDEX idx_growth_topic_category ON growth_topic (category);
CREATE INDEX idx_growth_topic_difficulty ON growth_topic (difficulty);
CREATE INDEX idx_growth_topic_is_unlocked ON growth_topic (is_unlocked);
CREATE INDEX idx_growth_topic_progress ON growth_topic (progress);
CREATE INDEX idx_growth_topic_completed_time ON growth_topic (completed_time);
CREATE INDEX idx_growth_topic_category_difficulty ON growth_topic (category, difficulty);
CREATE INDEX idx_growth_topic_create_time ON growth_topic (create_time);
-- topic_interaction表索引
CREATE INDEX idx_topic_interaction_topic_id ON topic_interaction (topic_id);
CREATE INDEX idx_topic_interaction_type ON topic_interaction (type);
CREATE INDEX idx_topic_interaction_completed_time ON topic_interaction (completed_time);
CREATE INDEX idx_topic_interaction_rating ON topic_interaction (rating);
CREATE INDEX idx_topic_interaction_topic_id_type ON topic_interaction (topic_id, type);
CREATE INDEX idx_topic_interaction_create_time ON topic_interaction (create_time);
-- location_pin表索引
CREATE INDEX idx_location_pin_latitude_longitude ON location_pin (latitude, longitude);
CREATE INDEX idx_location_pin_type ON location_pin (type);
CREATE INDEX idx_location_pin_category ON location_pin (category);
CREATE INDEX idx_location_pin_created_by ON location_pin (created_by);
CREATE INDEX idx_location_pin_likes ON location_pin (likes);
CREATE INDEX idx_location_pin_visits ON location_pin (visits);
CREATE INDEX idx_location_pin_is_bookmarked ON location_pin (is_bookmarked);
CREATE INDEX idx_location_pin_type_category ON location_pin (type, category);
CREATE INDEX idx_location_pin_create_time ON location_pin (create_time);
CREATE INDEX idx_location_pin_last_visit_time ON location_pin (last_visit_time);
-- community_post表索引
CREATE INDEX idx_community_post_user_id ON community_post (user_id);
CREATE INDEX idx_community_post_location_id ON community_post (location_id);
CREATE INDEX idx_community_post_create_time ON community_post (create_time);
CREATE INDEX idx_community_post_type ON community_post (type);
CREATE INDEX idx_community_post_likes ON community_post (likes);
CREATE INDEX idx_community_post_view_count ON community_post (view_count);
CREATE INDEX idx_community_post_is_private ON community_post (is_private);
CREATE INDEX idx_community_post_user_id_create_time ON community_post (user_id, create_time);
CREATE INDEX idx_community_post_type_create_time ON community_post (type, create_time);
-- comment表索引
CREATE INDEX idx_comment_post_id ON comment (post_id);
CREATE INDEX idx_comment_user_id ON comment (user_id);
CREATE INDEX idx_comment_reply_to_id ON comment (reply_to_id);
CREATE INDEX idx_comment_create_time ON comment (create_time);
CREATE INDEX idx_comment_likes ON comment (likes);
CREATE INDEX idx_comment_post_id_create_time ON comment (post_id, create_time);
-- achievement表索引
CREATE INDEX idx_achievement_category ON achievement (category);
CREATE INDEX idx_achievement_rarity ON achievement (rarity);
CREATE INDEX idx_achievement_unlocked_time ON achievement (unlocked_time);
CREATE INDEX idx_achievement_is_hidden ON achievement (is_hidden);
CREATE INDEX idx_achievement_progress ON achievement (progress);
CREATE INDEX idx_achievement_category_rarity ON achievement (category, rarity);
CREATE INDEX idx_achievement_create_time ON achievement (create_time);
-- reward表索引
CREATE INDEX idx_reward_topic_id ON reward (topic_id);
CREATE INDEX idx_reward_achievement_id ON reward (achievement_id);
CREATE INDEX idx_reward_type ON reward (type);
CREATE INDEX idx_reward_earned_time ON reward (earned_time);
CREATE INDEX idx_reward_rarity ON reward (rarity);
CREATE INDEX idx_reward_is_new ON reward (is_new);
CREATE INDEX idx_reward_type_earned_time ON reward (type, earned_time);
CREATE INDEX idx_reward_create_time ON reward (create_time);
-- user_stats表索引
CREATE INDEX idx_user_stats_user_id ON user_stats (user_id);
CREATE INDEX idx_user_stats_total_points ON user_stats (total_points);
CREATE INDEX idx_user_stats_consecutive_days ON user_stats (consecutive_days);
CREATE INDEX idx_user_stats_max_consecutive_days ON user_stats (max_consecutive_days);
CREATE INDEX idx_user_stats_social_interactions ON user_stats (social_interactions);
CREATE INDEX idx_user_stats_update_time ON user_stats (update_time);
CREATE INDEX idx_user_stats_create_time ON user_stats (create_time);
-- user_stats表日记相关索引
CREATE INDEX idx_user_stats_diary_posts_created ON user_stats (diary_posts_created);
CREATE INDEX idx_user_stats_diary_likes_received ON user_stats (diary_likes_received);
CREATE INDEX idx_user_stats_diary_comments_received ON user_stats (diary_comments_received);
CREATE INDEX idx_user_stats_diary_views_received ON user_stats (diary_views_received);
CREATE INDEX idx_user_stats_featured_diary_count ON user_stats (featured_diary_count);
CREATE INDEX idx_user_stats_ai_comments_received ON user_stats (ai_comments_received);
-- diary_post表索引
CREATE INDEX idx_diary_post_user_id ON diary_post (user_id);
CREATE INDEX idx_diary_post_publish_time ON diary_post (publish_time);
CREATE INDEX idx_diary_post_last_comment_time ON diary_post (last_comment_time);
CREATE INDEX idx_diary_post_status ON diary_post (status);
CREATE INDEX idx_diary_post_priority ON diary_post (priority);
CREATE INDEX idx_diary_post_featured ON diary_post (featured);
CREATE INDEX idx_diary_post_create_time ON diary_post (create_time);
-- diary_comment表索引
CREATE INDEX idx_diary_comment_diary_id ON diary_comment (diary_id);
CREATE INDEX idx_diary_comment_user_id ON diary_comment (user_id);
CREATE INDEX idx_diary_comment_parent_comment_id ON diary_comment (parent_comment_id);
CREATE INDEX idx_diary_comment_publish_time ON diary_comment (publish_time);
CREATE INDEX idx_diary_comment_last_reply_time ON diary_comment (last_reply_time);
CREATE INDEX idx_diary_comment_emotion_score ON diary_comment (emotion_score);
CREATE INDEX idx_diary_comment_sentiment_score ON diary_comment (sentiment_score);
CREATE INDEX idx_diary_comment_create_time ON diary_comment (create_time);
-- diary_post表复合索引和功能索引
CREATE INDEX idx_diary_post_user_publish ON diary_post (user_id, publish_time);
CREATE INDEX idx_diary_post_user_status ON diary_post (user_id, status);
CREATE INDEX idx_diary_post_public_publish ON diary_post (is_public, publish_time);
CREATE INDEX idx_diary_post_featured_publish ON diary_post (featured, publish_time);
CREATE INDEX idx_diary_post_mood_score ON diary_post (mood_score);
CREATE INDEX idx_diary_post_ai_sentiment ON diary_post (ai_sentiment_score);
CREATE INDEX idx_diary_post_location ON diary_post (latitude, longitude);
CREATE INDEX idx_diary_post_like_count ON diary_post (like_count);
CREATE INDEX idx_diary_post_comment_count ON diary_post (comment_count);
CREATE INDEX idx_diary_post_view_count ON diary_post (view_count);
CREATE INDEX idx_diary_post_create_by ON diary_post (create_by);
CREATE INDEX idx_diary_post_update_by ON diary_post (update_by);
CREATE INDEX idx_diary_post_is_deleted ON diary_post (is_deleted);
-- diary_comment表复合索引和功能索引
CREATE INDEX idx_diary_comment_diary_publish ON diary_comment (diary_id, publish_time);
CREATE INDEX idx_diary_comment_diary_type ON diary_comment (diary_id, comment_type);
CREATE INDEX idx_diary_comment_user_publish ON diary_comment (user_id, publish_time);
CREATE INDEX idx_diary_comment_parent_publish ON diary_comment (parent_comment_id, publish_time);
CREATE INDEX idx_diary_comment_type_publish ON diary_comment (comment_type, publish_time);
CREATE INDEX idx_diary_comment_status ON diary_comment (status);
CREATE INDEX idx_diary_comment_is_top ON diary_comment (is_top);
CREATE INDEX idx_diary_comment_like_count ON diary_comment (like_count);
CREATE INDEX idx_diary_comment_reply_count ON diary_comment (reply_count);
CREATE INDEX idx_diary_comment_ai_source ON diary_comment (ai_comment_source);
CREATE INDEX idx_diary_comment_create_by ON diary_comment (create_by);
CREATE INDEX idx_diary_comment_update_by ON diary_comment (update_by);
CREATE INDEX idx_diary_comment_is_deleted ON diary_comment (is_deleted);
-- guest_user表索引
CREATE INDEX idx_guest_user_guest_user_id ON guest_user (guest_user_id);
CREATE INDEX idx_guest_user_ip_address ON guest_user (ip_address);
CREATE INDEX idx_guest_user_last_active_time ON guest_user (last_active_time);
CREATE INDEX idx_guest_user_conversation_count ON guest_user (conversation_count);
CREATE INDEX idx_guest_user_message_count ON guest_user (message_count);
CREATE INDEX idx_guest_user_create_time ON guest_user (create_time);
CREATE INDEX idx_guest_user_create_by ON guest_user (create_by);
CREATE INDEX idx_guest_user_update_by ON guest_user (update_by);
CREATE INDEX idx_guest_user_is_deleted ON guest_user (is_deleted);
-- t_user表索引
CREATE INDEX idx_user_account ON t_user (account);
CREATE INDEX idx_user_username ON t_user (username);
CREATE INDEX idx_user_email ON t_user (email);
CREATE INDEX idx_user_phone ON t_user (phone);
CREATE INDEX idx_user_last_active_time ON t_user (last_active_time);
CREATE INDEX idx_user_create_time ON t_user (create_time);
CREATE INDEX idx_user_member_level ON t_user (member_level);
CREATE INDEX idx_user_status ON t_user (status);
CREATE INDEX idx_user_is_verified ON t_user (is_verified);
CREATE INDEX idx_user_create_by ON t_user (create_by);
CREATE INDEX idx_user_update_by ON t_user (update_by);
CREATE INDEX idx_user_is_deleted ON t_user (is_deleted);
CREATE INDEX idx_user_third_party_id ON t_user (third_party_id);
CREATE INDEX idx_user_third_party_type ON t_user (third_party_type);
-- t_conversation表索引
CREATE INDEX idx_conversation_user_id ON t_conversation (user_id);
CREATE INDEX idx_conversation_start_time ON t_conversation (start_time);
CREATE INDEX idx_conversation_user_id_start_time ON t_conversation (user_id, start_time);
CREATE INDEX idx_conversation_primary_emotion ON t_conversation (primary_emotion);
CREATE INDEX idx_conversation_end_time ON t_conversation (end_time);
CREATE INDEX idx_conversation_create_time ON t_conversation (create_time);
CREATE INDEX idx_conversation_coze_conversation_id ON t_conversation (coze_conversation_id);
CREATE INDEX idx_conversation_status ON t_conversation (status);
CREATE INDEX idx_conversation_last_active_time ON t_conversation (last_active_time);
CREATE INDEX idx_conversation_create_by ON t_conversation (create_by);
CREATE INDEX idx_conversation_update_by ON t_conversation (update_by);
CREATE INDEX idx_conversation_is_deleted ON t_conversation (is_deleted);
CREATE INDEX idx_conversation_user_type ON t_conversation (user_type);
CREATE INDEX idx_conversation_emotion_trend ON t_conversation (emotion_trend);
CREATE INDEX idx_conversation_confidence ON t_conversation (confidence);
CREATE INDEX idx_conversation_client_ip ON t_conversation (client_ip);
-- t_message表索引
CREATE INDEX idx_message_conversation_id ON t_message (conversation_id);
CREATE INDEX idx_message_timestamp ON t_message (timestamp);
CREATE INDEX idx_message_conversation_id_timestamp ON t_message (conversation_id, timestamp);
CREATE INDEX idx_message_sender ON t_message (sender);
CREATE INDEX idx_message_type ON t_message (type);
CREATE INDEX idx_message_is_read ON t_message (is_read);
CREATE INDEX idx_message_create_time ON t_message (create_time);
CREATE INDEX idx_message_coze_chat_id ON t_message (coze_chat_id);
CREATE INDEX idx_message_status ON t_message (status);
CREATE INDEX idx_message_parent_message_id ON t_message (parent_message_id);
CREATE INDEX idx_message_create_by ON t_message (create_by);
CREATE INDEX idx_message_update_by ON t_message (update_by);
CREATE INDEX idx_message_is_deleted ON t_message (is_deleted);
-- t_coze_api_call表索引
CREATE INDEX idx_coze_api_call_conversation_id ON t_coze_api_call (conversation_id);
CREATE INDEX idx_coze_api_call_message_id ON t_coze_api_call (message_id);
CREATE INDEX idx_coze_api_call_coze_chat_id ON t_coze_api_call (coze_chat_id);
CREATE INDEX idx_coze_api_call_bot_id ON t_coze_api_call (bot_id);
CREATE INDEX idx_coze_api_call_user_id ON t_coze_api_call (user_id);
CREATE INDEX idx_coze_api_call_status ON t_coze_api_call (status);
CREATE INDEX idx_coze_api_call_final_status ON t_coze_api_call (final_status);
CREATE INDEX idx_coze_api_call_start_time ON t_coze_api_call (start_time);
CREATE INDEX idx_coze_api_call_request_type ON t_coze_api_call (request_type);
CREATE INDEX idx_coze_api_call_client_ip ON t_coze_api_call (client_ip);
CREATE INDEX idx_coze_api_call_session_id ON t_coze_api_call (session_id);
CREATE INDEX idx_coze_api_call_trace_id ON t_coze_api_call (trace_id);
CREATE INDEX idx_coze_api_call_user_status ON t_coze_api_call (user_id, status);
CREATE INDEX idx_coze_api_call_conversation_time ON t_coze_api_call (conversation_id, start_time);
-- t_emotion_analysis表索引
CREATE INDEX idx_emotion_analysis_user_id ON t_emotion_analysis (user_id);
CREATE INDEX idx_emotion_analysis_message_id ON t_emotion_analysis (message_id);
CREATE INDEX idx_emotion_analysis_primary_emotion ON t_emotion_analysis (primary_emotion);
CREATE INDEX idx_emotion_analysis_analysis_time ON t_emotion_analysis (analysis_time);
CREATE INDEX idx_emotion_analysis_create_time ON t_emotion_analysis (create_time);
CREATE INDEX idx_emotion_analysis_create_by ON t_emotion_analysis (create_by);
CREATE INDEX idx_emotion_analysis_update_by ON t_emotion_analysis (update_by);
CREATE INDEX idx_emotion_analysis_is_deleted ON t_emotion_analysis (is_deleted);
-- t_emotion_record表索引
CREATE INDEX idx_emotion_record_user_id ON t_emotion_record (user_id);
CREATE INDEX idx_emotion_record_date ON t_emotion_record (record_date);
CREATE INDEX idx_emotion_record_emotion_type ON t_emotion_record (emotion_type);
CREATE INDEX idx_emotion_record_user_id_date ON t_emotion_record (user_id, record_date);
CREATE INDEX idx_emotion_record_user_id_emotion_type ON t_emotion_record (user_id, emotion_type);
CREATE INDEX idx_emotion_record_intensity ON t_emotion_record (intensity);
CREATE INDEX idx_emotion_record_create_time ON t_emotion_record (create_time);
CREATE INDEX idx_emotion_record_create_by ON t_emotion_record (create_by);
CREATE INDEX idx_emotion_record_update_by ON t_emotion_record (update_by);
CREATE INDEX idx_emotion_record_is_deleted ON t_emotion_record (is_deleted);
-- t_growth_topic表索引
CREATE INDEX idx_growth_topic_category ON t_growth_topic (category);
CREATE INDEX idx_growth_topic_difficulty ON t_growth_topic (difficulty);
CREATE INDEX idx_growth_topic_is_unlocked ON t_growth_topic (is_unlocked);
CREATE INDEX idx_growth_topic_progress ON t_growth_topic (progress);
CREATE INDEX idx_growth_topic_completed_time ON t_growth_topic (completed_time);
CREATE INDEX idx_growth_topic_category_difficulty ON t_growth_topic (category, difficulty);
CREATE INDEX idx_growth_topic_create_time ON t_growth_topic (create_time);
-- t_topic_interaction表索引
CREATE INDEX idx_topic_interaction_topic_id ON t_topic_interaction (topic_id);
CREATE INDEX idx_topic_interaction_type ON t_topic_interaction (type);
CREATE INDEX idx_topic_interaction_completed_time ON t_topic_interaction (completed_time);
CREATE INDEX idx_topic_interaction_rating ON t_topic_interaction (rating);
CREATE INDEX idx_topic_interaction_topic_id_type ON t_topic_interaction (topic_id, type);
CREATE INDEX idx_topic_interaction_create_time ON t_topic_interaction (create_time);
-- t_location_pin表索引
CREATE INDEX idx_location_pin_latitude_longitude ON t_location_pin (latitude, longitude);
CREATE INDEX idx_location_pin_type ON t_location_pin (type);
CREATE INDEX idx_location_pin_category ON t_location_pin (category);
CREATE INDEX idx_location_pin_create_by ON t_location_pin (create_by);
CREATE INDEX idx_location_pin_likes ON t_location_pin (likes);
CREATE INDEX idx_location_pin_visits ON t_location_pin (visits);
CREATE INDEX idx_location_pin_is_bookmarked ON t_location_pin (is_bookmarked);
CREATE INDEX idx_location_pin_type_category ON t_location_pin (type, category);
CREATE INDEX idx_location_pin_create_time ON t_location_pin (create_time);
CREATE INDEX idx_location_pin_last_visit_time ON t_location_pin (last_visit_time);
-- t_community_post表索引
CREATE INDEX idx_community_post_user_id ON t_community_post (user_id);
CREATE INDEX idx_community_post_location_id ON t_community_post (location_id);
CREATE INDEX idx_community_post_create_time ON t_community_post (create_time);
CREATE INDEX idx_community_post_type ON t_community_post (type);
CREATE INDEX idx_community_post_likes ON t_community_post (likes);
CREATE INDEX idx_community_post_view_count ON t_community_post (view_count);
CREATE INDEX idx_community_post_is_private ON t_community_post (is_private);
CREATE INDEX idx_community_post_user_id_create_time ON t_community_post (user_id, create_time);
CREATE INDEX idx_community_post_type_create_time ON t_community_post (type, create_time);
-- t_comment表索引
CREATE INDEX idx_comment_post_id ON t_comment (post_id);
CREATE INDEX idx_comment_user_id ON t_comment (user_id);
CREATE INDEX idx_comment_reply_to_id ON t_comment (reply_to_id);
CREATE INDEX idx_comment_create_time ON t_comment (create_time);
CREATE INDEX idx_comment_likes ON t_comment (likes);
CREATE INDEX idx_comment_post_id_create_time ON t_comment (post_id, create_time);
-- t_achievement表索引
CREATE INDEX idx_achievement_category ON t_achievement (category);
CREATE INDEX idx_achievement_rarity ON t_achievement (rarity);
CREATE INDEX idx_achievement_unlocked_time ON t_achievement (unlocked_time);
CREATE INDEX idx_achievement_is_hidden ON t_achievement (is_hidden);
CREATE INDEX idx_achievement_progress ON t_achievement (progress);
CREATE INDEX idx_achievement_category_rarity ON t_achievement (category, rarity);
CREATE INDEX idx_achievement_create_time ON t_achievement (create_time);
-- t_reward表索引
CREATE INDEX idx_reward_topic_id ON t_reward (topic_id);
CREATE INDEX idx_reward_achievement_id ON t_reward (achievement_id);
CREATE INDEX idx_reward_type ON t_reward (type);
CREATE INDEX idx_reward_earned_time ON t_reward (earned_time);
CREATE INDEX idx_reward_rarity ON t_reward (rarity);
CREATE INDEX idx_reward_is_new ON t_reward (is_new);
CREATE INDEX idx_reward_type_earned_time ON t_reward (type, earned_time);
CREATE INDEX idx_reward_create_time ON t_reward (create_time);
-- t_user_stats表索引
CREATE INDEX idx_user_stats_user_id ON t_user_stats (user_id);
CREATE INDEX idx_user_stats_total_points ON t_user_stats (total_points);
CREATE INDEX idx_user_stats_consecutive_days ON t_user_stats (consecutive_days);
CREATE INDEX idx_user_stats_max_consecutive_days ON t_user_stats (max_consecutive_days);
CREATE INDEX idx_user_stats_social_interactions ON t_user_stats (social_interactions);
CREATE INDEX idx_user_stats_update_time ON t_user_stats (update_time);
CREATE INDEX idx_user_stats_create_time ON t_user_stats (create_time);
-- t_user_stats表日记相关索引
CREATE INDEX idx_user_stats_diary_posts_created ON t_user_stats (diary_posts_created);
CREATE INDEX idx_user_stats_diary_likes_received ON t_user_stats (diary_likes_received);
CREATE INDEX idx_user_stats_diary_comments_received ON t_user_stats (diary_comments_received);
CREATE INDEX idx_user_stats_diary_views_received ON t_user_stats (diary_views_received);
CREATE INDEX idx_user_stats_featured_diary_count ON t_user_stats (featured_diary_count);
CREATE INDEX idx_user_stats_ai_comments_received ON t_user_stats (ai_comments_received);
-- t_diary_post表索引
CREATE INDEX idx_diary_post_user_id ON t_diary_post (user_id);
CREATE INDEX idx_diary_post_publish_time ON t_diary_post (publish_time);
CREATE INDEX idx_diary_post_last_comment_time ON t_diary_post (last_comment_time);
CREATE INDEX idx_diary_post_status ON t_diary_post (status);
CREATE INDEX idx_diary_post_priority ON t_diary_post (priority);
CREATE INDEX idx_diary_post_featured ON t_diary_post (featured);
CREATE INDEX idx_diary_post_create_time ON t_diary_post (create_time);
-- t_diary_comment表索引
CREATE INDEX idx_diary_comment_diary_id ON t_diary_comment (diary_id);
CREATE INDEX idx_diary_comment_user_id ON t_diary_comment (user_id);
CREATE INDEX idx_diary_comment_parent_comment_id ON t_diary_comment (parent_comment_id);
CREATE INDEX idx_diary_comment_publish_time ON t_diary_comment (publish_time);
CREATE INDEX idx_diary_comment_last_reply_time ON t_diary_comment (last_reply_time);
CREATE INDEX idx_diary_comment_emotion_score ON t_diary_comment (emotion_score);
CREATE INDEX idx_diary_comment_sentiment_score ON t_diary_comment (sentiment_score);
CREATE INDEX idx_diary_comment_create_time ON t_diary_comment (create_time);
-- t_diary_post表复合索引和功能索引
CREATE INDEX idx_diary_post_user_publish ON t_diary_post (user_id, publish_time);
CREATE INDEX idx_diary_post_user_status ON t_diary_post (user_id, status);
CREATE INDEX idx_diary_post_public_publish ON t_diary_post (is_public, publish_time);
CREATE INDEX idx_diary_post_featured_publish ON t_diary_post (featured, publish_time);
CREATE INDEX idx_diary_post_mood_score ON t_diary_post (mood_score);
CREATE INDEX idx_diary_post_ai_sentiment ON t_diary_post (ai_sentiment_score);
CREATE INDEX idx_diary_post_location ON t_diary_post (latitude, longitude);
CREATE INDEX idx_diary_post_like_count ON t_diary_post (like_count);
CREATE INDEX idx_diary_post_comment_count ON t_diary_post (comment_count);
CREATE INDEX idx_diary_post_view_count ON t_diary_post (view_count);
CREATE INDEX idx_diary_post_create_by ON t_diary_post (create_by);
CREATE INDEX idx_diary_post_update_by ON t_diary_post (update_by);
CREATE INDEX idx_diary_post_is_deleted ON t_diary_post (is_deleted);
-- t_diary_comment表复合索引和功能索引
CREATE INDEX idx_diary_comment_diary_publish ON t_diary_comment (diary_id, publish_time);
CREATE INDEX idx_diary_comment_diary_type ON t_diary_comment (diary_id, comment_type);
CREATE INDEX idx_diary_comment_user_publish ON t_diary_comment (user_id, publish_time);
CREATE INDEX idx_diary_comment_parent_publish ON t_diary_comment (parent_comment_id, publish_time);
CREATE INDEX idx_diary_comment_type_publish ON t_diary_comment (comment_type, publish_time);
CREATE INDEX idx_diary_comment_status ON t_diary_comment (status);
CREATE INDEX idx_diary_comment_is_top ON t_diary_comment (is_top);
CREATE INDEX idx_diary_comment_like_count ON t_diary_comment (like_count);
CREATE INDEX idx_diary_comment_reply_count ON t_diary_comment (reply_count);
CREATE INDEX idx_diary_comment_ai_source ON t_diary_comment (ai_comment_source);
CREATE INDEX idx_diary_comment_create_by ON t_diary_comment (create_by);
CREATE INDEX idx_diary_comment_update_by ON t_diary_comment (update_by);
CREATE INDEX idx_diary_comment_is_deleted ON t_diary_comment (is_deleted);
-- t_guest_user表索引
CREATE INDEX idx_guest_user_guest_user_id ON t_guest_user (guest_user_id);
CREATE INDEX idx_guest_user_ip_address ON t_guest_user (ip_address);
CREATE INDEX idx_guest_user_last_active_time ON t_guest_user (last_active_time);
CREATE INDEX idx_guest_user_conversation_count ON t_guest_user (conversation_count);
CREATE INDEX idx_guest_user_message_count ON t_guest_user (message_count);
CREATE INDEX idx_guest_user_create_time ON t_guest_user (create_time);
CREATE INDEX idx_guest_user_create_by ON t_guest_user (create_by);
CREATE INDEX idx_guest_user_update_by ON t_guest_user (update_by);
CREATE INDEX idx_guest_user_is_deleted ON t_guest_user (is_deleted);
-- ============================================================================
-- 数据库统计信息
@@ -1026,7 +858,8 @@ SELECT
FROM
INFORMATION_SCHEMA.TABLES
WHERE
TABLE_SCHEMA = 'emotion';
TABLE_SCHEMA = 'emotion'
AND TABLE_NAME LIKE 't\_%' ESCAPE '\\';
-- 显示创建的表
SELECT
@@ -1037,6 +870,7 @@ FROM
INFORMATION_SCHEMA.TABLES
WHERE
TABLE_SCHEMA = 'emotion'
AND TABLE_NAME LIKE 't\_%' ESCAPE '\\'
ORDER BY
TABLE_NAME;