TASK:1.登录接口联调修改 2.搭配生成优化 3.搭配生成、聊天接口文档添加
This commit is contained in:
5
pom.xml
5
pom.xml
@@ -90,6 +90,11 @@
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Swagger for API Documentation -->
|
||||
<dependency>
|
||||
|
||||
@@ -7,6 +7,8 @@ public class RedisURIConstants {
|
||||
public static final String verifyCodeCache = "VerifyCodeCache:";
|
||||
// 验证码 10分钟过期
|
||||
public static final Long verifyCodeTimeout = 10 * 60L;
|
||||
// outfit result 结果30分钟过期
|
||||
public static final Long outfitResultTimeout = 30 * 60L;
|
||||
|
||||
public static final String outfitResultCache = "OutfitResultCache:";
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import java.util.List;
|
||||
/**
|
||||
* Swagger配置类
|
||||
* 提供完整的API文档配置,包括安全认证、服务器信息和标签分类
|
||||
*
|
||||
*
|
||||
* @author AI Assistant
|
||||
* @since 2024-01-01
|
||||
*/
|
||||
@@ -116,9 +116,10 @@ public class SwaggerConfig {
|
||||
.in(SecurityScheme.In.COOKIE)
|
||||
.name("JSESSIONID")
|
||||
.description("Session认证,通过登录接口获取"))
|
||||
.addSecuritySchemes("basicAuth", new SecurityScheme()
|
||||
.type(SecurityScheme.Type.HTTP)
|
||||
.scheme("basic")
|
||||
.addSecuritySchemes("CustomAuth", new SecurityScheme()
|
||||
.type(SecurityScheme.Type.APIKEY)
|
||||
.name("Authorization")
|
||||
.in(SecurityScheme.In.HEADER)
|
||||
.description("基础认证(仅用于开发测试)"));
|
||||
}
|
||||
|
||||
@@ -128,7 +129,7 @@ public class SwaggerConfig {
|
||||
private List<SecurityRequirement> createSecurityRequirements() {
|
||||
return Arrays.asList(
|
||||
new SecurityRequirement().addList("sessionAuth"),
|
||||
new SecurityRequirement().addList("basicAuth")
|
||||
new SecurityRequirement().addList("CustomAuth")
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,8 +39,8 @@ public class WebConfig implements WebMvcConfigurer {
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(jwtInterceptor)
|
||||
.addPathPatterns("/api/**/**") // 保护这些路径
|
||||
.excludePathPatterns(Arrays.asList("/api/auth/precheckAndSendEmail", "/api/auth/register",
|
||||
"/api/auth/login", "/api/auth/forgotPwd", "/api/style/callback")); // 排除登录接口
|
||||
.excludePathPatterns(Arrays.asList("/api/auth/precheckEmail", "/api/auth/registerOrLogin",
|
||||
"/api/auth/forgotPwd", "/api/style/callback")); // 排除登录接口
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package com.aida.lanecarford.controller;
|
||||
|
||||
import com.aida.lanecarford.service.ChatService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -11,17 +14,27 @@ import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/llm")
|
||||
@Tag(name = "LLM对话管理", description = "大语言模型流式对话相关API接口")
|
||||
public class ChatController {
|
||||
|
||||
@Resource
|
||||
private ChatService chatService;
|
||||
|
||||
@CrossOrigin
|
||||
@Operation(
|
||||
summary = "流式对话",
|
||||
description = "与大语言模型进行流式对话,返回Server-Sent Events数据流"
|
||||
)
|
||||
@GetMapping(value = "/streamChat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||
public SseEmitter streamChat(@RequestParam(required = false) String message,
|
||||
@RequestParam Long sessionId,
|
||||
@RequestParam String gender) {
|
||||
return chatService.streamChat(message, sessionId, gender );
|
||||
}
|
||||
public SseEmitter streamChat(
|
||||
@Parameter(description = "用户输入的消息内容", example = "你好,请介绍一下自己")
|
||||
@RequestParam(required = false) String message,
|
||||
|
||||
@Parameter(description = "会话ID", example = "123456", required = true)
|
||||
@RequestParam Long sessionId,
|
||||
|
||||
@Parameter(description = "性别", example = "male | female", required = true)
|
||||
@RequestParam String gender) {
|
||||
return chatService.streamChat(message, sessionId, gender);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ import com.aida.lanecarford.common.ApiResponse;
|
||||
import com.aida.lanecarford.dto.LoginRequest;
|
||||
import com.aida.lanecarford.service.LoginService;
|
||||
import com.aida.lanecarford.vo.LoginVO;
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@@ -27,11 +27,22 @@ public class LoginController {
|
||||
description = "根据操作类型验证邮箱有效性并发送验证码。支持注册、登录、忘记密码三种操作类型。"
|
||||
)
|
||||
@PostMapping("/precheckAndSendEmail")
|
||||
@Hidden
|
||||
public ApiResponse<String> preCheckAndSendEmail(@Valid @RequestBody LoginRequest loginRequest) {
|
||||
loginService.preCheckAndSendEmail(loginRequest);
|
||||
return ApiResponse.success("验证码已发送到您的邮箱");
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "检查邮箱",
|
||||
description = "根据操作类型验证邮箱有效性并发送验证码。仅支持忘记密码。"
|
||||
)
|
||||
@GetMapping("/precheckEmail")
|
||||
public ApiResponse<String> precheckForgotPwdAndSendEmail(@Valid @RequestParam String email) {
|
||||
loginService.precheckForgotPwdAndSendEmail(email);
|
||||
return ApiResponse.success("验证码已发送到您的邮箱");
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "用户注册或登录",
|
||||
description = "通过验证码完成用户注册或登录,返回JWT令牌和用户信息。"
|
||||
|
||||
@@ -5,6 +5,10 @@ import com.aida.lanecarford.dto.OutfitCallbackDTO;
|
||||
import com.aida.lanecarford.dto.RequestOutfitDTO;
|
||||
import com.aida.lanecarford.service.StyleService;
|
||||
import com.aida.lanecarford.vo.OutfitResultVO;
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -22,22 +26,55 @@ import java.util.List;
|
||||
@RestController
|
||||
@RequestMapping("/api/style")
|
||||
@RequiredArgsConstructor
|
||||
@Tag(name = "穿搭风格管理", description = "AI穿搭推荐和结果查询相关API接口")
|
||||
public class StyleController {
|
||||
|
||||
private final StyleService styleService;
|
||||
|
||||
/**
|
||||
* 请求AI穿搭推荐
|
||||
* 提交穿搭需求给AI模型,异步生成穿搭方案
|
||||
*
|
||||
* @param requestOutfitDTO 穿搭请求参数DTO
|
||||
* @return 包含请求ID列表的响应结果
|
||||
*/
|
||||
@Operation(
|
||||
summary = "请求AI穿搭推荐",
|
||||
description = "提交用户的穿搭需求给AI模型进行异步处理,返回请求ID用于后续结果查询"
|
||||
)
|
||||
@PostMapping("/requestOutfit")
|
||||
public ApiResponse<List<String>> requestOutfit(@Valid @RequestBody RequestOutfitDTO requestOutfitDTO) {
|
||||
return ApiResponse.success(styleService.requestOutfit(requestOutfitDTO));
|
||||
}
|
||||
|
||||
/**
|
||||
* AI服务回调接口
|
||||
* 接收AI服务处理完成后的回调通知,更新穿搭结果状态
|
||||
* 注意:此接口为内部接口,供AI服务调用,不对外暴露文档
|
||||
*
|
||||
* @param callbackDTO AI回调数据DTO
|
||||
*/
|
||||
@Hidden
|
||||
@PostMapping("/callback")
|
||||
public void callback(@RequestBody OutfitCallbackDTO callbackDTO) {
|
||||
styleService.callback(callbackDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取穿搭结果
|
||||
* 根据请求ID列表查询AI生成的穿搭方案结果
|
||||
*
|
||||
* @param requestIDs 请求ID列表,通过requestOutfit接口获取
|
||||
* @return 穿搭结果视图对象列表
|
||||
*/
|
||||
@Operation(
|
||||
summary = "获取穿搭结果",
|
||||
description = "根据请求ID列表查询AI生成的穿搭方案结果,支持批量查询"
|
||||
)
|
||||
@GetMapping("/getOutfitResult")
|
||||
public ApiResponse<List<OutfitResultVO>> getOutfitResult(@RequestParam List<String> requestIDs) {
|
||||
public ApiResponse<List<OutfitResultVO>> getOutfitResult(
|
||||
@Parameter(description = "请求ID列表", required = true, example = "[a22019ac-9db2-4076-9953-42d65e8120ec, 20217a09-435d-4b34-962a-3af59881c6d9]")
|
||||
@RequestParam List<String> requestIDs) {
|
||||
return ApiResponse.success(styleService.getOutfitResult(requestIDs));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +1,55 @@
|
||||
package com.aida.lanecarford.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
@Data
|
||||
@Schema(description = "AI穿搭推荐请求参数")
|
||||
public class RequestOutfitDTO {
|
||||
|
||||
// 顾客id
|
||||
@Schema(
|
||||
description = "顾客ID",
|
||||
example = "1",
|
||||
requiredMode = Schema.RequiredMode.REQUIRED
|
||||
)
|
||||
@NotNull(message = "customer id cannot be empty")
|
||||
private Long customerId;
|
||||
|
||||
// 进店id
|
||||
@Schema(
|
||||
description = "顾客进店记录ID",
|
||||
example = "1",
|
||||
requiredMode = Schema.RequiredMode.REQUIRED
|
||||
)
|
||||
@NotNull(message = "customer check-in id cannot be empty")
|
||||
private Long checkInId;
|
||||
|
||||
// 选择的设计师
|
||||
@Schema(
|
||||
description = "选择的设计师风格",
|
||||
example = "mini",
|
||||
requiredMode = Schema.RequiredMode.REQUIRED,
|
||||
allowableValues = {"mini", " crystal"}
|
||||
)
|
||||
@NotNull(message = "please select a stylist")
|
||||
private String stylist;
|
||||
|
||||
@Schema(
|
||||
description = "性别",
|
||||
example = "female",
|
||||
requiredMode = Schema.RequiredMode.REQUIRED,
|
||||
allowableValues = {"male", "female"/*, "unisex"*/}
|
||||
)
|
||||
@NotNull(message = "please select gender")
|
||||
private String gender;
|
||||
|
||||
// 生成数量
|
||||
private int num;
|
||||
@Schema(
|
||||
description = "生成穿搭方案的数量",
|
||||
example = "4",
|
||||
defaultValue = "1",
|
||||
minimum = "1",
|
||||
maximum = "4"
|
||||
)
|
||||
private int num = 1;
|
||||
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ public class Style extends BaseEntity {
|
||||
/**
|
||||
* 单品的唯一id
|
||||
*/
|
||||
private List<String> items;
|
||||
private String items;
|
||||
|
||||
/**
|
||||
* 生成状态(pending-等待中,processing-处理中,completed-已完成,failed-失败)
|
||||
|
||||
@@ -17,6 +17,8 @@ public interface LoginService extends IService<User> {
|
||||
|
||||
void preCheckAndSendEmail(LoginRequest loginRequest);
|
||||
|
||||
void precheckForgotPwdAndSendEmail(String email);
|
||||
|
||||
LoginVO registerOrLogin(LoginRequest loginRequest);
|
||||
|
||||
void logout();
|
||||
|
||||
@@ -155,7 +155,7 @@ public class ChatServiceImpl implements ChatService {
|
||||
}
|
||||
|
||||
private void sendRawData(String rawData, SseEmitter emitter, String sessionId) {
|
||||
Map<String, Object> response = createResponse("raw", rawData, sessionId);
|
||||
Map<String, Object> response = createResponse("text", rawData, sessionId);
|
||||
sendToClient(emitter, response);
|
||||
}
|
||||
|
||||
|
||||
@@ -64,9 +64,6 @@ public class LoginServiceImpl extends ServiceImpl<UserMapper, User> implements L
|
||||
case LOGIN:
|
||||
precheckLogin(user, loginRequest);
|
||||
break;
|
||||
case FORGET_PWD:
|
||||
precheckForgotPwd(user, loginRequest);
|
||||
break;
|
||||
default:
|
||||
throw new BusinessException("Unknown authentication operation type.");
|
||||
|
||||
@@ -77,11 +74,11 @@ public class LoginServiceImpl extends ServiceImpl<UserMapper, User> implements L
|
||||
if (Objects.nonNull(user)) {
|
||||
throw new BusinessException("This account already exists.");
|
||||
}
|
||||
String verifyCode = getCodeAndSetCache(REGISTER.name(), email);
|
||||
/*String verifyCode = getCodeAndSetCache(REGISTER.name(), email);
|
||||
Boolean sent = sendEmailUtil.send(email, REGISTER.name(), verifyCode);
|
||||
if (!sent) {
|
||||
throw new BusinessException("Failed to send verification code");
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
private void precheckLogin(User user, LoginRequest loginRequest) {
|
||||
@@ -91,35 +88,41 @@ public class LoginServiceImpl extends ServiceImpl<UserMapper, User> implements L
|
||||
if (!user.getPassword().equals(loginRequest.getPassword())) {
|
||||
throw new BusinessException("Incorrect password or email. Please try again.");
|
||||
}
|
||||
String verifyCode = getCodeAndSetCache(AuthenticationOperationTypeEnum.LOGIN.name(), loginRequest.getEmail());
|
||||
/*String verifyCode = getCodeAndSetCache(AuthenticationOperationTypeEnum.LOGIN.name(), loginRequest.getEmail());
|
||||
Boolean sent = sendEmailUtil.send(loginRequest.getEmail(), LOGIN.name(), verifyCode);
|
||||
if (!sent) {
|
||||
throw new BusinessException("Failed to send verification code");
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
private void precheckForgotPwd(User user, LoginRequest loginRequest) {
|
||||
@Override
|
||||
public void precheckForgotPwdAndSendEmail(String email) {
|
||||
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.lambda().eq(User::getEmail, email);
|
||||
|
||||
User user = getOne(queryWrapper);
|
||||
if (Objects.isNull(user)) {
|
||||
throw new BusinessException("Account does not exist. Please register.");
|
||||
}
|
||||
if (StringUtil.isNullOrEmpty(loginRequest.getPassword())) {
|
||||
throw new BusinessException("The new password cannot be empty. Please enter a new password.");
|
||||
}
|
||||
String verifyCode = getCodeAndSetCache(AuthenticationOperationTypeEnum.FORGET_PWD.name(), loginRequest.getEmail());
|
||||
Boolean sent = sendEmailUtil.send(loginRequest.getEmail(), FORGET_PWD.name(), verifyCode);
|
||||
|
||||
String verifyCode = getCodeAndSetCache(AuthenticationOperationTypeEnum.FORGET_PWD.name(), email);
|
||||
Boolean sent = sendEmailUtil.send(email, FORGET_PWD.name(), verifyCode);
|
||||
if (!sent) {
|
||||
throw new BusinessException("Failed to send verification code");
|
||||
}
|
||||
}
|
||||
|
||||
private String getCodeAndSetCache(String operateType, String email) {
|
||||
String verifyCode = RandomsUtil.generateSecureSixDigitRandom();
|
||||
String verifyCode = RandomsUtil.generateSecureFiveDigitRandom();
|
||||
String key = RedisURIConstants.verifyCodeCache + operateType + "_" + email;
|
||||
cacheUtil.setCache(key, verifyCode, RedisURIConstants.verifyCodeTimeout);
|
||||
return verifyCode;
|
||||
}
|
||||
|
||||
private void checkVerifyCode(String verifyCode, String operateType, String email) {
|
||||
if (StringUtil.isNullOrEmpty(verifyCode)) {
|
||||
throw new BusinessException("Verification code cannot be empty.");
|
||||
}
|
||||
String key = RedisURIConstants.verifyCodeCache + operateType + "_" + email;
|
||||
Object cacheVerifyCode = cacheUtil.getCache(key);
|
||||
if (Objects.isNull(cacheVerifyCode)) {
|
||||
@@ -140,6 +143,8 @@ public class LoginServiceImpl extends ServiceImpl<UserMapper, User> implements L
|
||||
public LoginVO registerOrLogin(LoginRequest loginRequest) {
|
||||
LoginVO loginVO;
|
||||
|
||||
preCheckAndSendEmail(loginRequest);
|
||||
|
||||
// 2. 获取当前的操作类型
|
||||
AuthenticationOperationTypeEnum operationTypeEnum = AuthenticationOperationTypeEnum.of(loginRequest.getOperationType());
|
||||
|
||||
@@ -156,7 +161,7 @@ public class LoginServiceImpl extends ServiceImpl<UserMapper, User> implements L
|
||||
// 注册
|
||||
private LoginVO register(LoginRequest loginRequest) {
|
||||
// 1. 验证邮箱
|
||||
checkVerifyCode(loginRequest.getVerifyCode(), REGISTER.name(), loginRequest.getEmail());
|
||||
// checkVerifyCode(loginRequest.getVerifyCode(), REGISTER.name(), loginRequest.getEmail());
|
||||
|
||||
// 2. 通过验证,添加账号
|
||||
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
|
||||
@@ -183,7 +188,7 @@ public class LoginServiceImpl extends ServiceImpl<UserMapper, User> implements L
|
||||
// 登录
|
||||
private LoginVO login(LoginRequest loginRequest) {
|
||||
// 1. 验证邮箱
|
||||
checkVerifyCode(loginRequest.getVerifyCode(), LOGIN.name(), loginRequest.getEmail());
|
||||
// checkVerifyCode(loginRequest.getVerifyCode(), LOGIN.name(), loginRequest.getEmail());
|
||||
|
||||
// 2. 获取用户信息
|
||||
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
|
||||
@@ -217,7 +222,12 @@ public class LoginServiceImpl extends ServiceImpl<UserMapper, User> implements L
|
||||
// 1. 验证邮箱
|
||||
checkVerifyCode(loginRequest.getVerifyCode(), FORGET_PWD.name(), loginRequest.getEmail());
|
||||
|
||||
// 2. 重置密码
|
||||
// 2. 验证新密码是否为空
|
||||
if (StringUtil.isNullOrEmpty(loginRequest.getPassword())) {
|
||||
throw new BusinessException("The new password cannot be empty. Please enter a new password.");
|
||||
}
|
||||
|
||||
// 3. 重置密码
|
||||
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
|
||||
updateWrapper.lambda()
|
||||
.set(User::getPassword, loginRequest.getPassword())
|
||||
|
||||
@@ -15,6 +15,7 @@ import com.aida.lanecarford.service.StyleService;
|
||||
import com.aida.lanecarford.util.CacheUtil;
|
||||
import com.aida.lanecarford.util.MinioUtil;
|
||||
import com.aida.lanecarford.util.SendRequestUtil;
|
||||
import com.aida.lanecarford.util.StringListConverter;
|
||||
import com.aida.lanecarford.vo.OutfitResultVO;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
@@ -24,6 +25,7 @@ import io.netty.util.internal.StringUtil;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
@@ -44,6 +46,9 @@ public class StyleServiceImpl extends ServiceImpl<StyleMapper, Style> implements
|
||||
@Resource
|
||||
private OutfitRequestMapper outfitRequestMapper;
|
||||
|
||||
@Value("${webhook.domain}")
|
||||
private String webhookDomain;
|
||||
|
||||
|
||||
// 请求获取搭配
|
||||
public List<String> requestOutfit(RequestOutfitDTO requestOutfitDTO) {
|
||||
@@ -96,6 +101,7 @@ public class StyleServiceImpl extends ServiceImpl<StyleMapper, Style> implements
|
||||
params.put("user_id", customerId.toString());
|
||||
params.put("num_outfits", num);
|
||||
params.put("stylist_path", stylistPath);
|
||||
params.put("callback_url", webhookDomain);
|
||||
|
||||
return params;
|
||||
}
|
||||
@@ -130,9 +136,10 @@ public class StyleServiceImpl extends ServiceImpl<StyleMapper, Style> implements
|
||||
// 3.更新path, items, 状态
|
||||
// 由于数据变化较频繁,考虑存到redis
|
||||
if (outfitResult instanceof OutfitResultVO) {
|
||||
((OutfitResultVO) outfitResult).setPath(minioUtil.getPresignedUrl(callbackDTO.getPath(), CommonConstants.MINIO_PATH_TIMEOUT, null));
|
||||
((OutfitResultVO) outfitResult).setStatus(StatusEnum.SUCCEEDED.name());
|
||||
cacheUtil.setCache(key, outfitResult, RedisURIConstants.verifyCodeTimeout);
|
||||
((OutfitResultVO) outfitResult).setPath(minioUtil.getPresignedUrl(callbackDTO.getPath(), CommonConstants.MINIO_PATH_TIMEOUT));
|
||||
String status = "ok".equals(callbackDTO.getStatus()) ? StatusEnum.RUNNING.name() : StatusEnum.SUCCEEDED.name();
|
||||
((OutfitResultVO) outfitResult).setStatus(status);
|
||||
cacheUtil.setCache(key, outfitResult, RedisURIConstants.outfitResultTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,9 +158,11 @@ public class StyleServiceImpl extends ServiceImpl<StyleMapper, Style> implements
|
||||
int status = "stop".equals(callbackDTO.getStatus()) ? StatusEnum.SUCCEEDED.getCode() : StatusEnum.FAILED.getCode();
|
||||
outfit.setGenerationStatus(status);
|
||||
outfit.setStyleImageUrl(callbackDTO.getPath());
|
||||
outfit.setItems(callbackDTO.getItems());
|
||||
outfit.setUpdatedTime(LocalDateTime.now());
|
||||
|
||||
String itemsJson = StringListConverter.listToJson(callbackDTO.getItems());
|
||||
outfit.setItems(itemsJson);
|
||||
|
||||
updateById(outfit);
|
||||
}
|
||||
}
|
||||
@@ -185,7 +194,7 @@ public class StyleServiceImpl extends ServiceImpl<StyleMapper, Style> implements
|
||||
outfitResultVO.setRequestId(style.getPythonRequestId());
|
||||
outfitResultVO.setStatus(StatusEnum.of(style.getGenerationStatus()).name());
|
||||
if (!StringUtil.isNullOrEmpty(style.getStyleImageUrl())) {
|
||||
outfitResultVO.setPath(minioUtil.getPresignedUrl(style.getStyleImageUrl(), CommonConstants.MINIO_PATH_TIMEOUT, null));
|
||||
outfitResultVO.setPath(minioUtil.getPresignedUrl(style.getStyleImageUrl(), CommonConstants.MINIO_PATH_TIMEOUT));
|
||||
}
|
||||
resultVOS.add(outfitResultVO);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.aida.lanecarford.util;
|
||||
|
||||
import com.aida.lanecarford.config.MinioConfig;
|
||||
import com.aida.lanecarford.common.constant.MinioFileConstants;
|
||||
import com.aida.lanecarford.exception.BusinessException;
|
||||
import com.aida.lanecarford.exception.MinioException;
|
||||
import io.minio.*;
|
||||
import io.minio.http.Method;
|
||||
@@ -298,6 +299,23 @@ public class MinioUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取预签名URL(路径中包含了桶名)
|
||||
*
|
||||
* @param path 对象名称(逻辑路径)
|
||||
* @param expires 过期时间(秒)
|
||||
* @return 预签名URL
|
||||
*/
|
||||
public String getPresignedUrl(String path, int expires) {
|
||||
if (!path.contains("/")) {
|
||||
throw new BusinessException("unknown path");
|
||||
}
|
||||
int index = path.indexOf("/");
|
||||
String bucketName = path.substring(0, index);
|
||||
String fileName = path.substring(index + 1);
|
||||
return getPresignedUrl(fileName, expires, bucketName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量获取预签名URL
|
||||
*
|
||||
|
||||
@@ -9,11 +9,11 @@ import java.security.SecureRandom;
|
||||
public class RandomsUtil {
|
||||
|
||||
/**
|
||||
* 使用ThreadLocalRandom生成6位随机数
|
||||
* 使用ThreadLocalRandom生成5位随机数
|
||||
*/
|
||||
public static String generateSecureSixDigitRandom() {
|
||||
public static String generateSecureFiveDigitRandom() {
|
||||
SecureRandom secureRandom = new SecureRandom();
|
||||
return String.format("%06d", secureRandom.nextInt(1000000));
|
||||
return String.format("%05d", secureRandom.nextInt(100000));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.aida.lanecarford.util;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
public class StringListConverter {
|
||||
|
||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
/**
|
||||
* 将 List<String> 转换为 JSON 字符串
|
||||
*/
|
||||
public static String listToJson(List<String> list) {
|
||||
if (list == null || list.isEmpty()) {
|
||||
return "[]";
|
||||
}
|
||||
try {
|
||||
return objectMapper.writeValueAsString(list);
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("List转JSON失败: {}", list, e);
|
||||
throw new RuntimeException("List转JSON失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 JSON 字符串转换为 List<String>
|
||||
*/
|
||||
public static List<String> jsonToList(String json) {
|
||||
if (json == null || json.trim().isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
try {
|
||||
return objectMapper.readValue(json, new TypeReference<List<String>>() {});
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("JSON转List失败: {}", json, e);
|
||||
throw new RuntimeException("JSON转List失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,3 +80,5 @@ tencent:
|
||||
secret-key: XqujLlywhHfrqcCYfYVHtNgmeIiwxkKf
|
||||
sender: info@aida.com.hk
|
||||
|
||||
webhook:
|
||||
domain: https://0dd6f6504aff.ngrok-free.app
|
||||
|
||||
@@ -1,157 +1,169 @@
|
||||
-- Lane Carford AI系统基础架构数据库表结构
|
||||
-- 创建数据库
|
||||
CREATE DATABASE IF NOT EXISTS lanecarford CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
USE lanecarford;
|
||||
USE lanecrawford;
|
||||
|
||||
-- 1. 导购表
|
||||
CREATE TABLE sales (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '导购ID',
|
||||
username VARCHAR(50) NOT NULL UNIQUE COMMENT '用户名',
|
||||
password VARCHAR(255) NOT NULL COMMENT '密码(加密后)',
|
||||
real_name VARCHAR(100) NOT NULL COMMENT '真实姓名',
|
||||
employee_id VARCHAR(50) UNIQUE COMMENT '员工编号',
|
||||
store_id VARCHAR(50) COMMENT '门店ID',
|
||||
store_name VARCHAR(100) COMMENT '门店名称',
|
||||
phone VARCHAR(20) COMMENT '手机号',
|
||||
email VARCHAR(100) COMMENT '邮箱',
|
||||
is_active TINYINT DEFAULT 1 COMMENT '是否启用(0-禁用,1-启用)',
|
||||
created_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
deleted TINYINT DEFAULT 0 COMMENT '逻辑删除标志(0-未删除,1-已删除)',
|
||||
INDEX idx_username (username),
|
||||
INDEX idx_employee_id (employee_id),
|
||||
INDEX idx_store_id (store_id),
|
||||
INDEX idx_deleted (deleted)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='导购表';
|
||||
-- 1. 用户表
|
||||
CREATE TABLE `user` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID',
|
||||
`username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '用户名',
|
||||
`email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '邮箱',
|
||||
`password` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '密码(加密后)',
|
||||
`gender` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '性别',
|
||||
`employee_id` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '员工编号',
|
||||
`store_id` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '门店ID',
|
||||
`store_name` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '门店名称',
|
||||
`phone` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '手机号',
|
||||
`avatar` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '头像地址',
|
||||
`language` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '系统语言',
|
||||
`is_active` tinyint DEFAULT '1' COMMENT '是否启用(0-禁用,1-启用)',
|
||||
`created_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updated_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` tinyint DEFAULT '0' COMMENT '逻辑删除标志(0-未删除,1-已删除)',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `username` (`username`),
|
||||
UNIQUE KEY `employee_id` (`employee_id`),
|
||||
KEY `idx_email` (`email`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户表';
|
||||
|
||||
-- 2. 顾客表
|
||||
CREATE TABLE customers (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '顾客ID',
|
||||
name VARCHAR(100) NOT NULL COMMENT '顾客姓名',
|
||||
email VARCHAR(100) NOT NULL COMMENT '顾客邮箱',
|
||||
phone VARCHAR(20) COMMENT '手机号',
|
||||
gender VARCHAR(10) COMMENT '性别',
|
||||
age_range VARCHAR(20) COMMENT '年龄段',
|
||||
created_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
deleted TINYINT DEFAULT 0 COMMENT '逻辑删除标志(0-未删除,1-已删除)',
|
||||
INDEX idx_email (email),
|
||||
INDEX idx_phone (phone),
|
||||
INDEX idx_name (name),
|
||||
INDEX idx_deleted (deleted)
|
||||
CREATE TABLE `customers` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '顾客ID',
|
||||
`name` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '顾客姓名',
|
||||
`email` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '顾客邮箱',
|
||||
`phone` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '手机号',
|
||||
`gender` varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '性别',
|
||||
`age_range` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '年龄段',
|
||||
`created_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updated_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` tinyint DEFAULT '0' COMMENT '逻辑删除标志(0-未删除,1-已删除)',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_email` (`email`),
|
||||
KEY `idx_phone` (`phone`),
|
||||
KEY `idx_name` (`name`),
|
||||
KEY `idx_deleted` (`deleted`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='顾客表';
|
||||
|
||||
-- 3. 进店记录表
|
||||
CREATE TABLE visit_records (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '进店记录ID',
|
||||
customer_id BIGINT NOT NULL COMMENT '顾客ID',
|
||||
sales_id BIGINT NOT NULL COMMENT '导购ID',
|
||||
visit_date DATE NOT NULL COMMENT '进店日期',
|
||||
visit_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '进店时间',
|
||||
notes TEXT COMMENT '备注',
|
||||
created_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
deleted TINYINT DEFAULT 0 COMMENT '逻辑删除标志(0-未删除,1-已删除)',
|
||||
FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (sales_id) REFERENCES sales(id) ON DELETE CASCADE,
|
||||
INDEX idx_customer_id (customer_id),
|
||||
INDEX idx_sales_id (sales_id),
|
||||
INDEX idx_deleted (deleted)
|
||||
CREATE TABLE `visit_records` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '进店记录ID',
|
||||
`customer_id` bigint NOT NULL COMMENT '顾客ID',
|
||||
`user_id` bigint NOT NULL COMMENT '导购ID',
|
||||
`visit_date` date NOT NULL COMMENT '进店日期',
|
||||
`visit_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '进店时间',
|
||||
`notes` text COLLATE utf8mb4_unicode_ci COMMENT '备注',
|
||||
`created_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updated_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` tinyint DEFAULT '0' COMMENT '逻辑删除标志(0-未删除,1-已删除)',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_customer_id` (`customer_id`),
|
||||
KEY `idx_user_id` (`user_id`),
|
||||
KEY `idx_deleted` (`deleted`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='进店记录表';
|
||||
|
||||
-- 4. 风格配置表
|
||||
CREATE TABLE styles (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '风格配置ID',
|
||||
customer_id BIGINT NOT NULL COMMENT '顾客ID',
|
||||
visit_record_id BIGINT NOT NULL COMMENT '进店记录ID',
|
||||
is_selected TINYINT DEFAULT 0 COMMENT '是否选中(0-未选中,1-已选中)',
|
||||
style_image_url VARCHAR(500) COMMENT '风格图片URL',
|
||||
python_request_id VARCHAR(100) COMMENT 'Python请求ID',
|
||||
generation_status TINYINT DEFAULT 0 COMMENT '生成状态(0-处理中,1-已完成,2-失败)',
|
||||
error_message TEXT COMMENT '错误信息',
|
||||
created_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
deleted TINYINT DEFAULT 0 COMMENT '逻辑删除标志(0-未删除,1-已删除)',
|
||||
FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (visit_record_id) REFERENCES visit_records(id) ON DELETE CASCADE,
|
||||
INDEX idx_customer_id (customer_id),
|
||||
INDEX idx_visit_record_id (visit_record_id),
|
||||
INDEX idx_python_request_id (python_request_id),
|
||||
INDEX idx_is_selected (is_selected),
|
||||
INDEX idx_generation_status (generation_status),
|
||||
INDEX idx_deleted (deleted)
|
||||
CREATE TABLE `styles` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '风格配置ID',
|
||||
`customer_id` bigint NOT NULL COMMENT '顾客ID',
|
||||
`visit_record_id` bigint NOT NULL COMMENT '进店记录ID',
|
||||
`outfit_request_id` bigint NOT NULL COMMENT '请求id',
|
||||
`is_selected` tinyint DEFAULT '0' COMMENT '是否选中(0-未选中,1-已选中)',
|
||||
`style_image_url` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '风格图片URL',
|
||||
`python_request_id` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'Python请求ID',
|
||||
`generation_status` tinyint DEFAULT '0' COMMENT '生成状态(0-处理中,1-已完成,2-失败)',
|
||||
`items` json DEFAULT NULL COMMENT '单品唯一标识',
|
||||
`error_message` text COLLATE utf8mb4_unicode_ci COMMENT '错误信息',
|
||||
`created_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updated_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` tinyint DEFAULT '0' COMMENT '逻辑删除标志(0-未删除,1-已删除)',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_customer_id` (`customer_id`),
|
||||
KEY `idx_visit_record_id` (`visit_record_id`),
|
||||
KEY `idx_python_request_id` (`python_request_id`),
|
||||
KEY `idx_is_selected` (`is_selected`),
|
||||
KEY `idx_generation_status` (`generation_status`),
|
||||
KEY `idx_deleted` (`deleted`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='风格配置表';
|
||||
|
||||
-- 5. 模特照片表
|
||||
CREATE TABLE model_photos (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '模特照片ID',
|
||||
photo_url VARCHAR(500) NOT NULL COMMENT '模特照片URL',
|
||||
photo_name VARCHAR(200) COMMENT '照片名称',
|
||||
gender VARCHAR(10) NOT NULL COMMENT '性别',
|
||||
is_active TINYINT DEFAULT 1 COMMENT '是否启用(0-禁用,1-启用)',
|
||||
sort_order INT DEFAULT 0 COMMENT '排序权重',
|
||||
created_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
deleted TINYINT DEFAULT 0 COMMENT '逻辑删除标志(0-未删除,1-已删除)',
|
||||
INDEX idx_gender (gender),
|
||||
INDEX idx_is_active (is_active),
|
||||
INDEX idx_sort_order (sort_order),
|
||||
INDEX idx_deleted (deleted)
|
||||
CREATE TABLE `model_photos` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '模特照片ID',
|
||||
`photo_url` varchar(500) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模特照片URL',
|
||||
`photo_name` varchar(200) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '照片名称',
|
||||
`gender` varchar(10) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '性别',
|
||||
`is_active` tinyint DEFAULT '1' COMMENT '是否启用(0-禁用,1-启用)',
|
||||
`sort_order` int DEFAULT '0' COMMENT '排序权重',
|
||||
`created_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updated_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` tinyint DEFAULT '0' COMMENT '逻辑删除标志(0-未删除,1-已删除)',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_gender` (`gender`),
|
||||
KEY `idx_is_active` (`is_active`),
|
||||
KEY `idx_sort_order` (`sort_order`),
|
||||
KEY `idx_deleted` (`deleted`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='模特照片表';
|
||||
|
||||
-- 6. 顾客照片表
|
||||
CREATE TABLE customer_photos (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '顾客照片ID',
|
||||
customer_id BIGINT NOT NULL COMMENT '顾客ID',
|
||||
visit_record_id BIGINT NOT NULL COMMENT '进店记录ID',
|
||||
photo_url VARCHAR(500) NOT NULL COMMENT '照片URL',
|
||||
is_primary TINYINT DEFAULT 0 COMMENT '是否为主照片(0-否,1-是)',
|
||||
upload_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '上传时间',
|
||||
created_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
deleted TINYINT DEFAULT 0 COMMENT '逻辑删除标志(0-未删除,1-已删除)',
|
||||
FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (visit_record_id) REFERENCES visit_records(id) ON DELETE CASCADE,
|
||||
INDEX idx_customer_id (customer_id),
|
||||
INDEX idx_visit_record_id (visit_record_id),
|
||||
INDEX idx_is_primary (is_primary),
|
||||
INDEX idx_deleted (deleted)
|
||||
CREATE TABLE `customer_photos` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '顾客照片ID',
|
||||
`customer_id` bigint NOT NULL COMMENT '顾客ID',
|
||||
`visit_record_id` bigint NOT NULL COMMENT '进店记录ID',
|
||||
`photo_url` varchar(500) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '照片URL',
|
||||
`is_primary` tinyint DEFAULT '0' COMMENT '是否为主照片(0-否,1-是)',
|
||||
`upload_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '上传时间',
|
||||
`created_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updated_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` tinyint DEFAULT '0' COMMENT '逻辑删除标志(0-未删除,1-已删除)',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_customer_id` (`customer_id`),
|
||||
KEY `idx_visit_record_id` (`visit_record_id`),
|
||||
KEY `idx_is_primary` (`is_primary`),
|
||||
KEY `idx_deleted` (`deleted`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='顾客照片表';
|
||||
|
||||
|
||||
|
||||
-- 8. 试穿效果表
|
||||
CREATE TABLE try_on_effects (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '试穿效果ID',
|
||||
customer_id BIGINT NOT NULL COMMENT '顾客ID',
|
||||
visit_record_id BIGINT NOT NULL COMMENT '进店记录ID',
|
||||
style_id BIGINT NOT NULL COMMENT '风格ID',
|
||||
model_photo_id BIGINT COMMENT '模特照片ID',
|
||||
customer_photo_id BIGINT COMMENT '顾客照片ID',
|
||||
prompt VARCHAR(500) COMMENT '提示词,当is_regenerated为1时才会有值',
|
||||
original_try_on_id BIGINT COMMENT '原试穿效果ID,当is_regenerated为1时才会有值',
|
||||
is_regenerated TINYINT DEFAULT 0 COMMENT '是否由生成结果重新生成(0-否,1-是)',
|
||||
result_image_url VARCHAR(500) COMMENT '试穿结果图片URL',
|
||||
request_id VARCHAR(100) COMMENT '请求ID',
|
||||
generation_status VARCHAR(20) DEFAULT 'pending' COMMENT '生成状态(pending-等待中,processing-处理中,completed-已完成,failed-失败)',
|
||||
error_message TEXT COMMENT '错误信息',
|
||||
is_favorite TINYINT DEFAULT 0 COMMENT '是否喜欢的最终造型(0-否,1-是)',
|
||||
created_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
deleted TINYINT DEFAULT 0 COMMENT '逻辑删除标志(0-未删除,1-已删除)',
|
||||
FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (visit_record_id) REFERENCES visit_records(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (style_id) REFERENCES styles(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (model_photo_id) REFERENCES model_photos(id) ON DELETE SET NULL,
|
||||
FOREIGN KEY (customer_photo_id) REFERENCES customer_photos(id) ON DELETE SET NULL,
|
||||
INDEX idx_customer_id (customer_id),
|
||||
INDEX idx_visit_record_id (visit_record_id),
|
||||
INDEX idx_style_id (style_id),
|
||||
INDEX idx_request_id (request_id),
|
||||
INDEX idx_generation_status (generation_status),
|
||||
INDEX idx_is_favorite (is_favorite),
|
||||
INDEX idx_deleted (deleted)
|
||||
-- 7. 试穿效果表
|
||||
CREATE TABLE `try_on_effects` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '试穿效果ID',
|
||||
`customer_id` bigint NOT NULL COMMENT '顾客ID',
|
||||
`visit_record_id` bigint NOT NULL COMMENT '进店记录ID',
|
||||
`style_id` bigint NOT NULL COMMENT '风格ID',
|
||||
`model_photo_id` bigint DEFAULT NULL COMMENT '模特照片ID',
|
||||
`customer_photo_id` bigint DEFAULT NULL COMMENT '顾客照片ID',
|
||||
`prompt` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '提示词,当is_regenerated为1时才会有值',
|
||||
`original_try_on_id` bigint DEFAULT NULL COMMENT '原试穿效果ID,当is_regenerated为1时才会有值',
|
||||
`is_regenerated` tinyint DEFAULT '0' COMMENT '是否由生成结果重新生成(0-否,1-是)',
|
||||
`result_image_url` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '试穿结果图片URL',
|
||||
`request_id` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '请求ID',
|
||||
`generation_status` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT 'pending' COMMENT '生成状态(pending-等待中,processing-处理中,completed-已完成,failed-失败)',
|
||||
`error_message` text COLLATE utf8mb4_unicode_ci COMMENT '错误信息',
|
||||
`is_favorite` tinyint DEFAULT '0' COMMENT '是否喜欢的最终造型(0-否,1-是)',
|
||||
`created_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updated_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` tinyint DEFAULT '0' COMMENT '逻辑删除标志(0-未删除,1-已删除)',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_customer_id` (`customer_id`),
|
||||
KEY `idx_visit_record_id` (`visit_record_id`),
|
||||
KEY `idx_style_id` (`style_id`),
|
||||
KEY `idx_request_id` (`request_id`),
|
||||
KEY `idx_generation_status` (`generation_status`),
|
||||
KEY `idx_is_favorite` (`is_favorite`),
|
||||
KEY `idx_deleted` (`deleted`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='试穿效果表';
|
||||
|
||||
-- 8. 穿搭请求表
|
||||
CREATE TABLE `outfit_request` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`customer_id` bigint NOT NULL COMMENT '顾客id',
|
||||
`visit_record_id` bigint NOT NULL COMMENT '进店记录id',
|
||||
`stylist` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '选择的设计师风格',
|
||||
`gender` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '选择的性别',
|
||||
`status` tinyint(1) DEFAULT '0' COMMENT '当前任务状态 0-处理中 1-成功 2-失败',
|
||||
`created_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updated_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` tinyint NOT NULL DEFAULT '0' COMMENT '逻辑删除标志:0-未删除,1-已删除',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='穿搭请求表';
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user