chore: update project files

This commit is contained in:
AIGC Developer
2025-11-13 17:01:39 +08:00
parent 83bf064bb2
commit 2961d2b0d0
344 changed files with 11549 additions and 15941 deletions

View File

@@ -0,0 +1,188 @@
package com.example.demo.config;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
import org.springdoc.core.models.GroupedOpenApi;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Arrays;
/**
* OpenAPI (Swagger) 配置类
* 访问地址: http://localhost:8080/swagger-ui.html
* API文档JSON: http://localhost:8080/v3/api-docs
*/
@Configuration
public class OpenApiConfig {
/**
* OpenAPI 主配置
*/
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("AIGC平台 API 文档")
.version("1.0.0")
.description("AIGC平台后端API接口文档包含用户认证、视频生成、支付、订单管理等模块")
.contact(new Contact()
.name("AIGC平台开发团队")
.email("support@vionow.com"))
.license(new License()
.name("Apache 2.0")
.url("https://www.apache.org/licenses/LICENSE-2.0.html")))
.servers(Arrays.asList(
new Server().url("http://localhost:8080").description("本地开发环境"),
new Server().url("http://172.22.0.1:8080").description("内网环境"),
new Server().url("https://vionow.com").description("生产环境")
))
.addSecurityItem(new SecurityRequirement().addList("Bearer Authentication"))
.components(new io.swagger.v3.oas.models.Components()
.addSecuritySchemes("Bearer Authentication", new SecurityScheme()
.type(SecurityScheme.Type.HTTP)
.scheme("bearer")
.bearerFormat("JWT")
.description("JWT认证格式: Bearer {token}")));
}
/**
* 所有API分组
*/
@Bean
public GroupedOpenApi allApis() {
return GroupedOpenApi.builder()
.group("all")
.displayName("所有API")
.pathsToMatch("/api/**")
.build();
}
/**
* 认证相关API
*/
@Bean
public GroupedOpenApi authApis() {
return GroupedOpenApi.builder()
.group("auth")
.displayName("认证授权")
.pathsToMatch("/api/auth/**", "/api/verification/**")
.build();
}
/**
* 用户作品API
*/
@Bean
public GroupedOpenApi userWorkApis() {
return GroupedOpenApi.builder()
.group("user-works")
.displayName("用户作品")
.pathsToMatch("/api/works/**")
.build();
}
/**
* 视频生成API
*/
@Bean
public GroupedOpenApi videoGenerationApis() {
return GroupedOpenApi.builder()
.group("video-generation")
.displayName("视频生成")
.pathsToMatch("/api/text-to-video/**", "/api/image-to-video/**", "/api/storyboard-video/**")
.build();
}
/**
* 支付相关API
*/
@Bean
public GroupedOpenApi paymentApis() {
return GroupedOpenApi.builder()
.group("payment")
.displayName("支付管理")
.pathsToMatch("/api/payments/**", "/api/orders/**")
.build();
}
/**
* 会员管理API
*/
@Bean
public GroupedOpenApi memberApis() {
return GroupedOpenApi.builder()
.group("member")
.displayName("会员管理")
.pathsToMatch("/api/members/**", "/api/subscription/**")
.build();
}
/**
* 积分系统API
*/
@Bean
public GroupedOpenApi pointsApis() {
return GroupedOpenApi.builder()
.group("points")
.displayName("积分系统")
.pathsToMatch("/api/points/**")
.build();
}
/**
* 任务管理API
*/
@Bean
public GroupedOpenApi taskApis() {
return GroupedOpenApi.builder()
.group("tasks")
.displayName("任务管理")
.pathsToMatch("/api/tasks/**", "/api/queue/**", "/api/task-status/**")
.build();
}
/**
* 管理后台API
* 注意这些API需要ADMIN权限但文档生成不需要权限验证
*/
@Bean
public GroupedOpenApi adminApis() {
return GroupedOpenApi.builder()
.group("admin")
.displayName("管理后台")
.pathsToMatch("/api/admin/**", "/api/dashboard/**", "/api/analytics/**", "/api/cleanup/**")
// 在文档生成时,不验证权限
.build();
}
/**
* 系统设置API
*/
@Bean
public GroupedOpenApi settingsApis() {
return GroupedOpenApi.builder()
.group("settings")
.displayName("系统设置")
.pathsToMatch("/api/settings/**", "/api/api-keys/**")
.build();
}
/**
* 公共API无需认证
*/
@Bean
public GroupedOpenApi publicApis() {
return GroupedOpenApi.builder()
.group("public")
.displayName("公共接口")
.pathsToMatch("/api/public/**", "/api/test/**")
.build();
}
}

View File

@@ -0,0 +1,102 @@
package com.example.demo.config;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
/**
* 请求日志过滤器
* 用于记录请求和响应的详细信息,特别是在出现 JSON 解析错误时帮助调试
*/
@Component
public class RequestLoggingFilter extends OncePerRequestFilter {
private static final Logger logger = LoggerFactory.getLogger(RequestLoggingFilter.class);
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// 包装请求和响应以便读取内容
ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request);
ContentCachingResponseWrapper wrappedResponse = new ContentCachingResponseWrapper(response);
try {
// 继续过滤链
filterChain.doFilter(wrappedRequest, wrappedResponse);
} catch (Exception e) {
// 如果出现异常,记录请求详情
logRequestDetails(wrappedRequest, e);
throw e;
} finally {
// 记录响应状态
if (wrappedResponse.getStatus() >= 400) {
// 只有在出现错误时才记录详细的请求信息
logRequestDetails(wrappedRequest, null);
}
// 复制响应内容到原始响应
wrappedResponse.copyBodyToResponse();
}
}
private void logRequestDetails(ContentCachingRequestWrapper request, Exception exception) {
try {
String uri = request.getRequestURI();
String method = request.getMethod();
// 只记录POST/PUT/PATCH请求的详情
if ("POST".equals(method) || "PUT".equals(method) || "PATCH".equals(method)) {
logger.error("=== 请求详情 ({}出现问题) ===", exception != null ? "捕获异常" : "响应错误");
logger.error("URI: {} {}", method, uri);
logger.error("Content-Type: {}", request.getContentType());
logger.error("Content-Length: {}", request.getContentLength());
// 获取请求体内容
byte[] content = request.getContentAsByteArray();
if (content.length > 0) {
String body = getContentAsString(content, request.getCharacterEncoding());
logger.error("请求体内容 (前1000字符):");
logger.error("{}", body.length() > 1000 ? body.substring(0, 1000) + "..." : body);
// 检查是否包含可疑的反斜杠
if (body.contains("\\")) {
logger.error("⚠️ 警告:请求体中包含反斜杠字符,这可能导致 JSON 解析错误");
// 显示反斜杠周围的上下文
int index = body.indexOf("\\");
if (index >= 0) {
int start = Math.max(0, index - 20);
int end = Math.min(body.length(), index + 20);
logger.error("反斜杠位置附近的内容: [{}]", body.substring(start, end));
}
}
}
if (exception != null) {
logger.error("异常: {}", exception.getMessage());
}
}
} catch (Exception e) {
logger.error("记录请求详情时出错", e);
}
}
private String getContentAsString(byte[] content, String charset) {
try {
return new String(content, charset != null ? charset : "UTF-8");
} catch (UnsupportedEncodingException e) {
return "[无法解码内容]";
}
}
}

View File

@@ -42,7 +42,39 @@ public class SecurityConfig {
.sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 无状态使用JWT
)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/login", "/register", "/api/public/**", "/api/auth/**", "/api/verification/**", "/api/email/**", "/api/tencent/**", "/api/test/**", "/api/polling/**", "/api/diagnostic/**", "/api/polling-diagnostic/**", "/api/monitor/**", "/css/**", "/js/**", "/h2-console/**").permitAll()
// Swagger/OpenAPI 路径 - 必须放在最前面,完全公开访问
.requestMatchers(
"/swagger-ui/**",
"/swagger-ui.html",
"/v3/api-docs/**",
"/v3/api-docs",
"/api-docs/**",
"/swagger-resources/**",
"/webjars/**",
"/configuration/ui",
"/configuration/security",
"/swagger-config",
"/api/swagger-config"
).permitAll()
// 公共路径
.requestMatchers(
"/login",
"/register",
"/api/public/**",
"/api/auth/**",
"/api/verification/**",
"/api/email/**",
"/api/tencent/**",
"/api/test/**",
"/api/polling/**",
"/api/diagnostic/**",
"/api/polling-diagnostic/**",
"/api/monitor/**",
"/api/health/**",
"/css/**",
"/js/**",
"/h2-console/**"
).permitAll()
.requestMatchers("/api/orders/stats").permitAll() // 统计接口允许匿名访问
.requestMatchers("/api/orders/**").authenticated() // 订单接口需要认证
.requestMatchers("/api/payments/alipay/notify", "/api/payments/alipay/return").permitAll() // 支付宝回调接口允许匿名访问(外部调用)
@@ -53,10 +85,13 @@ public class SecurityConfig {
.requestMatchers("/api/admin/**").hasRole("ADMIN") // 管理员API需要管理员权限
.requestMatchers("/settings", "/settings/**").hasRole("ADMIN")
.requestMatchers("/users/**").hasRole("ADMIN")
.anyRequest().authenticated()
.anyRequest().permitAll()
)
.formLogin(form -> form
.loginPage("/login")
// 使用email作为表单登录的用户名参数账号即邮箱
.usernameParameter("email")
.passwordParameter("password")
.defaultSuccessUrl("/", true)
.permitAll()
)
@@ -88,23 +123,58 @@ public class SecurityConfig {
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
// 允许前端开发服务器和ngrok域名
configuration.setAllowedOrigins(Arrays.asList(
"http://localhost:3000",
"http://127.0.0.1:3000",
"http://localhost:5173",
"http://127.0.0.1:5173"
));
// 面向海外用户使用最宽松的CORS配置
// 使用allowedOriginPatterns支持通配符当allowCredentials=true时必须使用patterns而不是origins
configuration.setAllowedOriginPatterns(Arrays.asList(
// 允许所有HTTP和HTTPS来源任意域名、任意IP、任意端口
"http://*:*",
"https://*:*",
"http://*",
"https://*",
"http://*.*",
"https://*.*",
"http://*.*.*",
"https://*.*.*",
// 本地开发环境
"http://localhost:*",
"http://127.0.0.1:*",
"http://0.0.0.0:*",
// 常见开发工具和隧道服务
"https://*.ngrok.io",
"https://*.ngrok-free.app"
"https://*.ngrok-free.app",
"https://*.cloudflare.com",
"https://*.vercel.app",
"https://*.netlify.app",
"https://*.herokuapp.com",
"https://*.github.io",
"https://*.gitlab.io",
// 生产域名(如果有)
"https://vionow.com",
"https://www.vionow.com",
"http://vionow.com",
"http://www.vionow.com",
"https://*.vionow.com"
));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
// 允许所有HTTP方法
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH", "HEAD", "TRACE", "CONNECT"));
// 允许所有请求头
configuration.setAllowedHeaders(Arrays.asList("*"));
// 允许携带凭证cookies, authorization headers等
configuration.setAllowCredentials(true);
configuration.setExposedHeaders(Arrays.asList("Authorization"));
configuration.setMaxAge(3600L); // 预检请求缓存时间
// 暴露所有响应头给客户端
configuration.setExposedHeaders(Arrays.asList("*"));
// 预检请求缓存时间1小时减少预检请求频率
configuration.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;

View File

@@ -0,0 +1,317 @@
package com.example.demo.controller;
import java.io.BufferedReader;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.alipay.api.internal.util.AlipaySignature;
import com.example.demo.model.Payment;
import com.example.demo.model.PaymentStatus;
import com.example.demo.repository.PaymentRepository;
import jakarta.servlet.http.HttpServletRequest;
/**
* 支付宝回调接口控制器
* 参考 IJPay 实现,处理支付宝异步通知和同步返回
*
* @author Generated
*/
@RestController
@RequestMapping("/api/payments/alipay")
public class AlipayCallbackController {
private static final Logger logger = LoggerFactory.getLogger(AlipayCallbackController.class);
@Autowired
private PaymentRepository paymentRepository;
@Autowired
private com.example.demo.config.PaymentConfig.AliPayConfig aliPayConfig;
/**
* 支付宝异步通知接口
* 支付宝服务器会通过POST方式调用此接口通知支付结果
*
* 参考 IJPay 实现:
* - 使用 AlipaySignature.rsaCheckV1() 验证签名
* - 处理重复通知(去重)
* - 更新订单状态
* - 返回 "success" 或 "failure"
*
* @param request HTTP请求对象
* @return "success" 表示处理成功,"failure" 表示处理失败
*/
@PostMapping(value = "/notify", produces = MediaType.TEXT_PLAIN_VALUE)
public String notifyUrl(HttpServletRequest request) {
logger.info("========== 收到支付宝异步通知 ==========");
logger.info("请求方法: {}", request.getMethod());
logger.info("请求URL: {}", request.getRequestURL());
logger.info("Content-Type: {}", request.getContentType());
try {
// 获取支付宝POST过来的反馈信息
Map<String, String> params = getRequestParams(request);
// 打印所有参数(用于调试)
logger.info("支付宝异步通知参数:");
for (Map.Entry<String, String> entry : params.entrySet()) {
logger.info(" {} = {}", entry.getKey(), entry.getValue());
}
// 验证签名
boolean verifyResult = AlipaySignature.rsaCheckV1(
params,
aliPayConfig.getPublicKey(),
aliPayConfig.getCharset() != null ? aliPayConfig.getCharset() : "UTF-8",
aliPayConfig.getSignType() != null ? aliPayConfig.getSignType() : "RSA2"
);
if (!verifyResult) {
logger.error("========== 支付宝异步通知签名验证失败 ==========");
return "failure";
}
logger.info("========== 支付宝异步通知签名验证成功 ==========");
// 获取关键参数
String tradeStatus = params.get("trade_status");
String outTradeNo = params.get("out_trade_no");
String tradeNo = params.get("trade_no");
String totalAmount = params.get("total_amount");
String appId = params.get("app_id");
logger.info("订单号: {}, 交易号: {}, 交易状态: {}, 金额: {}, 应用ID: {}",
outTradeNo, tradeNo, tradeStatus, totalAmount, appId);
// 查找支付记录
Optional<Payment> paymentOpt = paymentRepository.findByOrderId(outTradeNo);
if (!paymentOpt.isPresent()) {
logger.error("支付记录不存在: {}", outTradeNo);
return "failure";
}
Payment payment = paymentOpt.get();
// 处理重复通知(去重)
// 如果订单已经是成功状态,且本次通知也是成功,则认为是重复通知
if (payment.getStatus() == PaymentStatus.SUCCESS &&
("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus))) {
logger.info("收到重复的成功通知,订单号: {}, 已处理过直接返回success", outTradeNo);
return "success";
}
// 根据交易状态更新支付记录
boolean shouldUpdateOrder = false;
switch (tradeStatus) {
case "TRADE_SUCCESS":
case "TRADE_FINISHED":
// 交易成功
if (payment.getStatus() != PaymentStatus.SUCCESS) {
payment.setStatus(PaymentStatus.SUCCESS);
payment.setExternalTransactionId(tradeNo);
payment.setPaidAt(LocalDateTime.now());
shouldUpdateOrder = true;
logger.info("订单支付成功: {}", outTradeNo);
}
break;
case "TRADE_CLOSED":
// 交易关闭(未付款交易超时关闭,或支付完成后全额退款)
if (payment.getStatus() != PaymentStatus.CANCELLED) {
payment.setStatus(PaymentStatus.CANCELLED);
shouldUpdateOrder = true;
logger.info("订单已关闭: {}", outTradeNo);
}
break;
case "WAIT_BUYER_PAY":
// 交易创建,等待买家付款
if (payment.getStatus() != PaymentStatus.PROCESSING) {
payment.setStatus(PaymentStatus.PROCESSING);
shouldUpdateOrder = true;
logger.info("订单等待付款: {}", outTradeNo);
}
break;
default:
logger.warn("未知的交易状态: {}, 订单号: {}", tradeStatus, outTradeNo);
break;
}
// 保存支付记录
if (shouldUpdateOrder) {
paymentRepository.save(payment);
logger.info("支付记录更新成功: 订单号={}, 状态={}", outTradeNo, payment.getStatus());
// TODO: 这里可以触发订单状态更新、发送通知等业务逻辑
// 例如:更新订单状态、扣除用户资源点、发送通知等
}
logger.info("========== 支付宝异步通知处理完成 ==========");
return "success";
} catch (Exception e) {
logger.error("========== 处理支付宝异步通知异常 ==========", e);
return "failure";
}
}
/**
* 支付宝同步返回接口
* 用户支付完成后支付宝会跳转到此页面GET请求
*
* 参考 IJPay 实现:
* - 使用 AlipaySignature.rsaCheckV1() 验证签名
* - 验证成功后可以跳转到支付成功页面
*
* @param request HTTP请求对象
* @return 支付结果信息
*/
@GetMapping("/return")
public Map<String, Object> returnUrl(HttpServletRequest request) {
logger.info("========== 收到支付宝同步返回 ==========");
logger.info("请求方法: {}", request.getMethod());
logger.info("请求URL: {}", request.getRequestURL());
Map<String, Object> result = new HashMap<>();
try {
// 获取支付宝GET过来的反馈信息
Map<String, String> params = getRequestParams(request);
// 打印所有参数(用于调试)
logger.info("支付宝同步返回参数:");
for (Map.Entry<String, String> entry : params.entrySet()) {
logger.info(" {} = {}", entry.getKey(), entry.getValue());
}
// 验证签名
boolean verifyResult = AlipaySignature.rsaCheckV1(
params,
aliPayConfig.getPublicKey(),
aliPayConfig.getCharset() != null ? aliPayConfig.getCharset() : "UTF-8",
aliPayConfig.getSignType() != null ? aliPayConfig.getSignType() : "RSA2"
);
if (!verifyResult) {
logger.error("========== 支付宝同步返回签名验证失败 ==========");
result.put("success", false);
result.put("message", "签名验证失败");
return result;
}
logger.info("========== 支付宝同步返回签名验证成功 ==========");
// 获取关键参数
String outTradeNo = params.get("out_trade_no");
String tradeNo = params.get("trade_no");
String totalAmount = params.get("total_amount");
logger.info("订单号: {}, 交易号: {}, 金额: {}", outTradeNo, tradeNo, totalAmount);
// 查找支付记录
Optional<Payment> paymentOpt = paymentRepository.findByOrderId(outTradeNo);
if (!paymentOpt.isPresent()) {
logger.error("支付记录不存在: {}", outTradeNo);
result.put("success", false);
result.put("message", "支付记录不存在");
return result;
}
Payment payment = paymentOpt.get();
// 如果状态还是待支付,更新为处理中(实际状态应该由异步通知更新)
if (payment.getStatus() == PaymentStatus.PENDING) {
payment.setStatus(PaymentStatus.PROCESSING);
payment.setExternalTransactionId(tradeNo);
paymentRepository.save(payment);
logger.info("支付记录状态已更新为处理中: {}", outTradeNo);
}
result.put("success", true);
result.put("message", "支付成功");
result.put("orderId", outTradeNo);
result.put("tradeNo", tradeNo);
result.put("amount", totalAmount);
result.put("paymentStatus", payment.getStatus().name());
logger.info("========== 支付宝同步返回处理完成 ==========");
return result;
} catch (Exception e) {
logger.error("========== 处理支付宝同步返回异常 ==========", e);
result.put("success", false);
result.put("message", "处理失败: " + e.getMessage());
return result;
}
}
/**
* 从HttpServletRequest中获取所有参数
* 兼容GET和POST请求支持form-urlencoded格式
*
* 注意Spring Boot 3 使用 jakarta.servlet而 IJPay 可能使用 javax.servlet
* 所以这里手动解析参数,而不是直接使用 AliPayApi.toMap(request)
*
* @param request HTTP请求对象
* @return 参数Map
*/
private Map<String, String> getRequestParams(HttpServletRequest request) throws IOException {
Map<String, String> params = new HashMap<>();
// 获取URL参数GET请求
request.getParameterMap().forEach((key, values) -> {
if (values != null && values.length > 0) {
params.put(key, values[0]);
}
});
// 如果是POST请求尝试从请求体获取参数
if ("POST".equalsIgnoreCase(request.getMethod())) {
try (BufferedReader reader = request.getReader()) {
StringBuilder body = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
body.append(line);
}
// 解析form-urlencoded格式的请求体
if (body.length() > 0) {
String bodyStr = body.toString();
if (bodyStr.contains("=")) {
String[] pairs = bodyStr.split("&");
for (String pair : pairs) {
String[] keyValue = pair.split("=", 2);
if (keyValue.length == 2) {
try {
String key = java.net.URLDecoder.decode(keyValue[0], "UTF-8");
String value = java.net.URLDecoder.decode(keyValue[1], "UTF-8");
// POST参数会覆盖GET参数如果存在
params.put(key, value);
} catch (Exception e) {
logger.warn("解析参数失败: {}", pair, e);
}
}
}
}
}
}
}
return params;
}
}

View File

@@ -3,7 +3,6 @@ package com.example.demo.controller;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
@@ -22,7 +21,6 @@ import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.ijpay.alipay.AliPayApi;
/**
@@ -217,71 +215,9 @@ public class AlipayController {
}
/**
* 支付同步回调
* 支付同步回调和异步回调已移至 AlipayCallbackController
* 请使用 /api/payments/alipay/return 和 /api/payments/alipay/notify
*
* @deprecated 此方法已移除,请使用 AlipayCallbackController
*/
@GetMapping("/return")
public ResponseEntity<Map<String, Object>> returnUrl(HttpServletRequest request) {
Map<String, Object> response = new HashMap<>();
try {
Map<String, String> params = AliPayApi.toMap(request);
logger.info("支付宝同步回调参数: {}", params);
boolean verifyResult = AlipaySignature.rsaCertCheckV1(params,
aliPayConfig.getAliPayCertPath(), "UTF-8", "RSA2");
if (verifyResult) {
response.put("success", true);
response.put("message", "支付成功");
logger.info("支付宝同步回调验证成功");
} else {
response.put("success", false);
response.put("message", "支付验证失败");
logger.warn("支付宝同步回调验证失败");
}
} catch (Exception e) {
logger.error("支付宝同步回调处理失败", e);
response.put("success", false);
response.put("message", "处理失败: " + e.getMessage());
}
return ResponseEntity.ok(response);
}
/**
* 支付异步回调
*/
@PostMapping("/notify")
public String notifyUrl(HttpServletRequest request) {
try {
Map<String, String> params = AliPayApi.toMap(request);
logger.info("支付宝异步回调参数: {}", params);
boolean verifyResult = AlipaySignature.rsaCertCheckV1(params,
aliPayConfig.getAliPayCertPath(), "UTF-8", "RSA2");
if (verifyResult) {
// TODO: 处理支付成功业务逻辑
String outTradeNo = params.get("out_trade_no");
String tradeNo = params.get("trade_no");
String tradeStatus = params.get("trade_status");
logger.info("支付宝异步回调验证成功: outTradeNo={}, tradeNo={}, status={}",
outTradeNo, tradeNo, tradeStatus);
// 处理支付成功逻辑
if ("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus)) {
// 更新订单状态为已支付
// 这里可以调用订单服务更新状态
logger.info("订单支付成功: {}", outTradeNo);
}
return "success";
} else {
logger.warn("支付宝异步回调验证失败");
return "failure";
}
} catch (Exception e) {
logger.error("支付宝异步回调处理失败", e);
return "failure";
}
}
}

View File

@@ -1,197 +0,0 @@
package com.example.demo.controller;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.service.ApiResponseHandler;
import com.example.demo.util.JwtUtils;
/**
* API测试控制器
* 演示如何使用改进的API调用和返回值处理
*/
@RestController
@RequestMapping("/api/test")
public class ApiTestController {
private static final Logger logger = LoggerFactory.getLogger(ApiTestController.class);
@Autowired
private ApiResponseHandler apiResponseHandler;
@Autowired
private JwtUtils jwtUtils;
@Value("${ai.api.base-url:http://116.62.4.26:8081}")
private String aiApiBaseUrl;
@Value("${ai.api.key:ak_5f13ec469e6047d5b8155c3cc91350e2}")
private String aiApiKey;
/**
* 获取视频列表 - 演示GET API调用
*/
@GetMapping("/videos")
public ResponseEntity<Map<String, Object>> getVideos(
@RequestHeader("Authorization") String token) {
try {
// 验证用户身份
String username = extractUsernameFromToken(token);
if (username == null) {
return ResponseEntity.status(401)
.body(apiResponseHandler.createErrorResponse("用户未登录"));
}
// 调用API获取视频列表
Map<String, Object> result = apiResponseHandler.getVideoList(aiApiKey, aiApiBaseUrl);
return ResponseEntity.ok(apiResponseHandler.createSuccessResponse(result));
} catch (Exception e) {
logger.error("获取视频列表失败", e);
return ResponseEntity.status(500)
.body(apiResponseHandler.createErrorResponse("获取视频列表失败: " + e.getMessage()));
}
}
/**
* 获取任务状态 - 演示带参数的GET API调用
*/
@GetMapping("/tasks/{taskId}/status")
public ResponseEntity<Map<String, Object>> getTaskStatus(
@PathVariable String taskId,
@RequestHeader("Authorization") String token) {
try {
// 验证用户身份
String username = extractUsernameFromToken(token);
if (username == null) {
return ResponseEntity.status(401)
.body(apiResponseHandler.createErrorResponse("用户未登录"));
}
// 调用API获取任务状态
Map<String, Object> result = apiResponseHandler.getTaskStatus(taskId, aiApiKey, aiApiBaseUrl);
return ResponseEntity.ok(apiResponseHandler.createSuccessResponse(result));
} catch (Exception e) {
logger.error("获取任务状态失败", e);
return ResponseEntity.status(500)
.body(apiResponseHandler.createErrorResponse("获取任务状态失败: " + e.getMessage()));
}
}
/**
* 提交测试任务 - 演示POST API调用
*/
@PostMapping("/submit-task")
public ResponseEntity<Map<String, Object>> submitTestTask(
@RequestBody Map<String, Object> request,
@RequestHeader("Authorization") String token) {
try {
// 验证用户身份
String username = extractUsernameFromToken(token);
if (username == null) {
return ResponseEntity.status(401)
.body(apiResponseHandler.createErrorResponse("用户未登录"));
}
// 准备请求参数
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("modelName", request.getOrDefault("modelName", "default-model"));
requestBody.put("prompt", request.get("prompt"));
requestBody.put("aspectRatio", request.getOrDefault("aspectRatio", "16:9"));
requestBody.put("imageToVideo", request.getOrDefault("imageToVideo", false));
// 调用API提交任务
String url = aiApiBaseUrl + "/user/ai/tasks/submit";
Map<String, Object> result = apiResponseHandler.callApi(url, aiApiKey, requestBody);
return ResponseEntity.ok(apiResponseHandler.createSuccessResponse(result));
} catch (Exception e) {
logger.error("提交测试任务失败", e);
return ResponseEntity.status(500)
.body(apiResponseHandler.createErrorResponse("提交测试任务失败: " + e.getMessage()));
}
}
/**
* 直接调用外部API - 演示原始Unirest调用
*/
@GetMapping("/external-api")
public ResponseEntity<Map<String, Object>> callExternalApi(
@RequestHeader("Authorization") String token) {
try {
// 验证用户身份
String username = extractUsernameFromToken(token);
if (username == null) {
return ResponseEntity.status(401)
.body(apiResponseHandler.createErrorResponse("用户未登录"));
}
// 使用您提供的代码模式
String url = aiApiBaseUrl + "/v1/videos/";
// 这里演示您提到的代码模式
// Unirest.setTimeouts(0, 0);
// HttpResponse<String> response = Unirest.get(url)
// .header("Authorization", "Bearer " + aiApiKey)
// .asString();
// 使用我们的封装方法
Map<String, Object> result = apiResponseHandler.callGetApi(url, aiApiKey);
return ResponseEntity.ok(apiResponseHandler.createSuccessResponse(result));
} catch (Exception e) {
logger.error("调用外部API失败", e);
return ResponseEntity.status(500)
.body(apiResponseHandler.createErrorResponse("调用外部API失败: " + e.getMessage()));
}
}
/**
* 从Token中提取用户名
*/
private String extractUsernameFromToken(String token) {
try {
if (token == null || !token.startsWith("Bearer ")) {
return null;
}
String actualToken = jwtUtils.extractTokenFromHeader(token);
if (actualToken == null) {
return null;
}
String username = jwtUtils.getUsernameFromToken(actualToken);
if (username != null && !jwtUtils.isTokenExpired(actualToken)) {
return username;
}
return null;
} catch (Exception e) {
logger.error("解析token失败", e);
return null;
}
}
}

View File

@@ -46,9 +46,54 @@ public class AuthApiController {
public ResponseEntity<Map<String, Object>> login(@RequestBody Map<String, String> credentials,
HttpServletRequest request,
HttpServletResponse response) {
logger.warn("尝试使用用户名密码登录,但系统已禁用此方式");
return ResponseEntity.badRequest()
.body(createErrorResponse("系统已禁用用户名密码登录,请使用邮箱验证码登录"));
try {
// 支持使用邮箱+密码登录(账号就是邮箱)或用户名+密码
String emailOrUsername = credentials.get("email");
if (emailOrUsername == null || emailOrUsername.trim().isEmpty()) {
// 兼容旧客户端使用 username 字段
emailOrUsername = credentials.get("username");
}
String password = credentials.get("password");
if (emailOrUsername == null || emailOrUsername.trim().isEmpty() || password == null) {
return ResponseEntity.badRequest().body(createErrorResponse("邮箱/用户名或密码不能为空"));
}
// 先尝试按邮箱查找用户
com.example.demo.model.User user = userService.findByEmailOrNull(emailOrUsername);
if (user == null) {
// 再按用户名查找
user = userService.findByUsernameOrNull(emailOrUsername);
}
if (user == null) {
return ResponseEntity.badRequest().body(createErrorResponse("用户不存在"));
}
// 检查密码
if (!userService.checkPassword(password, user.getPasswordHash())) {
return ResponseEntity.badRequest().body(createErrorResponse("邮箱/用户名或密码不正确"));
}
// 生成JWT Token为了兼容系统中其他逻辑使用 user.getUsername() 作为 token subject
String token = jwtUtils.generateToken(user.getUsername(), user.getRole(), user.getId());
Map<String, Object> body = new HashMap<>();
body.put("success", true);
body.put("message", "登录成功");
Map<String, Object> data = new HashMap<>();
// 不返回密码哈希
user.setPasswordHash(null);
data.put("user", user);
data.put("token", token);
body.put("data", data);
logger.info("邮箱/用户名密码登录成功:{}", emailOrUsername);
return ResponseEntity.ok(body);
} catch (Exception e) {
logger.error("用户名密码登录出错:", e);
return ResponseEntity.badRequest().body(createErrorResponse("登录失败:" + e.getMessage()));
}
}
/**
@@ -84,49 +129,68 @@ public class AuthApiController {
logger.info("邮箱验证码登录 - 用户不存在,开始自动注册:{}", email);
// 从邮箱生成用户名(去掉@符号及后面的部分)
String username = email.split("@")[0];
logger.info("邮箱验证码登录 - 原始邮箱: '{}', 生成的用户名: '{}'", email, username);
String emailPrefix = email.split("@")[0];
String emailDomain = email.contains("@") ? email.split("@")[1] : "";
logger.info("邮箱验证码登录 - 原始邮箱: '{}', 邮箱前缀: '{}', 邮箱域名: '{}'", email, emailPrefix, emailDomain);
// 清理用户名(移除特殊字符,只保留字母、数字、下划线)
username = username.replaceAll("[^a-zA-Z0-9_]", "_");
// 清理邮箱前缀(移除特殊字符,只保留字母、数字、下划线)
String cleanPrefix = emailPrefix.replaceAll("[^a-zA-Z0-9_]", "_");
// 确保用户名长度不超过50个字符
if (username.length() > 50) {
username = username.substring(0, 50);
logger.info("邮箱验证码登录 - 用户名过长,截断为: '{}'", username);
}
// 生成基础用户名:优先使用邮箱前缀
String baseUsername = cleanPrefix;
// 确保用户名不为空且至少3个字符
if (username.length() < 3) {
username = username + "_" + System.currentTimeMillis() % 1000;
if (username.length() > 50) {
username = username.substring(0, 50);
}
if (baseUsername.length() < 3) {
baseUsername = baseUsername + "_" + System.currentTimeMillis() % 1000;
}
// 确保用户名长度不超过50个字符
if (baseUsername.length() > 50) {
baseUsername = baseUsername.substring(0, 50);
logger.info("邮箱验证码登录 - 用户名过长,截断为: '{}'", baseUsername);
}
// 确保用户名唯一
String originalUsername = username;
// 策略:如果基础用户名已存在,添加邮箱域名的简短标识或数字后缀
String username = baseUsername;
int counter = 1;
while (userService.findByUsernameOrNull(username) != null) {
// 如果用户名过长,需要重新截断
String baseUsername = originalUsername.length() > 45 ?
originalUsername.substring(0, 45) : originalUsername;
String newUsername = baseUsername + counter;
int maxAttempts = 1000;
while (userService.findByUsernameOrNull(username) != null && counter <= maxAttempts) {
// 尝试策略1添加邮箱域名的简短标识如 qq, 163
if (counter == 1 && emailDomain.length() > 0) {
String domainShort = emailDomain.split("\\.")[0]; // 获取域名第一部分
if (domainShort.length() > 0 && domainShort.length() <= 5) {
String candidateUsername = baseUsername.length() > 45 ?
baseUsername.substring(0, 45) : baseUsername;
candidateUsername = candidateUsername + "_" + domainShort;
if (candidateUsername.length() <= 50 &&
userService.findByUsernameOrNull(candidateUsername) == null) {
username = candidateUsername;
logger.info("邮箱验证码登录 - 使用域名标识生成用户名: '{}'", username);
break;
}
}
}
// 策略2添加数字后缀
String baseForSuffix = baseUsername.length() > 45 ?
baseUsername.substring(0, 45) : baseUsername;
String newUsername = baseForSuffix + counter;
if (newUsername.length() > 50) {
newUsername = newUsername.substring(0, 50);
}
username = newUsername;
counter++;
// 防止无限循环
if (counter > 1000) {
// 使用时间戳确保唯一性
username = "user_" + System.currentTimeMillis();
break;
}
}
logger.info("邮箱验证码登录 - 最终用户名: '{}'", username);
// 如果还是冲突,使用时间戳确保唯一性
if (counter > maxAttempts || userService.findByUsernameOrNull(username) != null) {
username = "user_" + System.currentTimeMillis();
logger.warn("邮箱验证码登录 - 用户名冲突过多,使用时间戳生成: '{}'", username);
}
logger.info("邮箱验证码登录 - 最终用户名: '{}' (原始邮箱: '{}')", username, email);
// 直接创建用户对象并设置所有必要字段
user = new User();
@@ -266,17 +330,50 @@ public class AuthApiController {
* 获取当前用户信息
*/
@GetMapping("/me")
public ResponseEntity<Map<String, Object>> getCurrentUser(Authentication authentication) {
public ResponseEntity<Map<String, Object>> getCurrentUser(Authentication authentication,
jakarta.servlet.http.HttpServletRequest request) {
try {
logger.info("获取当前用户信息 - authentication: {}", authentication);
if (authentication != null && authentication.isAuthenticated()) {
User user = null;
String username = authentication.getName();
logger.info("当前用户名: {}", username);
try {
User user = userService.findByUsername(username);
logger.info("找到用户: {}", user.getUsername());
// 首先尝试通过用户名查找
user = userService.findByUsernameOrNull(username);
// 如果通过用户名找不到尝试从JWT token中获取用户ID
if (user == null) {
String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
String token = authHeader.substring(7);
try {
Long userId = jwtUtils.getUserIdFromToken(token);
if (userId != null) {
logger.warn("通过用户名未找到用户尝试通过用户ID查找: {}", userId);
user = userService.findById(userId);
}
} catch (Exception e) {
logger.warn("从token获取用户ID失败: {}", e.getMessage());
}
}
}
// 如果通过用户名找不到,尝试通过邮箱查找(兼容邮箱登录的情况)
if (user == null && username.contains("@")) {
logger.warn("通过用户名未找到用户,尝试通过邮箱查找: {}", username);
user = userService.findByEmailOrNull(username);
}
if (user == null) {
logger.error("无法找到用户,用户名/邮箱: {}", username);
return ResponseEntity.badRequest()
.body(createErrorResponse("用户不存在: " + username));
}
logger.info("找到用户: ID={}, 用户名={}, 邮箱={}", user.getId(), user.getUsername(), user.getEmail());
Map<String, Object> response = new HashMap<>();
response.put("success", true);
@@ -285,7 +382,7 @@ public class AuthApiController {
} catch (Exception e) {
logger.error("查找用户失败: {}", username, e);
return ResponseEntity.badRequest()
.body(createErrorResponse("用户不存在: " + username));
.body(createErrorResponse("查找用户失败: " + e.getMessage()));
}
}

View File

@@ -7,29 +7,94 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import com.fasterxml.jackson.core.JsonParseException;
import jakarta.servlet.http.HttpServletRequest;
@ControllerAdvice
public class GlobalExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
/**
* 处理 JSON 解析错误
* 这个异常通常是因为请求体中的 JSON 格式不正确
*/
@ExceptionHandler(HttpMessageNotReadableException.class)
public ResponseEntity<Map<String, Object>> handleJsonParseException(
HttpMessageNotReadableException ex,
HttpServletRequest request) {
logger.error("=== JSON 解析错误 ===");
logger.error("请求URL: {}", request.getRequestURI());
logger.error("请求方法: {}", request.getMethod());
logger.error("Content-Type: {}", request.getContentType());
logger.error("错误消息: {}", ex.getMessage());
// 记录所有请求头
logger.error("请求头:");
request.getHeaderNames().asIterator().forEachRemaining(headerName -> {
logger.error(" {}: {}", headerName, request.getHeader(headerName));
});
// 获取根本原因
Throwable rootCause = ex.getRootCause();
if (rootCause != null) {
logger.error("根本原因: {}", rootCause.getMessage());
if (rootCause instanceof JsonParseException) {
JsonParseException jsonEx = (JsonParseException) rootCause;
logger.error("JSON解析位置: line {}, column {}",
jsonEx.getLocation().getLineNr(),
jsonEx.getLocation().getColumnNr());
}
}
ex.printStackTrace();
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("success", false);
errorResponse.put("message", "请求数据格式错误JSON 格式不正确");
errorResponse.put("error", "InvalidJsonFormat");
errorResponse.put("details", "请检查发送的数据格式,确保是有效的 JSON");
errorResponse.put("path", request.getRequestURI());
if (rootCause != null && rootCause.getMessage() != null) {
// 提取有用的错误信息,但不暴露太多内部细节
String errorMsg = rootCause.getMessage();
if (errorMsg.length() > 200) {
errorMsg = errorMsg.substring(0, 200) + "...";
}
errorResponse.put("parseError", errorMsg);
}
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse);
}
/**
* 处理其他所有异常
*/
@ExceptionHandler(Exception.class)
public ResponseEntity<Map<String, Object>> handleException(Exception e) {
logger.error("全局异常处理器捕获到异常", e);
public ResponseEntity<Map<String, Object>> handleException(Exception e, HttpServletRequest request) {
logger.error("全局异常处理器捕获到异常");
logger.error("请求URL: {}", request.getRequestURI());
logger.error("请求方法: {}", request.getMethod());
logger.error("异常类型: {}", e.getClass().getName());
logger.error("异常消息: {}", e.getMessage());
if (e.getCause() != null) {
logger.error("异常原因: {}", e.getCause().getMessage());
}
e.printStackTrace();
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("success", false);
errorResponse.put("message", "服务器内部错误: " + e.getMessage());
errorResponse.put("error", e.getClass().getSimpleName());
errorResponse.put("path", request.getRequestURI());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
}
}

View File

@@ -0,0 +1,162 @@
package com.example.demo.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.sql.DataSource;
import java.sql.Connection;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
/**
* 健康检查控制器
* 用于监控服务状态,无需认证
*/
@RestController
@RequestMapping("/api/health")
@Tag(name = "健康检查", description = "服务健康状态监控接口")
public class HealthCheckController {
@Autowired
private DataSource dataSource;
/**
* 健康检查接口
* @return 服务健康状态
*/
@GetMapping
@Operation(summary = "健康检查", description = "检查服务运行状态、数据库连接等")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "服务正常"),
@ApiResponse(responseCode = "503", description = "服务异常")
})
public ResponseEntity<Map<String, Object>> healthCheck() {
Map<String, Object> health = new HashMap<>();
boolean isHealthy = true;
try {
// 应用状态
health.put("status", "UP");
health.put("timestamp", LocalDateTime.now().toString());
health.put("service", "AIGC Platform API");
// 数据库连接检查
Map<String, Object> database = new HashMap<>();
try (Connection connection = dataSource.getConnection()) {
boolean isValid = connection.isValid(5); // 5秒超时
database.put("status", isValid ? "UP" : "DOWN");
database.put("type", "MySQL");
if (!isValid) {
isHealthy = false;
}
} catch (Exception e) {
database.put("status", "DOWN");
database.put("error", e.getMessage());
isHealthy = false;
}
health.put("database", database);
// 系统信息
Map<String, Object> system = new HashMap<>();
Runtime runtime = Runtime.getRuntime();
system.put("availableProcessors", runtime.availableProcessors());
system.put("totalMemory", runtime.totalMemory() / (1024 * 1024) + " MB");
system.put("freeMemory", runtime.freeMemory() / (1024 * 1024) + " MB");
system.put("maxMemory", runtime.maxMemory() / (1024 * 1024) + " MB");
health.put("system", system);
// 返回状态
if (isHealthy) {
return ResponseEntity.ok(health);
} else {
health.put("status", "DOWN");
return ResponseEntity.status(503).body(health);
}
} catch (Exception e) {
health.put("status", "DOWN");
health.put("error", e.getMessage());
return ResponseEntity.status(503).body(health);
}
}
/**
* 简单的健康检查(轻量级)
* @return 简单的健康状态
*/
@GetMapping("/ping")
@Operation(summary = "简单健康检查", description = "快速检查服务是否在线")
@ApiResponse(responseCode = "200", description = "服务在线")
public ResponseEntity<Map<String, String>> ping() {
Map<String, String> response = new HashMap<>();
response.put("status", "OK");
response.put("message", "pong");
response.put("timestamp", LocalDateTime.now().toString());
return ResponseEntity.ok(response);
}
/**
* 就绪检查Readiness Probe
* @return 服务是否就绪
*/
@GetMapping("/ready")
@Operation(summary = "就绪检查", description = "检查服务是否准备好处理请求")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "服务就绪"),
@ApiResponse(responseCode = "503", description = "服务未就绪")
})
public ResponseEntity<Map<String, Object>> readiness() {
Map<String, Object> readiness = new HashMap<>();
boolean isReady = true;
try {
// 检查数据库连接
try (Connection connection = dataSource.getConnection()) {
if (!connection.isValid(5)) {
isReady = false;
}
} catch (Exception e) {
isReady = false;
readiness.put("error", "Database connection failed: " + e.getMessage());
}
readiness.put("ready", isReady);
readiness.put("timestamp", LocalDateTime.now().toString());
if (isReady) {
return ResponseEntity.ok(readiness);
} else {
return ResponseEntity.status(503).body(readiness);
}
} catch (Exception e) {
readiness.put("ready", false);
readiness.put("error", e.getMessage());
return ResponseEntity.status(503).body(readiness);
}
}
/**
* 存活检查Liveness Probe
* @return 服务是否存活
*/
@GetMapping("/live")
@Operation(summary = "存活检查", description = "检查服务是否存活")
@ApiResponse(responseCode = "200", description = "服务存活")
public ResponseEntity<Map<String, Object>> liveness() {
Map<String, Object> liveness = new HashMap<>();
liveness.put("alive", true);
liveness.put("timestamp", LocalDateTime.now().toString());
return ResponseEntity.ok(liveness);
}
}

View File

@@ -27,17 +27,21 @@ import com.example.demo.model.OrderStatus;
import com.example.demo.model.PaymentMethod;
import com.example.demo.model.User;
import com.example.demo.service.OrderService;
import com.example.demo.service.UserService;
import jakarta.validation.Valid;
@RestController
@RequestMapping("/api/orders")
public class OrderApiController {
private static final Logger logger = LoggerFactory.getLogger(OrderApiController.class);
@Autowired
private OrderService orderService;
@Autowired
private UserService userService;
/**
* 获取订单列表
@@ -59,8 +63,9 @@ public class OrderApiController {
response.put("message", "用户未认证,请重新登录");
return ResponseEntity.status(401).body(response);
}
User user = (User) authentication.getPrincipal();
String username = authentication.getName();
User user = userService.findByUsername(username);
if (user == null) {
Map<String, Object> response = new HashMap<>();
response.put("success", false);
@@ -81,11 +86,49 @@ public class OrderApiController {
// 普通用户只能查看自己的订单
orderPage = orderService.findOrdersByUser(user, pageable, status, search);
}
// 转换订单数据,添加支付方式信息
Page<Map<String, Object>> orderDataPage = orderPage.map(order -> {
Map<String, Object> orderData = new HashMap<>();
orderData.put("id", order.getId());
orderData.put("orderNumber", order.getOrderNumber());
orderData.put("totalAmount", order.getTotalAmount());
orderData.put("currency", order.getCurrency());
orderData.put("status", order.getStatus());
orderData.put("orderType", order.getOrderType());
orderData.put("description", order.getDescription());
orderData.put("createdAt", order.getCreatedAt());
orderData.put("updatedAt", order.getUpdatedAt());
orderData.put("paidAt", order.getPaidAt());
// 添加用户信息
if (order.getUser() != null) {
Map<String, Object> userData = new HashMap<>();
userData.put("id", order.getUser().getId());
userData.put("username", order.getUser().getUsername());
orderData.put("user", userData);
}
// 从订单关联的Payment中获取支付方式
String paymentMethod = null;
if (order.getPayments() != null && !order.getPayments().isEmpty()) {
// 获取最新的支付记录
var latestPayment = order.getPayments().stream()
.filter(p -> p.getPaymentMethod() != null)
.findFirst();
if (latestPayment.isPresent()) {
paymentMethod = latestPayment.get().getPaymentMethod().name();
}
}
orderData.put("paymentMethod", paymentMethod);
return orderData;
});
Map<String, Object> response = new HashMap<>();
response.put("success", true);
response.put("data", orderPage);
response.put("data", orderDataPage);
return ResponseEntity.ok(response);
} catch (Exception e) {
@@ -109,15 +152,16 @@ public class OrderApiController {
response.put("message", "用户未认证,请重新登录");
return ResponseEntity.status(401).body(response);
}
User user = (User) authentication.getPrincipal();
String username = authentication.getName();
User user = userService.findByUsername(username);
if (user == null) {
Map<String, Object> response = new HashMap<>();
response.put("success", false);
response.put("message", "用户信息获取失败,请重新登录");
return ResponseEntity.status(401).body(response);
}
Order order = orderService.findById(id)
.orElse(null);
@@ -165,15 +209,16 @@ public class OrderApiController {
response.put("message", "用户未认证,请重新登录");
return ResponseEntity.status(401).body(response);
}
User user = (User) authentication.getPrincipal();
String username = authentication.getName();
User user = userService.findByUsername(username);
if (user == null) {
Map<String, Object> response = new HashMap<>();
response.put("success", false);
response.put("message", "用户信息获取失败,请重新登录");
return ResponseEntity.status(401).body(response);
}
order.setUser(user);
Order createdOrder = orderService.createOrder(order);
@@ -200,7 +245,8 @@ public class OrderApiController {
@RequestBody Map<String, String> request,
Authentication authentication) {
try {
User user = (User) authentication.getPrincipal();
String username = authentication.getName();
User user = userService.findByUsername(username);
Order order = orderService.findById(id)
.orElseThrow(() -> new RuntimeException("订单不存在"));
@@ -242,7 +288,8 @@ public class OrderApiController {
@RequestBody Map<String, String> request,
Authentication authentication) {
try {
User user = (User) authentication.getPrincipal();
String username = authentication.getName();
User user = userService.findByUsername(username);
Order order = orderService.findById(id)
.orElseThrow(() -> new RuntimeException("订单不存在"));
@@ -277,8 +324,9 @@ public class OrderApiController {
@RequestBody Map<String, String> request,
Authentication authentication) {
try {
User user = (User) authentication.getPrincipal();
String username = authentication.getName();
User user = userService.findByUsername(username);
// 只有管理员可以发货
if (!user.getRole().equals("ROLE_ADMIN")) {
return ResponseEntity.badRequest()
@@ -309,8 +357,9 @@ public class OrderApiController {
public ResponseEntity<Map<String, Object>> completeOrder(@PathVariable Long id,
Authentication authentication) {
try {
User user = (User) authentication.getPrincipal();
String username = authentication.getName();
User user = userService.findByUsername(username);
// 只有管理员可以完成订单
if (!user.getRole().equals("ROLE_ADMIN")) {
return ResponseEntity.badRequest()
@@ -341,7 +390,8 @@ public class OrderApiController {
@RequestBody Map<String, String> request,
Authentication authentication) {
try {
User user = (User) authentication.getPrincipal();
String username = authentication.getName();
User user = userService.findByUsername(username);
Order order = orderService.findById(id)
.orElseThrow(() -> new RuntimeException("订单不存在"));
@@ -392,8 +442,9 @@ public class OrderApiController {
response.put("message", "用户未认证,请重新登录");
return ResponseEntity.status(401).body(response);
}
User user = (User) authentication.getPrincipal();
String username = authentication.getName();
User user = userService.findByUsername(username);
if (user == null) {
Map<String, Object> response = new HashMap<>();
response.put("success", false);
@@ -431,7 +482,8 @@ public class OrderApiController {
public ResponseEntity<Map<String, Object>> deleteOrder(@PathVariable Long id,
Authentication authentication) {
try {
User user = (User) authentication.getPrincipal();
String username = authentication.getName();
User user = userService.findByUsername(username);
Order order = orderService.findById(id)
.orElseThrow(() -> new RuntimeException("订单不存在"));
@@ -463,8 +515,9 @@ public class OrderApiController {
public ResponseEntity<Map<String, Object>> deleteOrders(@RequestBody List<Long> orderIds,
Authentication authentication) {
try {
User user = (User) authentication.getPrincipal();
String username = authentication.getName();
User user = userService.findByUsername(username);
// 只有管理员可以批量删除
if (!user.getRole().equals("ROLE_ADMIN")) {
return ResponseEntity.badRequest()

View File

@@ -31,20 +31,24 @@ import com.example.demo.model.PaymentMethod;
import com.example.demo.model.User;
import com.example.demo.service.OrderService;
import com.example.demo.service.PaymentService;
import com.example.demo.service.UserService;
import jakarta.validation.Valid;
@Controller
@RequestMapping("/orders")
public class OrderController {
private static final Logger logger = LoggerFactory.getLogger(OrderController.class);
@Autowired
private OrderService orderService;
@Autowired
private PaymentService paymentService;
@Autowired
private UserService userService;
/**
* 显示订单列表
@@ -59,8 +63,9 @@ public class OrderController {
Authentication authentication,
Model model) {
try {
User user = (User) authentication.getPrincipal();
Sort sort = sortDir.equalsIgnoreCase("desc") ?
String username = authentication.getName();
User user = userService.findByUsername(username);
Sort sort = sortDir.equalsIgnoreCase("desc") ?
Sort.by(sortBy).descending() : Sort.by(sortBy).ascending();
Pageable pageable = PageRequest.of(page, size, sort);
@@ -94,11 +99,12 @@ public class OrderController {
* 显示订单详情
*/
@GetMapping("/{id}")
public String orderDetail(@PathVariable Long id,
Authentication authentication,
public String orderDetail(@PathVariable Long id,
Authentication authentication,
Model model) {
try {
User user = (User) authentication.getPrincipal();
String username = authentication.getName();
User user = userService.findByUsername(username);
Optional<Order> orderOpt = orderService.findById(id);
if (!orderOpt.isPresent()) {
@@ -152,7 +158,7 @@ public class OrderController {
* 处理创建订单
*/
@PostMapping("/create")
public String createOrder(@Valid @ModelAttribute Order order,
public String createOrder(@Valid @ModelAttribute Order order,
BindingResult result,
Authentication authentication,
Model model) {
@@ -162,8 +168,9 @@ public class OrderController {
model.addAttribute("orderStatuses", OrderStatus.values());
return "orders/form";
}
User user = (User) authentication.getPrincipal();
String username = authentication.getName();
User user = userService.findByUsername(username);
order.setUser(user);
// 验证订单项
@@ -211,7 +218,8 @@ public class OrderController {
Authentication authentication,
Model model) {
try {
User user = (User) authentication.getPrincipal();
String username = authentication.getName();
User user = userService.findByUsername(username);
Optional<Order> orderOpt = orderService.findById(id);
if (!orderOpt.isPresent()) {
@@ -253,7 +261,8 @@ public class OrderController {
Authentication authentication,
Model model) {
try {
User user = (User) authentication.getPrincipal();
String username = authentication.getName();
User user = userService.findByUsername(username);
Optional<Order> orderOpt = orderService.findById(id);
if (!orderOpt.isPresent()) {
@@ -290,8 +299,9 @@ public class OrderController {
Authentication authentication,
Model model) {
try {
User user = (User) authentication.getPrincipal();
String username = authentication.getName();
User user = userService.findByUsername(username);
// 只有管理员可以发货
if (!user.getRole().equals("ROLE_ADMIN")) {
model.addAttribute("error", "无权限操作此订单");
@@ -318,8 +328,9 @@ public class OrderController {
Authentication authentication,
Model model) {
try {
User user = (User) authentication.getPrincipal();
String username = authentication.getName();
User user = userService.findByUsername(username);
// 只有管理员可以完成订单
if (!user.getRole().equals("ROLE_ADMIN")) {
model.addAttribute("error", "无权限操作此订单");
@@ -347,7 +358,8 @@ public class OrderController {
Authentication authentication,
Model model) {
try {
User user = (User) authentication.getPrincipal();
String username = authentication.getName();
User user = userService.findByUsername(username);
Optional<Order> orderOpt = orderService.findById(id);
if (!orderOpt.isPresent()) {
@@ -400,8 +412,9 @@ public class OrderController {
Authentication authentication,
Model model) {
try {
User user = (User) authentication.getPrincipal();
String username = authentication.getName();
User user = userService.findByUsername(username);
// 只有管理员可以访问
if (!user.getRole().equals("ROLE_ADMIN")) {
model.addAttribute("error", "无权限访问");

View File

@@ -28,6 +28,7 @@ import com.example.demo.repository.PaymentRepository;
import com.example.demo.service.AlipayService;
import com.example.demo.service.PaymentService;
import com.example.demo.service.UserService;
import com.example.demo.util.JwtUtils;
@RestController
@RequestMapping("/api/payments")
@@ -46,6 +47,9 @@ public class PaymentApiController {
@Autowired
private PaymentRepository paymentRepository;
@Autowired
private JwtUtils jwtUtils;
/**
@@ -377,7 +381,8 @@ public class PaymentApiController {
*/
@GetMapping("/subscription/info")
public ResponseEntity<Map<String, Object>> getUserSubscriptionInfo(
Authentication authentication) {
Authentication authentication,
jakarta.servlet.http.HttpServletRequest request) {
try {
logger.info("=== 开始获取用户订阅信息 ===");
@@ -387,10 +392,40 @@ public class PaymentApiController {
.body(createErrorResponse("请先登录"));
}
User user = null;
String username = authentication.getName();
logger.info("认证用户名: {}", username);
try {
// Principal 现在是用户名字符串,直接通过用户名查找
user = userService.findByUsernameOrNull(username);
// 如果通过用户名找不到尝试从JWT token中获取用户ID
if (user == null) {
String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
String token = authHeader.substring(7);
try {
Long userId = jwtUtils.getUserIdFromToken(token);
if (userId != null) {
logger.warn("通过用户名未找到用户尝试通过用户ID查找: {}", userId);
user = userService.findById(userId);
}
} catch (Exception e) {
logger.warn("从token获取用户ID失败: {}", e.getMessage());
}
}
}
// 如果通过用户名找不到,尝试通过邮箱查找(兼容邮箱登录的情况)
if (user == null && username.contains("@")) {
logger.warn("通过用户名未找到用户,尝试通过邮箱查找: {}", username);
user = userService.findByEmailOrNull(username);
}
} catch (Exception e) {
logger.error("查找用户失败: {}", e.getMessage(), e);
}
User user = userService.findByUsername(username);
logger.info("查找用户结果: {}", user != null ? "找到用户ID: " + user.getId() : "未找到用户");
if (user == null) {

View File

@@ -22,6 +22,7 @@ import com.example.demo.model.PaymentMethod;
import com.example.demo.model.User;
import com.example.demo.service.AlipayService;
import com.example.demo.service.PaymentService;
import com.example.demo.service.UserService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
@@ -29,14 +30,17 @@ import jakarta.validation.Valid;
@Controller
@RequestMapping("/payment")
public class PaymentController {
private static final Logger logger = LoggerFactory.getLogger(PaymentController.class);
@Autowired
private PaymentService paymentService;
@Autowired
private AlipayService alipayService;
@Autowired
private UserService userService;
/**
* 显示支付页面
@@ -64,7 +68,8 @@ public class PaymentController {
try {
// 设置当前用户
User user = (User) authentication.getPrincipal();
String username = authentication.getName();
User user = userService.findByUsername(username);
payment.setUser(user);
// 设置默认货币
@@ -208,7 +213,8 @@ public class PaymentController {
@GetMapping("/history")
public String paymentHistory(Authentication authentication, Model model) {
try {
User user = (User) authentication.getPrincipal();
String username = authentication.getName();
User user = userService.findByUsername(username);
List<Payment> payments = paymentService.findByUserId(user.getId());
model.addAttribute("payments", payments);
return "payment/history";
@@ -223,11 +229,12 @@ public class PaymentController {
* 支付详情
*/
@GetMapping("/detail/{id}")
public String paymentDetail(@PathVariable Long id,
Authentication authentication,
public String paymentDetail(@PathVariable Long id,
Authentication authentication,
Model model) {
try {
User user = (User) authentication.getPrincipal();
String username = authentication.getName();
User user = userService.findByUsername(username);
Payment payment = paymentService.findById(id)
.orElseThrow(() -> new RuntimeException("支付记录不存在"));

View File

@@ -1,90 +0,0 @@
package com.example.demo.controller;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.service.PollingQueryService;
/**
* 轮询查询测试控制器
* 用于测试和监控轮询查询功能
*/
@RestController
@RequestMapping("/api/polling")
public class PollingTestController {
@Autowired
private PollingQueryService pollingQueryService;
/**
* 获取轮询查询统计信息
*/
@GetMapping("/stats")
public ResponseEntity<Map<String, Object>> getPollingStats() {
Map<String, Object> response = new HashMap<>();
try {
String stats = pollingQueryService.getPollingStats();
response.put("success", true);
response.put("message", "轮询查询统计信息");
response.put("stats", stats);
response.put("timestamp", System.currentTimeMillis());
return ResponseEntity.ok(response);
} catch (Exception e) {
response.put("success", false);
response.put("message", "获取统计信息失败: " + e.getMessage());
return ResponseEntity.status(500).body(response);
}
}
/**
* 手动触发轮询查询
*/
@PostMapping("/trigger")
public ResponseEntity<Map<String, Object>> triggerPolling() {
Map<String, Object> response = new HashMap<>();
try {
pollingQueryService.manualPollingQuery();
response.put("success", true);
response.put("message", "手动触发轮询查询成功");
response.put("timestamp", System.currentTimeMillis());
return ResponseEntity.ok(response);
} catch (Exception e) {
response.put("success", false);
response.put("message", "手动触发轮询查询失败: " + e.getMessage());
return ResponseEntity.status(500).body(response);
}
}
/**
* 检查轮询查询配置
*/
@GetMapping("/config")
public ResponseEntity<Map<String, Object>> getPollingConfig() {
Map<String, Object> response = new HashMap<>();
try {
Map<String, Object> config = new HashMap<>();
config.put("pollingInterval", "120000ms (2分钟)");
config.put("scheduledMethod", "TaskStatusPollingService.pollTaskStatuses()");
config.put("scheduledMethod2", "TaskQueueScheduler.checkTaskStatuses()");
config.put("scheduledMethod3", "PollingQueryService.executePollingQuery()");
config.put("enabled", true);
response.put("success", true);
response.put("message", "轮询查询配置信息");
response.put("config", config);
return ResponseEntity.ok(response);
} catch (Exception e) {
response.put("success", false);
response.put("message", "获取配置信息失败: " + e.getMessage());
return ResponseEntity.status(500).body(response);
}
}
}

View File

@@ -36,7 +36,7 @@ public class PromptOptimizerApiController {
@RequestBody Map<String, Object> request,
Authentication authentication) {
try {
String username = authentication.getName();
String username = (authentication != null) ? authentication.getName() : "anonymous";
logger.info("收到优化提示词请求,用户: {}", username);
// 从请求中提取参数

View File

@@ -4,7 +4,13 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
@@ -12,18 +18,29 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.model.TaskStatus;
import com.example.demo.repository.TaskStatusRepository;
import com.example.demo.service.TaskStatusPollingService;
import com.example.demo.util.JwtUtils;
@RestController
@RequestMapping("/api/task-status")
@CrossOrigin(origins = "http://localhost:5173")
public class TaskStatusApiController {
private static final Logger logger = LoggerFactory.getLogger(TaskStatusApiController.class);
@Autowired
private TaskStatusPollingService taskStatusPollingService;
@Autowired
private TaskStatusRepository taskStatusRepository;
@Autowired
private JwtUtils jwtUtils;
/**
* 获取任务状态
@@ -130,44 +147,172 @@ public class TaskStatusApiController {
@PostMapping("/poll")
public ResponseEntity<Map<String, Object>> triggerPolling(
@RequestHeader("Authorization") String token) {
try {
// 验证token但不使用用户名管理员接口
extractUsernameFromToken(token);
// 这里可以添加管理员权限检查
// if (!isAdmin(username)) {
// return ResponseEntity.status(403).body(Map.of("error", "权限不足"));
// }
taskStatusPollingService.pollTaskStatuses();
Map<String, Object> response = new HashMap<>();
response.put("success", true);
response.put("message", "轮询已触发");
return ResponseEntity.ok(response);
} catch (Exception e) {
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("error", "触发轮询失败: " + e.getMessage());
return ResponseEntity.status(500).body(errorResponse);
}
}
/**
* 从token中提取用户名简化实现
* 获取所有任务记录(管理员功能
*/
@GetMapping("/admin/all")
public ResponseEntity<Map<String, Object>> getAllTaskRecords(
@RequestHeader("Authorization") String token,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam(required = false) String status,
@RequestParam(required = false) String taskType,
@RequestParam(required = false) String search) {
Map<String, Object> response = new HashMap<>();
try {
// 验证token
String username = extractUsernameFromToken(token);
if (username == null) {
response.put("success", false);
response.put("message", "未授权访问");
return ResponseEntity.status(401).body(response);
}
// TODO: 添加管理员权限检查
// if (!isAdmin(username)) {
// response.put("success", false);
// response.put("message", "权限不足");
// return ResponseEntity.status(403).body(response);
// }
// 输入验证
if (page < 0) page = 0;
if (size <= 0 || size > 100) size = 10;
// 创建分页对象
Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createdAt"));
Page<TaskStatus> taskPage;
// 根据条件查询
if (status != null && !status.isEmpty() && !"all".equals(status)) {
try {
TaskStatus.Status statusEnum = TaskStatus.Status.valueOf(status.toUpperCase());
taskPage = taskStatusRepository.findByStatus(statusEnum, pageable);
} catch (IllegalArgumentException e) {
logger.warn("无效的任务状态: {}", status);
taskPage = taskStatusRepository.findAllWithPagination(pageable);
}
} else if (taskType != null && !taskType.isEmpty()) {
try {
TaskStatus.TaskType taskTypeEnum = TaskStatus.TaskType.valueOf(taskType.toUpperCase());
taskPage = taskStatusRepository.findByTaskType(taskTypeEnum, pageable);
} catch (IllegalArgumentException e) {
logger.warn("无效的任务类型: {}", taskType);
taskPage = taskStatusRepository.findAllWithPagination(pageable);
}
} else {
taskPage = taskStatusRepository.findAllWithPagination(pageable);
}
// 构建响应数据
List<Map<String, Object>> taskRecords = taskPage.getContent().stream()
.map(task -> {
Map<String, Object> record = new HashMap<>();
record.put("id", task.getId());
record.put("taskId", task.getTaskId());
record.put("username", task.getUsername());
record.put("type", task.getTaskType() != null ? task.getTaskType().getDescription() : "未知");
record.put("taskType", task.getTaskType() != null ? task.getTaskType().name() : null);
record.put("status", task.getStatus().name());
record.put("statusText", task.getStatus().getDescription());
record.put("progress", task.getProgress());
record.put("resultUrl", task.getResultUrl());
record.put("errorMessage", task.getErrorMessage());
record.put("createdAt", task.getCreatedAt());
record.put("updatedAt", task.getUpdatedAt());
record.put("completedAt", task.getCompletedAt());
// 计算消耗资源(根据任务类型)
String resources = "0积分";
if (task.getTaskType() != null) {
switch (task.getTaskType()) {
case TEXT_TO_VIDEO:
resources = "10积分";
break;
case IMAGE_TO_VIDEO:
resources = "5积分";
break;
case STORYBOARD_VIDEO:
resources = "15积分";
break;
}
}
record.put("resources", resources);
return record;
})
.toList();
response.put("success", true);
response.put("data", taskRecords);
response.put("totalElements", taskPage.getTotalElements());
response.put("totalPages", taskPage.getTotalPages());
response.put("currentPage", page);
response.put("size", size);
return ResponseEntity.ok(response);
} catch (Exception e) {
logger.error("获取任务记录失败", e);
response.put("success", false);
response.put("message", "获取任务记录失败: " + e.getMessage());
return ResponseEntity.status(500).body(response);
}
}
/**
* 从token中提取用户名
*/
private String extractUsernameFromToken(String token) {
// 这里应该解析JWT token现在简化处理
// 实际实现应该使用JWT工具类
String cleanToken = token;
if (token.startsWith("Bearer ")) {
cleanToken = token.substring(7);
try {
if (token == null || !token.startsWith("Bearer ")) {
return null;
}
// 提取实际的token
String actualToken = jwtUtils.extractTokenFromHeader(token);
if (actualToken == null) {
return null;
}
// 验证token并获取用户名
String username = jwtUtils.getUsernameFromToken(actualToken);
if (username != null && !jwtUtils.isTokenExpired(actualToken)) {
return username;
}
return null;
} catch (Exception e) {
logger.error("解析token失败", e);
return null;
}
// 简化处理实际应该解析JWT
return "admin"; // 临时返回admin实际应该从JWT中解析
}
}

View File

@@ -1,50 +0,0 @@
package com.example.demo.controller;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.util.JwtUtils;
@RestController
@RequestMapping("/api/test")
public class TestController {
@Autowired
private JwtUtils jwtUtils;
@GetMapping("/generate-token")
public ResponseEntity<Map<String, Object>> generateToken() {
Map<String, Object> response = new HashMap<>();
try {
// 为admin用户生成新的token
String token = jwtUtils.generateToken("admin", "ROLE_ADMIN", 231L);
response.put("success", true);
response.put("token", token);
response.put("message", "Token生成成功");
return ResponseEntity.ok(response);
} catch (Exception e) {
response.put("success", false);
response.put("message", "Token生成失败: " + e.getMessage());
return ResponseEntity.status(500).body(response);
}
}
@GetMapping("/test-auth")
public ResponseEntity<Map<String, Object>> testAuth() {
Map<String, Object> response = new HashMap<>();
response.put("success", true);
response.put("message", "认证测试成功");
response.put("timestamp", System.currentTimeMillis());
return ResponseEntity.ok(response);
}
}

View File

@@ -91,11 +91,6 @@ public class TextToVideoApiController {
return ResponseEntity.badRequest().body(response);
}
if (prompt.trim().length() > 1000) {
response.put("success", false);
response.put("message", "文本描述不能超过1000个字符");
return ResponseEntity.badRequest().body(response);
}
if (duration < 1 || duration > 60) {
response.put("success", false);

View File

@@ -1,17 +1,28 @@
package com.example.demo.controller;
import com.example.demo.model.UserWork;
import com.example.demo.service.UserWorkService;
import com.example.demo.util.JwtUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
import com.example.demo.model.UserWork;
import com.example.demo.service.UserWorkService;
import com.example.demo.util.JwtUtils;
/**
* 用户作品API控制器
@@ -28,6 +39,38 @@ public class UserWorkApiController {
@Autowired
private JwtUtils jwtUtils;
/**
* 获取正在进行中的作品
*/
@GetMapping("/processing")
public ResponseEntity<Map<String, Object>> getProcessingWorks(
@RequestHeader("Authorization") String token) {
Map<String, Object> response = new HashMap<>();
try {
String username = extractUsernameFromToken(token);
if (username == null) {
response.put("success", false);
response.put("message", "用户未登录");
return ResponseEntity.status(401).body(response);
}
List<UserWork> processingWorks = userWorkService.getProcessingWorks(username);
response.put("success", true);
response.put("data", processingWorks);
return ResponseEntity.ok(response);
} catch (Exception e) {
logger.error("获取正在进行中的作品失败", e);
response.put("success", false);
response.put("message", "获取作品失败:" + e.getMessage());
return ResponseEntity.status(500).body(response);
}
}
/**
* 获取我的作品列表
*/
@@ -75,7 +118,7 @@ public class UserWorkApiController {
/**
* 获取作品详情
*/
@GetMapping("/{workId}")
@GetMapping("/{workId:\\d+}")
public ResponseEntity<Map<String, Object>> getWorkDetail(
@PathVariable Long workId,
@RequestHeader("Authorization") String token) {
@@ -111,7 +154,7 @@ public class UserWorkApiController {
/**
* 更新作品信息
*/
@PutMapping("/{workId}")
@PutMapping("/{workId:\\d+}")
public ResponseEntity<Map<String, Object>> updateWork(
@PathVariable Long workId,
@RequestHeader("Authorization") String token,
@@ -157,7 +200,7 @@ public class UserWorkApiController {
/**
* 删除作品
*/
@DeleteMapping("/{workId}")
@DeleteMapping("/{workId:\\d+}")
public ResponseEntity<Map<String, Object>> deleteWork(
@PathVariable Long workId,
@RequestHeader("Authorization") String token) {
@@ -194,7 +237,7 @@ public class UserWorkApiController {
/**
* 点赞作品
*/
@PostMapping("/{workId}/like")
@PostMapping("/{workId:\\d+}/like")
public ResponseEntity<Map<String, Object>> likeWork(
@PathVariable Long workId,
@RequestHeader("Authorization") String token) {
@@ -234,7 +277,7 @@ public class UserWorkApiController {
/**
* 下载作品
*/
@PostMapping("/{workId}/download")
@PostMapping("/{workId:\\d+}/download")
public ResponseEntity<Map<String, Object>> downloadWork(
@PathVariable Long workId,
@RequestHeader("Authorization") String token) {

View File

@@ -1,13 +1,19 @@
package com.example.demo.controller;
import com.example.demo.service.VerificationCodeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.service.VerificationCodeService;
/**
* 验证码控制器
*/
@@ -15,6 +21,8 @@ import java.util.Map;
@RequestMapping("/api/verification")
public class VerificationCodeController {
private static final Logger logger = LoggerFactory.getLogger(VerificationCodeController.class);
@Autowired
private VerificationCodeService verificationCodeService;
@@ -24,10 +32,12 @@ public class VerificationCodeController {
*/
@PostMapping("/email/send")
public ResponseEntity<Map<String, Object>> sendEmailCode(@RequestBody Map<String, String> request) {
logger.info("收到发送验证码请求,参数: {}", request);
Map<String, Object> response = new HashMap<>();
String email = request.get("email");
if (email == null || email.trim().isEmpty()) {
logger.warn("验证码发送请求失败:邮箱为空");
response.put("success", false);
response.put("message", "邮箱不能为空");
return ResponseEntity.badRequest().body(response);
@@ -35,25 +45,31 @@ public class VerificationCodeController {
// 简单的邮箱格式验证
if (!email.matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$")) {
logger.warn("验证码发送请求失败:邮箱格式不正确,邮箱: {}", email);
response.put("success", false);
response.put("message", "邮箱格式不正确");
return ResponseEntity.badRequest().body(response);
}
logger.info("开始发送验证码到邮箱: {}", email);
try {
boolean success = verificationCodeService.sendEmailVerificationCode(email);
if (success) {
logger.info("验证码发送成功,邮箱: {}", email);
response.put("success", true);
response.put("message", "验证码发送成功");
} else {
logger.warn("验证码发送失败,邮箱: {}", email);
response.put("success", false);
response.put("message", "验证码发送失败,请稍后重试");
}
} catch (Exception e) {
logger.error("验证码发送异常,邮箱: {}", email, e);
response.put("success", false);
response.put("message", "验证码发送失败:" + e.getMessage());
}
logger.info("验证码发送请求处理完成,邮箱: {}, 结果: {}", email, response.get("success"));
return ResponseEntity.ok(response);
}

View File

@@ -76,3 +76,7 @@ public class MailMessage {

View File

@@ -269,4 +269,8 @@ public class TaskStatus {

View File

@@ -100,7 +100,8 @@ public class UserWork {
public enum WorkType {
TEXT_TO_VIDEO("文生视频"),
IMAGE_TO_VIDEO("图生视频"),
STORYBOARD_VIDEO("分镜视频");
STORYBOARD_VIDEO("分镜视频"),
STORYBOARD_IMAGE("分镜图");
private final String description;

View File

@@ -58,6 +58,13 @@ public interface TaskQueueRepository extends JpaRepository<TaskQueue, Long> {
*/
@Query("SELECT tq FROM TaskQueue tq WHERE tq.status = 'PROCESSING' AND tq.checkCount < tq.maxCheckCount ORDER BY tq.lastCheckTime ASC NULLS FIRST, tq.createdAt ASC")
List<TaskQueue> findTasksToCheck();
/**
* 统计需要检查的任务数量状态为PROCESSING且未超时
* 用于快速检查是否有待处理任务
*/
@Query("SELECT COUNT(tq) FROM TaskQueue tq WHERE tq.status = 'PROCESSING' AND tq.checkCount < tq.maxCheckCount")
long countTasksToCheck();
/**
* 查找超时的任务

View File

@@ -33,6 +33,12 @@ public interface TaskStatusRepository extends JpaRepository<TaskStatus, Long> {
*/
@Query("SELECT t FROM TaskStatus t WHERE t.status = 'PROCESSING' AND t.pollCount < t.maxPolls AND (t.lastPolledAt IS NULL OR t.lastPolledAt < :cutoffTime)")
List<TaskStatus> findTasksNeedingPolling(@Param("cutoffTime") LocalDateTime cutoffTime);
/**
* 计数:查找需要轮询的任务数量(用于快速短路判断,避免加载实体列表)
*/
@Query("SELECT COUNT(t) FROM TaskStatus t WHERE t.status = 'PROCESSING' AND t.pollCount < t.maxPolls AND (t.lastPolledAt IS NULL OR t.lastPolledAt < :cutoffTime)")
long countTasksNeedingPolling(@Param("cutoffTime") LocalDateTime cutoffTime);
/**
* 查找超时的任务
@@ -49,6 +55,11 @@ public interface TaskStatusRepository extends JpaRepository<TaskStatus, Long> {
* 统计用户的任务数量
*/
long countByUsername(String username);
/**
* 根据状态统计任务数量(用于快速短路判断)
*/
long countByStatus(TaskStatus.Status status);
/**
* 统计用户指定状态的任务数量
@@ -60,6 +71,22 @@ public interface TaskStatusRepository extends JpaRepository<TaskStatus, Long> {
*/
@Query("SELECT t FROM TaskStatus t WHERE t.username = :username ORDER BY t.createdAt DESC")
List<TaskStatus> findRecentTasksByUsername(@Param("username") String username, org.springframework.data.domain.Pageable pageable);
/**
* 查找所有任务(管理员功能,支持分页)
*/
@Query("SELECT t FROM TaskStatus t ORDER BY t.createdAt DESC")
org.springframework.data.domain.Page<TaskStatus> findAllWithPagination(org.springframework.data.domain.Pageable pageable);
/**
* 根据状态查找任务(管理员功能,支持分页)
*/
org.springframework.data.domain.Page<TaskStatus> findByStatus(TaskStatus.Status status, org.springframework.data.domain.Pageable pageable);
/**
* 根据任务类型查找任务(管理员功能,支持分页)
*/
org.springframework.data.domain.Page<TaskStatus> findByTaskType(TaskStatus.TaskType taskType, org.springframework.data.domain.Pageable pageable);
}
@@ -78,3 +105,4 @@ public interface TaskStatusRepository extends JpaRepository<TaskStatus, Long> {

View File

@@ -32,6 +32,12 @@ public interface UserWorkRepository extends JpaRepository<UserWork, Long> {
@Query("SELECT uw FROM UserWork uw WHERE uw.username = :username AND uw.status = :status ORDER BY uw.createdAt DESC")
List<UserWork> findByUsernameAndStatusOrderByCreatedAtDesc(@Param("username") String username, @Param("status") UserWork.WorkStatus status);
/**
* 根据用户名查找正在进行中和排队中的作品
*/
@Query("SELECT uw FROM UserWork uw WHERE uw.username = :username AND (uw.status = 'PROCESSING' OR uw.status = 'PENDING') ORDER BY uw.createdAt DESC")
List<UserWork> findByUsernameAndProcessingOrPendingOrderByCreatedAtDesc(@Param("username") String username);
/**
* 根据任务ID查找作品
*/

View File

@@ -26,6 +26,12 @@ public class TaskQueueScheduler {
@Autowired
private TaskQueueService taskQueueService;
@Autowired
private com.example.demo.repository.TaskStatusRepository taskStatusRepository;
@Autowired
private com.example.demo.service.TaskStatusPollingService taskStatusPollingService;
@Autowired
private TaskCleanupService taskCleanupService;
@@ -56,11 +62,28 @@ public class TaskQueueScheduler {
* 检查任务状态 - 每2分钟执行一次轮询查询
* 固定间隔120000毫秒 = 2分钟
* 查询正在处理的任务状态,更新完成/失败状态
* 优化:只在有待处理任务时才执行轮询,节省资源
*/
@Scheduled(fixedRate = 120000) // 2分钟 = 120000毫秒
public void checkTaskStatuses() {
try {
// 新策略:仅在任务队列中存在待处理任务时才进行轮询查询
boolean hasQueueTasks = taskQueueService.hasTasksToCheck();
if (!hasQueueTasks) {
// 没有待处理任务,静默跳过轮询,不输出日志以减少噪音
return;
}
logger.debug("发现待处理任务,开始轮询查询");
// 队列中有任务检查队列内任务状态并在必要时调用状态轮询如果存在正在PROCESSING的任务
taskQueueService.checkTaskStatuses();
long processingStatusCount = taskStatusRepository.countByStatus(com.example.demo.model.TaskStatus.Status.PROCESSING);
if (processingStatusCount > 0) {
// TaskStatusPollingService 的 @Scheduled 已被禁用,统一由此处调用
taskStatusPollingService.pollTaskStatuses();
}
} catch (Exception e) {
logger.error("检查任务状态失败", e);
}

View File

@@ -38,35 +38,68 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
}
@Override
protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response,
protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response,
@NonNull FilterChain filterChain) throws ServletException, IOException {
logger.info("JWT过滤器处理请求: {}", request.getRequestURI());
String requestURI = request.getRequestURI();
logger.info("JWT过滤器处理请求: {}", requestURI);
// 定义不需要JWT验证的路径
String[] publicPaths = {
"/api/auth/login",
"/api/auth/login/email",
"/api/auth/register",
"/api/verification/",
"/api/public/",
"/api/email/",
"/api/payments/alipay/notify",
"/api/payments/alipay/return",
"/swagger-ui",
"/v3/api-docs",
"/api-docs"
};
// 检查是否是公开路径
boolean isPublicPath = false;
for (String publicPath : publicPaths) {
if (requestURI.contains(publicPath)) {
isPublicPath = true;
logger.info("JWT过滤器: 跳过公开路径 {}", requestURI);
break;
}
}
// 如果是公开路径直接放行不进行JWT验证
if (isPublicPath) {
filterChain.doFilter(request, response);
return;
}
try {
String authHeader = request.getHeader("Authorization");
logger.debug("Authorization头: {}", authHeader);
String token = jwtUtils.extractTokenFromHeader(authHeader);
logger.debug("提取的token: {}", token != null ? "存在" : "不存在");
if (token != null && !token.equals("null") && !token.trim().isEmpty()) {
String username = jwtUtils.getUsernameFromToken(token);
logger.debug("从token获取用户名: {}", username);
if (username != null && jwtUtils.validateToken(token, username)) {
logger.info("JWT认证 - 从token获取的用户名: '{}'", username);
User user = userService.findByUsername(username);
logger.info("JWT认证 - 数据库查找结果: {}", user != null ? "找到用户 '" + user.getUsername() + "'" : "未找到用户");
if (user != null) {
// 创建用户权限列表
List<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority(user.getRole()));
// 将User对象作为Principal而不是用户名字符串
UsernamePasswordAuthenticationToken authToken =
new UsernamePasswordAuthenticationToken(user, null, authorities);
// 使用用户名字符串作为Principal而不是User对象
// 这样 authentication.getName() 会返回用户名字符串
UsernamePasswordAuthenticationToken authToken =
new UsernamePasswordAuthenticationToken(user.getUsername(), null, authorities);
authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authToken);
logger.debug("JWT认证成功用户: {}, 角色: {}", username, user.getRole());

View File

@@ -44,6 +44,10 @@ public class PlainTextPasswordEncoder implements PasswordEncoder {

View File

@@ -22,8 +22,13 @@ public class UserDetailsServiceImpl implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("用户不存在: " + username));
// 支持通过用户名或邮箱登录:先按用户名查找,找不到时按邮箱查找
java.util.Optional<com.example.demo.model.User> opt = userRepository.findByUsername(username);
if (opt.isEmpty()) {
opt = userRepository.findByEmail(username);
}
User user = opt.orElseThrow(() -> new UsernameNotFoundException("用户不存在: " + username));
return new org.springframework.security.core.userdetails.User(
user.getUsername(),

View File

@@ -22,13 +22,31 @@ public class ApiResponseHandler {
private static final Logger logger = LoggerFactory.getLogger(ApiResponseHandler.class);
private final ObjectMapper objectMapper;
private static boolean unirestConfigured = false;
public ApiResponseHandler() {
this.objectMapper = new ObjectMapper();
// 设置Unirest超时配置 - 修复HTTP客户端协议异常
Unirest.config()
.connectTimeout(30000) // 30秒连接超时
.socketTimeout(300000); // 5分钟读取超时
// 只配置一次Unirest
configureUnirest();
}
/**
* 配置Unirest - 使用同步锁确保只配置一次
*/
private synchronized void configureUnirest() {
if (!unirestConfigured) {
try {
// 设置Unirest超时配置
Unirest.config()
.connectTimeout(30000) // 30秒连接超时
.socketTimeout(300000); // 5分钟读取超时
unirestConfigured = true;
logger.info("Unirest配置完成");
} catch (Exception e) {
// 如果配置失败(例如已经配置过),则忽略错误
logger.warn("Unirest配置异常可能已经配置过: {}", e.getMessage());
}
}
}
/**

View File

@@ -49,6 +49,7 @@ public class ImageToVideoService {
@Value("${app.video.output.path:/outputs}")
private String outputPath;
/**
* 创建图生视频任务
*/
@@ -395,27 +396,41 @@ public class ImageToVideoService {
* 保存图片文件
*/
private String saveImage(MultipartFile file, String taskId, String type) throws IOException {
// 确保上传目录存在
Path uploadDir = Paths.get(uploadPath);
// 解析上传目录:如果配置的是相对路径,则相对于应用当前工作目录
Path uploadDir = Paths.get(uploadPath == null ? "uploads" : uploadPath);
if (!uploadDir.isAbsolute()) {
uploadDir = Paths.get(System.getProperty("user.dir")).resolve(uploadDir).toAbsolutePath().normalize();
}
// 确保上传目录存在(创建所有父目录)
if (!Files.exists(uploadDir)) {
Files.createDirectories(uploadDir);
}
// 创建任务目录
Path taskDir = uploadDir.resolve(taskId);
Files.createDirectories(taskDir);
if (!Files.exists(taskDir)) {
Files.createDirectories(taskDir);
}
// 生成文件名
String originalFilename = file.getOriginalFilename();
String extension = getFileExtension(originalFilename);
String filename = type + "_" + System.currentTimeMillis() + extension;
// 保存文件
// 保存文件(覆盖同名文件的行为由 Files.copy 决定,此处不启用 REPLACE_EXISTING
Path filePath = taskDir.resolve(filename);
Files.copy(file.getInputStream(), filePath);
// 返回相对路径,确保路径格式正确
return uploadPath + "/" + taskId + "/" + filename;
try {
Files.copy(file.getInputStream(), filePath);
} catch (IOException e) {
logger.error("保存上传图片失败: uploadDir={}, taskId={}, fileName={}", uploadDir, taskId, filename, e);
throw e;
}
// 返回前端可访问的相对URL由 WebMvcConfig 映射 /uploads/** -> upload 目录)
// 确保使用统一的URL前缀 /uploads
String urlPath = "/uploads/" + taskId + "/" + filename;
return urlPath;
}
/**

View File

@@ -207,27 +207,27 @@ public class RealAIService {
int retryAttempt = 0; // 重试次数计数器
while (retryCount < maxRetries) {
try {
// 根据参数选择可用的模型
String modelName = selectAvailableImageToVideoModel(aspectRatio, duration, hdMode);
try {
// 根据参数选择可用的模型
String modelName = selectAvailableImageToVideoModel(aspectRatio, duration, hdMode);
// 验证base64数据格式提取纯Base64数据用于验证
String base64DataForValidation = imageBase64;
if (imageBase64.contains(",")) {
if (imageBase64.contains(",")) {
base64DataForValidation = imageBase64.substring(imageBase64.indexOf(",") + 1);
}
try {
}
try {
Base64.getDecoder().decode(base64DataForValidation);
logger.debug("Base64数据格式验证通过");
} catch (IllegalArgumentException e) {
logger.error("Base64数据格式错误: {}", e.getMessage());
throw new RuntimeException("图片数据格式错误");
}
// 根据分辨率选择size参数用于日志记录
String size = convertAspectRatioToSize(aspectRatio, hdMode);
logger.debug("选择的尺寸参数: {}", size);
logger.debug("Base64数据格式验证通过");
} catch (IllegalArgumentException e) {
logger.error("Base64数据格式错误: {}", e.getMessage());
throw new RuntimeException("图片数据格式错误");
}
// 根据分辨率选择size参数用于日志记录
String size = convertAspectRatioToSize(aspectRatio, hdMode);
logger.debug("选择的尺寸参数: {}", size);
// 使用 Sora2 端点(与文生视频使用相同的端点,参考 Comfly.py 6297 行)
String url = aiApiBaseUrl + "/v2/videos/generations";
@@ -273,35 +273,35 @@ public class RealAIService {
// 使用流式传输,避免一次性加载整个请求体到内存
// 添加额外的请求头以支持大请求体
HttpResponse<String> response = Unirest.post(url)
.header("Authorization", "Bearer " + aiApiKey)
HttpResponse<String> response = Unirest.post(url)
.header("Authorization", "Bearer " + aiApiKey)
.header("Content-Type", "application/json; charset=UTF-8")
.header("Accept", "application/json")
.header("Connection", "keep-alive")
.body(requestBody)
.asString();
.body(requestBody)
.asString();
// 添加响应调试日志
logger.info("API响应状态: {}", response.getStatus());
String responseBodyStr = response.getBody();
logger.info("API响应内容前500字符: {}", responseBodyStr != null && responseBodyStr.length() > 500 ?
responseBodyStr.substring(0, 500) : responseBodyStr);
// 添加响应调试日志
logger.info("API响应状态: {}", response.getStatus());
String responseBodyStr = response.getBody();
logger.info("API响应内容前500字符: {}", responseBodyStr != null && responseBodyStr.length() > 500 ?
responseBodyStr.substring(0, 500) : responseBodyStr);
if (response.getStatus() == 200 && responseBodyStr != null) {
// 检查响应是否为HTML可能是认证失败或API端点错误
String trimmedResponse = responseBodyStr.trim();
String lowerResponse = trimmedResponse.toLowerCase();
if (lowerResponse.startsWith("<!") || lowerResponse.startsWith("<html") ||
lowerResponse.contains("<!doctype") || (!trimmedResponse.startsWith("{") && !trimmedResponse.startsWith("["))) {
logger.error("API返回HTML页面而不是JSON可能是认证失败或API端点错误");
logger.error("响应前100字符: {}", trimmedResponse.length() > 100 ? trimmedResponse.substring(0, 100) : trimmedResponse);
logger.error("请检查1) API密钥是否正确 2) API端点URL是否正确 3) API服务是否正常运行");
throw new RuntimeException("API返回HTML页面可能是认证失败。请检查API密钥和端点配置");
}
try {
@SuppressWarnings("unchecked")
Map<String, Object> responseBody = objectMapper.readValue(responseBodyStr, Map.class);
if (response.getStatus() == 200 && responseBodyStr != null) {
// 检查响应是否为HTML可能是认证失败或API端点错误
String trimmedResponse = responseBodyStr.trim();
String lowerResponse = trimmedResponse.toLowerCase();
if (lowerResponse.startsWith("<!") || lowerResponse.startsWith("<html") ||
lowerResponse.contains("<!doctype") || (!trimmedResponse.startsWith("{") && !trimmedResponse.startsWith("["))) {
logger.error("API返回HTML页面而不是JSON可能是认证失败或API端点错误");
logger.error("响应前100字符: {}", trimmedResponse.length() > 100 ? trimmedResponse.substring(0, 100) : trimmedResponse);
logger.error("请检查1) API密钥是否正确 2) API端点URL是否正确 3) API服务是否正常运行");
throw new RuntimeException("API返回HTML页面可能是认证失败。请检查API密钥和端点配置");
}
try {
@SuppressWarnings("unchecked")
Map<String, Object> responseBody = objectMapper.readValue(responseBodyStr, Map.class);
// Sora2 API 使用 task_id 字段表示成功(与文生视频相同格式)
if (responseBody.containsKey("task_id")) {
@@ -312,7 +312,7 @@ public class RealAIService {
result.put("data", responseBody);
result.put("task_id", responseBody.get("task_id"));
return result;
} else {
} else {
// 处理错误响应
logger.error("图生视频任务提交失败响应中缺少task_id: {}", responseBody);
String errorMsg = "未知错误";
@@ -320,19 +320,19 @@ public class RealAIService {
errorMsg = responseBody.get("message").toString();
}
throw new RuntimeException("任务提交失败: " + errorMsg);
}
} catch (com.fasterxml.jackson.core.JsonParseException e) {
logger.error("解析API响应为JSON失败响应内容可能是HTML或其他格式", e);
logger.error("响应内容前200字符: {}", responseBodyStr.length() > 200 ?
responseBodyStr.substring(0, 200) : responseBodyStr);
throw new RuntimeException("API返回非JSON响应可能是认证失败。请检查API密钥和端点配置");
}
} else {
logger.error("图生视频任务提交失败HTTP状态: {}", response.getStatus());
throw new RuntimeException("任务提交失败HTTP状态: " + response.getStatus());
} catch (com.fasterxml.jackson.core.JsonParseException e) {
logger.error("解析API响应为JSON失败响应内容可能是HTML或其他格式", e);
logger.error("响应内容前200字符: {}", responseBodyStr.length() > 200 ?
responseBodyStr.substring(0, 200) : responseBodyStr);
throw new RuntimeException("API返回非JSON响应可能是认证失败。请检查API密钥和端点配置");
}
} else {
logger.error("图生视频任务提交失败HTTP状态: {}", response.getStatus());
throw new RuntimeException("任务提交失败HTTP状态: " + response.getStatus());
}
} catch (UnirestException e) {
} catch (UnirestException e) {
retryCount++;
retryAttempt++;
Throwable cause = e.getCause();
@@ -391,11 +391,11 @@ public class RealAIService {
logger.error("建议: 1) 检查网络连接 2) 检查请求体大小是否过大 3) 联系API服务提供商检查服务器状态");
throw new RuntimeException("提交任务失败: " + errorMessage, e);
}
} catch (Exception e) {
} catch (Exception e) {
// 其他不可重试的错误直接抛出
logger.error("提交图生视频任务异常", e);
logger.error("提交图生视频任务异常", e);
throw new RuntimeException("提交任务失败: " + e.getMessage(), e);
}
}
}
// 理论上不会到达这里,但为了编译通过
@@ -728,7 +728,7 @@ public class RealAIService {
logger.debug("验证图片格式完成,原始数量: {}, 验证后数量: {}", images.size(), validatedImages.size());
return validatedImages;
}
/**
* 将图片文件转换为Base64
*/

View File

@@ -33,6 +33,7 @@ import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import com.example.demo.model.StoryboardVideoTask;
import com.example.demo.model.TaskStatus;
import com.example.demo.repository.StoryboardVideoTaskRepository;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -56,7 +57,16 @@ public class StoryboardVideoService {
@Autowired
private TaskQueueService taskQueueService;
@Autowired
private UserWorkService userWorkService;
@Autowired
private UserService userService;
@Autowired
private TaskStatusPollingService taskStatusPollingService;
@Autowired
private ApplicationContext applicationContext;
@@ -352,6 +362,45 @@ public class StoryboardVideoService {
task.updateStatus(StoryboardVideoTask.TaskStatus.PROCESSING);
taskRepository.save(task);
logger.info("任务状态已更新为处理中: {}", taskId);
// 创建 TaskStatus 记录用于跟踪分镜图生成状态
try {
// 分镜图生成是同步的,不需要 externalTaskId
TaskStatus taskStatus = taskStatusPollingService.createTaskStatus(
taskId,
task.getUsername(),
TaskStatus.TaskType.STORYBOARD_VIDEO,
null // 分镜图生成是同步API不需要外部任务ID
);
logger.info("TaskStatus 记录已创建: taskId={}, status={}", taskId, taskStatus.getStatus());
} catch (Exception e) {
logger.error("创建 TaskStatus 记录失败: {}", taskId, e);
// 不抛出异常,避免影响主流程
}
// 创建初始的 UserWork 记录PROCESSING状态以便前端可以恢复任务
try {
// 检查是否已存在 UserWork
if (!userWorkService.getWorkByTaskId(taskId).isPresent()) {
com.example.demo.model.UserWork work = new com.example.demo.model.UserWork();
work.setUserId(getUserIdByUsername(task.getUsername()));
work.setUsername(task.getUsername());
work.setTaskId(taskId);
work.setWorkType(com.example.demo.model.UserWork.WorkType.STORYBOARD_VIDEO);
work.setTitle(generateTitle(task.getPrompt()));
work.setDescription("分镜视频生成中");
work.setPrompt(task.getPrompt());
work.setAspectRatio(task.getAspectRatio());
work.setQuality(task.isHdMode() ? "HD" : "SD");
work.setPointsCost(0); // 任务进行中,暂时不计算积分
work.setStatus(com.example.demo.model.UserWork.WorkStatus.PROCESSING);
userWorkService.createWork(work);
logger.info("初始UserWork记录已创建: taskId={}", taskId);
}
} catch (Exception e) {
logger.error("创建初始UserWork记录失败: {}", taskId, e);
// 不抛出异常,避免影响主流程
}
} catch (Exception e) {
logger.error("更新任务状态失败: {}", taskId, e);
status.setRollbackOnly();
@@ -376,6 +425,20 @@ public class StoryboardVideoService {
task.updateProgress(50); // 分镜图生成完成进度50%
taskRepository.save(task);
logger.debug("分镜图结果已保存: taskId={}, 图片数量={}", taskId, validatedImageCount);
// 更新 TaskStatus 为完成状态
try {
TaskStatus taskStatus = taskStatusPollingService.getTaskStatus(taskId);
if (taskStatus != null) {
taskStatus.markAsCompleted(mergedImageUrl);
taskStatus.setProgress(50); // 分镜图完成进度50%
taskStatusPollingService.saveOrUpdateTaskStatus(taskStatus);
logger.info("TaskStatus 已更新为完成: taskId={}", taskId);
}
} catch (Exception e) {
logger.error("更新 TaskStatus 为完成失败: {}", taskId, e);
// 不抛出异常,避免影响主流程
}
} catch (Exception e) {
logger.error("保存分镜图结果失败: {}", taskId, e);
status.setRollbackOnly();
@@ -396,6 +459,19 @@ public class StoryboardVideoService {
task.updateStatus(StoryboardVideoTask.TaskStatus.FAILED);
task.setErrorMessage(errorMessage);
taskRepository.save(task);
// 更新 TaskStatus 为失败状态
try {
TaskStatus taskStatus = taskStatusPollingService.getTaskStatus(taskId);
if (taskStatus != null) {
taskStatus.markAsFailed(errorMessage);
taskStatusPollingService.saveOrUpdateTaskStatus(taskStatus);
logger.info("TaskStatus 已更新为失败: taskId={}", taskId);
}
} catch (Exception e) {
logger.error("更新 TaskStatus 为失败失败: {}", taskId, e);
// 不抛出异常,避免影响主流程
}
} catch (Exception e) {
logger.error("更新任务失败状态失败: {}", taskId, e);
status.setRollbackOnly();
@@ -441,6 +517,15 @@ public class StoryboardVideoService {
// 状态保持 PROCESSING等待用户点击"开始生成"按钮后再生成视频
taskRepository.save(task);
logger.debug("分镜图结果已保存: taskId={}, 图片数量={}", taskId, validatedImageCount);
// 创建分镜图作品记录
try {
userWorkService.createStoryboardImageWork(taskId, mergedImageUrl);
logger.info("分镜图作品记录已创建: taskId={}", taskId);
} catch (Exception e) {
logger.error("创建分镜图作品记录失败: taskId={}", taskId, e);
// 不抛出异常,避免影响主流程
}
}
/**
@@ -864,14 +949,47 @@ public class StoryboardVideoService {
}
if (handledCount > 0 || skippedCount > 0) {
logger.info("处理超时分镜图生成任务完成,失败: {}/{},跳过(已生成): {}",
logger.info("处理超时分镜图生成任务完成,失败: {}/{},跳过(已生成): {}",
handledCount, timeoutTasks.size(), skippedCount);
}
return handledCount;
} catch (Exception e) {
logger.error("检查超时分镜图生成任务失败", e);
return 0;
}
}
/**
* 根据用户名获取用户ID
*/
private Long getUserIdByUsername(String username) {
try {
com.example.demo.model.User user = userService.findByUsername(username);
if (user != null) {
return user.getId();
}
logger.warn("找不到用户: {}", username);
return null;
} catch (Exception e) {
logger.error("获取用户ID失败: {}", username, e);
return null;
}
}
/**
* 生成作品标题
*/
private String generateTitle(String prompt) {
if (prompt == null || prompt.trim().isEmpty()) {
return "未命名作品";
}
// 取提示词的前20个字符作为标题
String title = prompt.trim();
if (title.length() > 20) {
title = title.substring(0, 20) + "...";
}
return title;
}
}

View File

@@ -1,11 +1,5 @@
package com.example.demo.service;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
@@ -77,6 +71,9 @@ public class TaskQueueService {
@Autowired
private VideoConcatService videoConcatService;
@Autowired
private ImageGridService imageGridService;
@org.springframework.beans.factory.annotation.Value("${app.temp.dir:./temp}")
private String tempDir;
@@ -258,7 +255,7 @@ public class TaskQueueService {
// 创建新的队列任务
TaskQueue taskQueue = new TaskQueue(username, taskId, taskType);
taskQueue = taskQueueRepository.save(taskQueue);
// 添加到内存阻塞队列非阻塞如果队列满会立即返回false但无界队列不会满
boolean added = taskBlockingQueue.offer(taskQueue);
if (added) {
@@ -446,7 +443,7 @@ public class TaskQueueService {
// 更新状态为处理中
taskQueue.updateStatus(TaskQueue.QueueStatus.PROCESSING);
taskQueueRepository.save(taskQueue);
taskQueueRepository.save(taskQueue);
logger.debug("任务 {} 状态已更新为PROCESSING使用悲观锁", taskId);
return Boolean.TRUE;
} catch (jakarta.persistence.NoResultException e) {
@@ -509,7 +506,7 @@ public class TaskQueueService {
task.isHdMode()
);
}
/**
* 使用只读事务获取文生视频任务(快速完成,避免连接泄漏)
*/
@@ -556,15 +553,14 @@ public class TaskQueueService {
/**
* 处理分镜视频任务
* 使用分镜图Base64调用 sora2 生成视频
* 将6张分镜图拼接成一张图片然后调用图生视频接口生成视频
* 使用只读事务快速查询任务信息
*/
private Map<String, Object> processStoryboardVideoTask(TaskQueue taskQueue) {
// 使用只读事务快速查询任务信息
StoryboardVideoTask task = getStoryboardVideoTaskWithTransaction(taskQueue.getTaskId());
// 参考sora2实现优先使用单独的分镜图片数组参考Comfly.py 6272-6278行
// 如果存在单独的分镜图片,使用它们;否则回退到网格图
// 获取6张分镜图片
List<String> images = null;
String storyboardImagesJson = task.getStoryboardImages();
@@ -577,10 +573,10 @@ public class TaskQueueService {
);
if (parsedImages != null && !parsedImages.isEmpty()) {
images = parsedImages;
logger.info("使用单独的分镜图片生成视频,图片数量: {}", images.size());
logger.info("获取到分镜图片,数量: {}", images.size());
}
} catch (Exception e) {
logger.warn("解析分镜图片JSON失败,回退到网格图: {}", e.getMessage());
logger.warn("解析分镜图片JSON失败: {}", e.getMessage());
}
}
@@ -590,80 +586,90 @@ public class TaskQueueService {
if (imageBase64 == null || imageBase64.isEmpty()) {
throw new RuntimeException("分镜图未生成,无法生成视频");
}
// 将网格图转换为单元素数组参考sora2实现
images = new java.util.ArrayList<>();
images.add(imageBase64);
// 如果只有网格图,直接使用(已经是拼接后的图片
logger.info("使用网格图生成视频(向后兼容)");
}
// 使用 sora2 生成视频(使用默认时长,每张图片单独生成)
// 每张图片的时长:总时长 / 图片数量但最少2秒
int totalDuration = 10; // 总时长10秒
int perImageDuration = Math.max(2, totalDuration / images.size()); // 每张图片至少2秒
String duration = String.valueOf(perImageDuration);
logger.info("开始为每张图片单独提交视频任务,图片数量: {}, 每张图片时长: {}秒", images.size(), duration);
// 为每张图片单独提交视频任务
List<String> videoTaskIds = new java.util.ArrayList<>();
for (int i = 0; i < images.size(); i++) {
String image = images.get(i);
try {
// 为单张图片提交视频任务(使用单元素列表)
List<String> singleImageList = new java.util.ArrayList<>();
singleImageList.add(image);
Map<String, Object> result = realAIService.submitStoryboardVideoTask(
task.getPrompt(),
singleImageList,
task.getAspectRatio(),
duration,
task.isHdMode()
);
if (result != null && result.containsKey("task_id")) {
String videoTaskId = result.get("task_id").toString();
videoTaskIds.add(videoTaskId);
logger.info("图片 {} 的视频任务提交成功task_id: {}", i + 1, videoTaskId);
} else {
logger.error("图片 {} 的视频任务提交失败未返回task_id", i + 1);
throw new RuntimeException("图片 " + (i + 1) + " 的视频任务提交失败");
}
} catch (Exception e) {
logger.error("为图片 {} 提交视频任务失败: {}", i + 1, e.getMessage(), e);
throw new RuntimeException("为图片 " + (i + 1) + " 提交视频任务失败: " + e.getMessage(), e);
// 直接使用网格图调用图生视频接口
Map<String, Object> result = realAIService.submitImageToVideoTask(
task.getPrompt(),
imageBase64,
task.getAspectRatio(),
"10", // 默认10秒
task.isHdMode()
);
if (result != null && result.containsKey("task_id")) {
String videoTaskId = result.get("task_id").toString();
// 保存视频任务ID到数据库
saveVideoTaskId(taskQueue.getTaskId(), videoTaskId);
logger.info("分镜视频任务提交成功task_id: {}", videoTaskId);
return result;
} else {
throw new RuntimeException("图生视频任务提交失败未返回task_id");
}
}
// 保存所有视频任务ID到数据库
// 确保有6张图片
if (images.size() < 6) {
throw new RuntimeException("分镜图片数量不足需要6张当前只有" + images.size() + "");
}
// 只取前6张图片
if (images.size() > 6) {
logger.warn("分镜图片数量超过6张只取前6张进行拼接");
images = images.subList(0, 6);
}
logger.info("开始将6张分镜图拼接成一张图片...");
// 将6张图片拼接成一张图片
String mergedImageBase64;
try {
mergedImageBase64 = imageGridService.mergeImagesToGrid(images, 3); // 3列2行布局
logger.info("6张分镜图拼接完成");
} catch (Exception e) {
logger.error("拼接分镜图失败: {}", e.getMessage(), e);
throw new RuntimeException("拼接分镜图失败: " + e.getMessage(), e);
}
// 使用拼接后的图片调用图生视频接口
logger.info("使用拼接后的图片调用图生视频接口...");
Map<String, Object> result = realAIService.submitImageToVideoTask(
task.getPrompt(),
mergedImageBase64,
task.getAspectRatio(),
"10", // 默认10秒
task.isHdMode()
);
if (result != null && result.containsKey("task_id")) {
String videoTaskId = result.get("task_id").toString();
// 保存视频任务ID到数据库
saveVideoTaskId(taskQueue.getTaskId(), videoTaskId);
logger.info("分镜视频任务提交成功task_id: {}", videoTaskId);
return result;
} else {
throw new RuntimeException("图生视频任务提交失败未返回task_id");
}
}
/**
* 保存视频任务ID到数据库
*/
private void saveVideoTaskId(String taskId, String videoTaskId) {
try {
String videoTaskIdsJson = objectMapper.writeValueAsString(videoTaskIds);
// 使用事务模板保存
transactionTemplate.executeWithoutResult(status -> {
StoryboardVideoTask currentTask = storyboardVideoTaskRepository.findByTaskId(taskQueue.getTaskId())
.orElseThrow(() -> new RuntimeException("任务不存在: " + taskQueue.getTaskId()));
currentTask.setVideoTaskIds(videoTaskIdsJson);
StoryboardVideoTask currentTask = storyboardVideoTaskRepository.findByTaskId(taskId)
.orElseThrow(() -> new RuntimeException("任务不存在: " + taskId));
// 保存为单个任务ID不再使用videoTaskIds数组)
currentTask.setRealTaskId(videoTaskId);
storyboardVideoTaskRepository.save(currentTask);
logger.info("已保存{}个视频任务ID到数据库", videoTaskIds.size());
logger.info("已保存视频任务ID到数据库: {}", videoTaskId);
});
} catch (Exception e) {
logger.error("保存视频任务ID失败: {}", e.getMessage(), e);
// 不抛出异常,因为任务已经提交成功
}
// 返回第一个任务ID用于兼容现有逻辑
Map<String, Object> result = new java.util.HashMap<>();
result.put("code", 200);
result.put("task_id", videoTaskIds.isEmpty() ? null : videoTaskIds.get(0));
result.put("video_task_ids", videoTaskIds); // 包含所有任务ID
result.put("data", new java.util.HashMap<String, Object>() {{
put("task_id", videoTaskIds.isEmpty() ? null : videoTaskIds.get(0));
}});
logger.info("所有视频任务提交完成,共{}个任务第一个任务ID: {}",
videoTaskIds.size(), videoTaskIds.isEmpty() ? "" : videoTaskIds.get(0));
return result;
}
/**
@@ -835,6 +841,15 @@ public class TaskQueueService {
public List<TaskQueue> getTasksToCheck() {
return taskQueueRepository.findTasksToCheck();
}
/**
* 检查是否有待处理的任务(快速检查,只统计数量)
* @return true 如果有待处理任务false 否则
*/
@Transactional(readOnly = true)
public boolean hasTasksToCheck() {
return taskQueueRepository.countTasksToCheck() > 0;
}
/**
* 检查单个任务状态 - 公共方法
@@ -859,7 +874,7 @@ public class TaskQueueService {
logger.debug("任务 {} 正在被其他线程查询,跳过本次查询", taskId);
return;
}
try {
// 特殊处理:分镜视频任务需要检查多个视频任务
if (taskQueue.getTaskType() == TaskQueue.TaskType.STORYBOARD_VIDEO) {
@@ -870,7 +885,7 @@ public class TaskQueueService {
if (taskQueue.getRealTaskId() == null) {
return;
}
// 查询外部API状态
Map<String, Object> statusResponse = realAIService.getTaskStatus(taskQueue.getRealTaskId());
@@ -947,12 +962,12 @@ public class TaskQueueService {
// 2. 检查嵌套的data.data.task_result.videos[0].urlKling API嵌套格式
if (resultUrl == null) {
Object nestedData = taskData.get("data");
if (nestedData instanceof Map) {
Map<?, ?> nestedDataMap = (Map<?, ?>) nestedData;
Object innerData = nestedDataMap.get("data");
if (innerData instanceof Map) {
Map<?, ?> innerDataMap = (Map<?, ?>) innerData;
Object nestedData = taskData.get("data");
if (nestedData instanceof Map) {
Map<?, ?> nestedDataMap = (Map<?, ?>) nestedData;
Object innerData = nestedDataMap.get("data");
if (innerData instanceof Map) {
Map<?, ?> innerDataMap = (Map<?, ?>) innerData;
// 检查 task_result.videos[0].url
Object taskResult = innerDataMap.get("task_result");
@@ -973,17 +988,17 @@ public class TaskQueueService {
// 如果上面没找到检查output字段
if (resultUrl == null) {
Object output = innerDataMap.get("output");
if (output != null) {
resultUrl = output.toString();
Object output = innerDataMap.get("output");
if (output != null) {
resultUrl = output.toString();
}
}
}
// 如果深层嵌套没有找到检查当前层的output
if (resultUrl == null) {
Object output = nestedDataMap.get("output");
if (output != null) {
resultUrl = output.toString();
}
// 如果深层嵌套没有找到检查当前层的output
if (resultUrl == null) {
Object output = nestedDataMap.get("output");
if (output != null) {
resultUrl = output.toString();
}
}
}
@@ -1070,8 +1085,9 @@ public class TaskQueueService {
}
/**
* 检查分镜视频任务的多个视频任务状态
* 当所有视频任务完成后,下载并拼接视频
* 检查分镜视频任务状态
* 优化现在只生成一个视频任务将6张分镜图拼接后调用图生视频接口
* 不再需要视频拼接逻辑
*/
@Transactional(propagation = Propagation.NOT_SUPPORTED)
private void checkStoryboardVideoTasks(TaskQueue taskQueue) {
@@ -1083,229 +1099,22 @@ public class TaskQueueService {
return;
}
// 获取所有视频任务ID
String videoTaskIdsJson = storyboardTask.getVideoTaskIds();
if (videoTaskIdsJson == null || videoTaskIdsJson.isEmpty()) {
// 如果没有视频任务ID使用旧的realTaskId(向后兼容)
if (taskQueue.getRealTaskId() != null) {
// 使用旧的单任务逻辑
checkTaskStatusInternalForSingleTask(taskQueue);
}
return;
}
// 解析视频任务ID列表
List<String> videoTaskIds;
try {
videoTaskIds = objectMapper.readValue(
videoTaskIdsJson,
objectMapper.getTypeFactory().constructCollectionType(List.class, String.class)
);
} catch (Exception e) {
logger.error("解析视频任务ID失败: {}", taskQueue.getTaskId(), e);
return;
}
if (videoTaskIds == null || videoTaskIds.isEmpty()) {
logger.warn("视频任务ID列表为空: {}", taskQueue.getTaskId());
return;
}
logger.debug("检查分镜视频任务的{}个视频任务状态: {}", videoTaskIds.size(), taskQueue.getTaskId());
// 检查所有视频任务状态
List<String> completedVideoUrls = new java.util.ArrayList<>();
boolean allCompleted = true;
boolean hasFailed = false;
for (String videoTaskId : videoTaskIds) {
try {
Map<String, Object> statusResponse = realAIService.getTaskStatus(videoTaskId);
if (statusResponse == null || !statusResponse.containsKey("data")) {
allCompleted = false;
continue;
}
Object data = statusResponse.get("data");
Map<?, ?> taskData = null;
if (data instanceof Map) {
taskData = (Map<?, ?>) data;
} else if (data instanceof List) {
List<?> dataList = (List<?>) data;
if (!dataList.isEmpty() && dataList.get(0) instanceof Map) {
taskData = (Map<?, ?>) dataList.get(0);
}
}
if (taskData != null) {
String status = taskData.get("status") != null ?
taskData.get("status").toString().toUpperCase() : "";
String videoUrl = extractVideoUrl(taskData);
if ("COMPLETED".equals(status) || "SUCCESS".equals(status) ||
(videoUrl != null && !videoUrl.trim().isEmpty() && !videoUrl.equals("null"))) {
if (videoUrl != null && !videoUrl.trim().isEmpty() && !videoUrl.equals("null")) {
completedVideoUrls.add(videoUrl);
logger.debug("视频任务 {} 已完成URL: {}", videoTaskId, videoUrl.length() > 50 ? videoUrl.substring(0, 50) + "..." : videoUrl);
} else {
allCompleted = false;
logger.debug("视频任务 {} 状态为完成但无URL", videoTaskId);
}
} else if ("FAILED".equals(status) || "ERROR".equals(status)) {
hasFailed = true;
logger.warn("视频任务 {} 失败", videoTaskId);
} else {
allCompleted = false;
logger.debug("视频任务 {} 仍在处理中,状态: {}", videoTaskId, status);
}
} else {
allCompleted = false;
}
} catch (Exception e) {
logger.error("检查视频任务状态失败: {}", videoTaskId, e);
allCompleted = false;
}
}
// 如果所有视频都完成了,下载并拼接
if (allCompleted && completedVideoUrls.size() == videoTaskIds.size() && !hasFailed) {
logger.info("所有视频任务已完成,开始下载并拼接: {} 个视频", completedVideoUrls.size());
// 检查是否有视频URL
if (completedVideoUrls.isEmpty()) {
logger.error("所有视频任务完成但没有视频URL");
updateTaskAsFailed(taskQueue, "所有视频任务完成但没有视频URL");
return;
}
// 保存所有视频URL到数据库
try {
String videoUrlsJson = objectMapper.writeValueAsString(completedVideoUrls);
transactionTemplate.executeWithoutResult(status -> {
StoryboardVideoTask currentTask = storyboardVideoTaskRepository.findByTaskId(taskQueue.getTaskId())
.orElseThrow(() -> new RuntimeException("任务不存在: " + taskQueue.getTaskId()));
currentTask.setVideoUrls(videoUrlsJson);
storyboardVideoTaskRepository.save(currentTask);
});
} catch (Exception e) {
logger.error("保存视频URL失败: {}", taskQueue.getTaskId(), e);
}
// 尝试下载并拼接视频
String finalVideoUrl = null;
try {
// 检查FFmpeg是否可用
if (!videoConcatService.isFFmpegAvailable()) {
String errorMsg = "FFmpeg不可用无法拼接视频。请确保FFmpeg已正确安装并配置";
logger.error("{}: taskId={}", errorMsg, taskQueue.getTaskId());
updateTaskAsFailed(taskQueue, errorMsg);
return;
}
// 创建临时输出文件路径
String tempOutputFileName = "storyboard_" + taskQueue.getTaskId() + "_" + System.currentTimeMillis() + ".mp4";
String outputPath = tempDir + File.separator + tempOutputFileName;
// 下载并拼接视频
boolean concatSuccess = videoConcatService.downloadAndConcatVideos(completedVideoUrls, outputPath);
if (concatSuccess && new java.io.File(outputPath).exists()) {
// 保存拼接后的视频到可访问的位置
try {
// 处理上传路径:如果是相对路径,转换为绝对路径
Path uploadDirPath = Paths.get(uploadPath);
if (!uploadDirPath.isAbsolute()) {
// 相对路径:基于应用运行目录
uploadDirPath = Paths.get(System.getProperty("user.dir"), uploadPath);
}
// 确保上传目录存在
if (!Files.exists(uploadDirPath)) {
Files.createDirectories(uploadDirPath);
}
// 创建任务目录
String taskId = taskQueue.getTaskId();
Path taskDir = uploadDirPath.resolve("storyboard_videos").resolve(taskId);
Files.createDirectories(taskDir);
// 生成文件名
String outputFileName = "storyboard_" + taskId + "_" + System.currentTimeMillis() + ".mp4";
// 保存文件
Path sourcePath = Paths.get(outputPath);
Path targetPath = taskDir.resolve(outputFileName);
Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING);
// 生成可访问的URL相对路径通过静态资源服务访问
// 格式:/uploads/storyboard_videos/{taskId}/{filename}
// 注意URL路径始终使用正斜杠与操作系统无关
String relativePath = "uploads/storyboard_videos/" + taskId + "/" + outputFileName;
// 确保URL以 / 开头
if (!relativePath.startsWith("/")) {
relativePath = "/" + relativePath;
}
finalVideoUrl = relativePath;
logger.info("视频拼接成功,已保存到: {}", targetPath);
logger.info("视频访问URL: {}", finalVideoUrl);
// 清理临时文件
try {
Files.deleteIfExists(sourcePath);
logger.debug("已清理临时文件: {}", sourcePath);
} catch (IOException e) {
logger.warn("清理临时文件失败: {}", sourcePath, e);
}
} catch (IOException e) {
logger.error("保存拼接后的视频失败: {}", outputPath, e);
// 如果保存失败使用第一个视频URL作为备用方案
finalVideoUrl = completedVideoUrls.get(0);
logger.warn("使用第一个视频URL作为备用方案: {}", finalVideoUrl);
}
} else {
String errorMsg = "视频拼接失败FFmpeg执行失败或输出文件不存在";
logger.error("{}: taskId={}", errorMsg, taskQueue.getTaskId());
updateTaskAsFailed(taskQueue, errorMsg);
return;
}
} catch (OutOfMemoryError e) {
String errorMsg = "视频拼接失败内存不足。请增加JVM堆内存或减少视频数量";
logger.error("{}: taskId={}", errorMsg, taskQueue.getTaskId(), e);
updateTaskAsFailed(taskQueue, errorMsg);
return;
} catch (Exception e) {
String errorMsg = "视频拼接过程出错: " + e.getMessage();
logger.error("{}: taskId={}", errorMsg, taskQueue.getTaskId(), e);
updateTaskAsFailed(taskQueue, errorMsg);
return;
}
if (finalVideoUrl != null && !finalVideoUrl.isEmpty()) {
// 更新任务为完成状态
updateTaskAsCompleted(taskQueue, finalVideoUrl);
} else {
logger.error("无法获取最终视频URL");
updateTaskAsFailed(taskQueue, "视频拼接失败无法获取最终视频URL");
}
} else if (hasFailed) {
// 如果有任务失败,标记整个任务失败
String errorMessage = "部分视频任务生成失败";
updateTaskAsFailed(taskQueue, errorMessage);
// 使用realTaskId检查单个视频任务状态现在只有一个视频任务
String realTaskId = storyboardTask.getRealTaskId();
if (realTaskId == null || realTaskId.isEmpty()) {
// 向后兼容检查taskQueue的realTaskId
if (taskQueue.getRealTaskId() != null && !taskQueue.getRealTaskId().isEmpty()) {
realTaskId = taskQueue.getRealTaskId();
} else {
// 更新进度(基于已完成的视频数量)
if (!videoTaskIds.isEmpty()) {
int progress = (completedVideoUrls.size() * 100) / videoTaskIds.size();
transactionTemplate.executeWithoutResult(status -> {
StoryboardVideoTask currentTask = storyboardVideoTaskRepository.findByTaskId(taskQueue.getTaskId())
.orElseThrow(() -> new RuntimeException("任务不存在: " + taskQueue.getTaskId()));
currentTask.updateProgress(Math.min(100, progress + 50)); // 50%是分镜图生成剩余50%是视频生成
storyboardVideoTaskRepository.save(currentTask);
});
logger.warn("分镜视频任务没有realTaskId: {}", taskQueue.getTaskId());
return;
}
}
// 检查单个视频任务状态(使用图生视频任务的检查逻辑)
logger.debug("检查分镜视频任务状态: taskId={}, realTaskId={}", taskQueue.getTaskId(), realTaskId);
checkTaskStatusInternalForSingleTask(taskQueue);
// 增加检查次数
incrementCheckCountWithTransaction(taskQueue.getTaskId());
} catch (Exception e) {
@@ -1450,31 +1259,31 @@ public class TaskQueueService {
// 扣除冻结的积分(内部已处理重复扣除的情况)
try {
userService.deductFrozenPoints(taskQueue.getTaskId());
userService.deductFrozenPoints(taskQueue.getTaskId());
} catch (Exception e) {
logger.debug("扣除积分失败(可能已扣除): {}", taskQueue.getTaskId());
// 积分扣除失败不影响任务完成状态
}
// 更新原始任务状态
updateOriginalTaskStatus(taskQueue, "COMPLETED", resultUrl, null);
// 创建用户作品 - 在最后执行,避免影响主要流程
if (resultUrl != null && !resultUrl.isEmpty()) {
try {
// 更新原始任务状态
updateOriginalTaskStatus(taskQueue, "COMPLETED", resultUrl, null);
// 创建用户作品 - 在最后执行,避免影响主要流程
if (resultUrl != null && !resultUrl.isEmpty()) {
try {
userWorkService.createWorkFromTask(taskQueue.getTaskId(), resultUrl);
} catch (Exception workException) {
} catch (Exception workException) {
// 如果是重复创建异常,静默处理
if (workException.getMessage() == null ||
(!workException.getMessage().contains("已存在") &&
!workException.getMessage().contains("Duplicate entry"))) {
logger.warn("创建用户作品失败: {}", taskQueue.getTaskId());
}
// 作品创建失败不影响任务完成状态
}
}
} catch (Exception e) {
logger.error("更新任务完成状态失败: {}", taskQueue.getTaskId(), e);
// 作品创建失败不影响任务完成状态
}
}
} catch (Exception e) {
logger.error("更新任务完成状态失败: {}", taskQueue.getTaskId(), e);
status.setRollbackOnly();
throw e;
}
@@ -1493,18 +1302,18 @@ public class TaskQueueService {
try {
// 使用 TransactionTemplate 确保在事务中执行
transactionTemplate.executeWithoutResult(status -> {
try {
taskQueue.updateStatus(TaskQueue.QueueStatus.FAILED);
taskQueue.setErrorMessage(errorMessage);
taskQueueRepository.save(taskQueue);
try {
taskQueue.updateStatus(TaskQueue.QueueStatus.FAILED);
taskQueue.setErrorMessage(errorMessage);
taskQueueRepository.save(taskQueue);
// 返还冻结的积分
userService.returnFrozenPoints(taskQueue.getTaskId());
// 返还冻结的积分
userService.returnFrozenPoints(taskQueue.getTaskId());
// 更新原始任务状态
updateOriginalTaskStatus(taskQueue, "FAILED", null, errorMessage);
} catch (Exception e) {
logger.error("更新任务失败状态失败: {}", taskQueue.getTaskId(), e);
// 更新原始任务状态
updateOriginalTaskStatus(taskQueue, "FAILED", null, errorMessage);
} catch (Exception e) {
logger.error("更新任务失败状态失败: {}", taskQueue.getTaskId(), e);
status.setRollbackOnly();
throw e;
}
@@ -1523,18 +1332,18 @@ public class TaskQueueService {
try {
// 使用 TransactionTemplate 确保在事务中执行
transactionTemplate.executeWithoutResult(status -> {
try {
taskQueue.updateStatus(TaskQueue.QueueStatus.TIMEOUT);
taskQueue.setErrorMessage("任务处理超时");
taskQueueRepository.save(taskQueue);
try {
taskQueue.updateStatus(TaskQueue.QueueStatus.TIMEOUT);
taskQueue.setErrorMessage("任务处理超时");
taskQueueRepository.save(taskQueue);
// 返还冻结的积分
userService.returnFrozenPoints(taskQueue.getTaskId());
// 返还冻结的积分
userService.returnFrozenPoints(taskQueue.getTaskId());
// 更新原始任务状态
updateOriginalTaskStatus(taskQueue, "FAILED", null, "任务处理超时");
} catch (Exception e) {
logger.error("更新任务超时状态失败: {}", taskQueue.getTaskId(), e);
// 更新原始任务状态
updateOriginalTaskStatus(taskQueue, "FAILED", null, "任务处理超时");
} catch (Exception e) {
logger.error("更新任务超时状态失败: {}", taskQueue.getTaskId(), e);
status.setRollbackOnly();
throw e;
}
@@ -1623,7 +1432,7 @@ public class TaskQueueService {
storyboardVideoTaskRepository.save(task);
}
// 如果新的也是图片,保留原来的分镜图
} else {
} else {
// 当前不是分镜图,直接更新
task.setResultUrl(resultUrl);
storyboardVideoTaskRepository.save(task);

View File

@@ -7,7 +7,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@@ -38,24 +37,28 @@ public class TaskStatusPollingService {
private String apiBaseUrl;
/**
* 每2分钟执行一次轮询查询任务状态
* 固定间隔120000毫秒 = 2分钟
* (Scheduling disabled) 原先每2分钟执行一次轮询查询任务状态
* 注意:调度已集中到 `TaskQueueScheduler.checkTaskStatuses()`,以避免重复并发查询。
* 如果你更希望这个服务自己轮询,可以将 @Scheduled 注解恢复到此方法。
*/
@Scheduled(fixedRate = 120000) // 2分钟 = 120000毫秒
// @Scheduled(fixedRate = 120000) // 2分钟 = 120000毫秒
public void pollTaskStatuses() {
logger.info("=== 开始执行任务状态轮询查询 (每2分钟) ===");
try {
// 查找需要轮询的任务状态为PROCESSING且创建时间超过2分钟
LocalDateTime cutoffTime = LocalDateTime.now().minusMinutes(2);
List<TaskStatus> tasksToPoll = taskStatusRepository.findTasksNeedingPolling(cutoffTime);
logger.info("找到 {} 个需要轮询查询的任务", tasksToPoll.size());
if (tasksToPoll.isEmpty()) {
logger.debug("当前没有需要轮询的任务");
// 先做一次计数,避免在无任务时加载实体列表
long needCount = taskStatusRepository.countTasksNeedingPolling(cutoffTime);
logger.info("需要轮询查询的任务数量: {}", needCount);
if (needCount == 0) {
logger.debug("当前没有需要轮询的任务count=0");
return;
}
List<TaskStatus> tasksToPoll = taskStatusRepository.findTasksNeedingPolling(cutoffTime);
// 逐个轮询任务状态
for (TaskStatus task : tasksToPoll) {
@@ -223,19 +226,28 @@ public class TaskStatusPollingService {
@Transactional
public boolean cancelTask(String taskId, String username) {
TaskStatus task = taskStatusRepository.findByTaskId(taskId).orElse(null);
if (task == null || !task.getUsername().equals(username)) {
return false;
}
if (task.getStatus() == TaskStatus.Status.PROCESSING) {
task.setStatus(TaskStatus.Status.CANCELLED);
task.setUpdatedAt(LocalDateTime.now());
taskStatusRepository.save(task);
return true;
}
return false;
}
/**
* 保存或更新任务状态
*/
@Transactional
public TaskStatus saveOrUpdateTaskStatus(TaskStatus taskStatus) {
taskStatus.setUpdatedAt(LocalDateTime.now());
return taskStatusRepository.save(taskStatus);
}
}

View File

@@ -54,9 +54,6 @@ public class TextToVideoService {
if (prompt == null || prompt.trim().isEmpty()) {
throw new IllegalArgumentException("文本描述不能为空");
}
if (prompt.trim().length() > 1000) {
throw new IllegalArgumentException("文本描述不能超过1000个字符");
}
if (duration < 1 || duration > 60) {
throw new IllegalArgumentException("视频时长必须在1-60秒之间");
}

View File

@@ -174,6 +174,46 @@ public class UserWorkService {
return work;
}
/**
* 创建分镜图作品(从分镜视频任务的分镜图阶段)
*/
@Transactional
public UserWork createStoryboardImageWork(String taskId, String imageUrl) {
// 检查是否已存在分镜图作品(避免重复创建)
Optional<UserWork> existingWork = userWorkRepository.findByTaskId(taskId + "_image");
if (existingWork.isPresent()) {
logger.info("分镜图作品已存在,跳过创建: taskId={}, workId={}", taskId, existingWork.get().getId());
return existingWork.get();
}
// 获取分镜视频任务
Optional<StoryboardVideoTask> taskOpt = storyboardVideoTaskRepository.findByTaskId(taskId);
if (!taskOpt.isPresent()) {
throw new RuntimeException("找不到分镜视频任务: " + taskId);
}
StoryboardVideoTask task = taskOpt.get();
UserWork work = new UserWork();
work.setUserId(getUserIdByUsername(task.getUsername()));
work.setUsername(task.getUsername());
work.setTaskId(taskId + "_image"); // 添加后缀区分分镜图和视频
work.setWorkType(UserWork.WorkType.STORYBOARD_IMAGE);
work.setTitle(generateTitle(task.getPrompt()) + " - 分镜图");
work.setDescription("分镜图作品");
work.setPrompt(task.getPrompt());
work.setResultUrl(imageUrl);
work.setAspectRatio(task.getAspectRatio());
work.setQuality(task.isHdMode() ? "HD" : "SD");
work.setPointsCost(0); // 分镜图不单独扣费
work.setStatus(UserWork.WorkStatus.COMPLETED);
work.setCompletedAt(LocalDateTime.now());
work = userWorkRepository.save(work);
logger.info("创建分镜图作品成功: {}, 用户: {}", work.getId(), work.getUsername());
return work;
}
/**
* 根据用户名获取用户ID
*/
@@ -216,6 +256,14 @@ public class UserWorkService {
return userWorkRepository.findByUsernameOrderByCreatedAtDesc(username, pageable);
}
/**
* 获取用户正在进行中的作品包括PROCESSING和PENDING状态
*/
@Transactional(readOnly = true)
public java.util.List<UserWork> getProcessingWorks(String username) {
return userWorkRepository.findByUsernameAndProcessingOrPendingOrderByCreatedAtDesc(username);
}
/**
* 获取用户作品详情
*/
@@ -417,6 +465,36 @@ public class UserWorkService {
return userWorkRepository.findByTaskId(taskId);
}
/**
* 直接创建作品记录
*/
@Transactional
public UserWork createWork(UserWork work) {
if (work.getStatus() == null) {
work.setStatus(UserWork.WorkStatus.PROCESSING);
}
if (work.getPointsCost() == null) {
work.setPointsCost(0);
}
if (work.getIsPublic() == null) {
work.setIsPublic(Boolean.FALSE);
}
if (work.getViewCount() == null) {
work.setViewCount(0);
}
if (work.getLikeCount() == null) {
work.setLikeCount(0);
}
if (work.getDownloadCount() == null) {
work.setDownloadCount(0);
}
work.setUpdatedAt(LocalDateTime.now());
if (work.getCreatedAt() == null) {
work.setCreatedAt(LocalDateTime.now());
}
return userWorkRepository.save(work);
}
/**
* 更新作品状态
*/

View File

@@ -43,6 +43,14 @@ public class VerificationCodeService {
private final ConcurrentHashMap<String, String> verificationCodes = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, Long> rateLimits = new ConcurrentHashMap<>();
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
/**
* 统一归一化邮箱(去首尾空格并小写),避免大小写或空白导致匹配失败
*/
private String normalizeEmail(String email) {
if (email == null) return null;
return email.trim().toLowerCase();
}
/**
* 验证码长度
@@ -77,11 +85,12 @@ public class VerificationCodeService {
*/
public boolean sendEmailVerificationCode(String email) {
try {
// 检查发送频率限制
String rateLimitKey = "email_rate_limit:" + email;
// 归一化邮箱并检查发送频率限制
String normEmail = normalizeEmail(email);
String rateLimitKey = "email_rate_limit:" + normEmail;
Long lastSendTime = rateLimits.get(rateLimitKey);
if (lastSendTime != null && System.currentTimeMillis() - lastSendTime < SEND_INTERVAL_SECONDS * 1000) {
logger.warn("邮件发送过于频繁,邮箱: {}", email);
logger.warn("邮件发送过于频繁,邮箱: {}", normEmail);
return false;
}
@@ -89,10 +98,10 @@ public class VerificationCodeService {
String code = generateVerificationCode();
// 发送邮件
boolean success = sendEmail(email, code);
boolean success = sendEmail(normEmail, code);
if (success) {
// 存储验证码到内存
String codeKey = "email_code:" + email;
String codeKey = "email_code:" + normEmail;
verificationCodes.put(codeKey, code);
// 设置发送频率限制
@@ -101,10 +110,10 @@ public class VerificationCodeService {
// 设置验证码过期时间
scheduler.schedule(() -> {
verificationCodes.remove(codeKey);
logger.info("验证码已过期,邮箱: {}", email);
logger.info("验证码已过期,邮箱: {}", normEmail);
}, CODE_EXPIRE_MINUTES, TimeUnit.MINUTES);
logger.info("邮件验证码发送成功,邮箱: {}", email);
logger.info("邮件验证码发送成功,邮箱: {}", normEmail);
return true;
}
@@ -121,17 +130,18 @@ public class VerificationCodeService {
*/
public boolean verifyEmailCode(String email, String code) {
try {
String codeKey = "email_code:" + email;
String normEmail = normalizeEmail(email);
String codeKey = "email_code:" + normEmail;
String storedCode = verificationCodes.get(codeKey);
if (storedCode != null && storedCode.equals(code)) {
// 验证成功后删除验证码
verificationCodes.remove(codeKey);
logger.info("邮件验证码验证成功,邮箱: {}", email);
logger.info("邮件验证码验证成功,邮箱: {}", normEmail);
return true;
}
logger.warn("邮件验证码验证失败,邮箱: {}, 输入码: {}", email, code);
logger.warn("邮件验证码验证失败,邮箱: {}, 输入码: {}", normEmail, code);
return false;
} catch (Exception e) {
@@ -140,20 +150,30 @@ public class VerificationCodeService {
}
}
/**
* 获取验证码(仅用于开发模式返回给前端)
*/
public String getVerificationCode(String email) {
String normEmail = normalizeEmail(email);
String codeKey = "email_code:" + normEmail;
return verificationCodes.get(codeKey);
}
/**
* 开发模式:直接设置验证码(仅开发环境使用)
*/
public void setVerificationCode(String email, String code) {
String codeKey = "email_code:" + email;
String normEmail = normalizeEmail(email);
String codeKey = "email_code:" + normEmail;
verificationCodes.put(codeKey, code);
// 设置验证码过期时间
scheduler.schedule(() -> {
verificationCodes.remove(codeKey);
logger.info("开发模式验证码已过期,邮箱: {}", email);
logger.info("开发模式验证码已过期,邮箱: {}", normEmail);
}, CODE_EXPIRE_MINUTES, TimeUnit.MINUTES);
logger.info("开发模式验证码设置成功,邮箱: {}, 验证码: {}", email, code);
logger.info("开发模式验证码设置成功,邮箱: {}, 验证码: {}", normEmail, code);
}

View File

@@ -93,6 +93,18 @@ public class JwtUtils {
* 获取Token中的所有声明
*/
private Claims getAllClaimsFromToken(String token) {
if (token == null) {
throw new io.jsonwebtoken.JwtException("JWT token is null");
}
// 快速校验格式:紧凑形式的 JWS 应包含 2 个点header.payload.signature
long dotCount = token.chars().filter(ch -> ch == '.').count();
if (dotCount != 2) {
throw new io.jsonwebtoken.MalformedJwtException(
"Invalid compact JWT string: expected 2 period characters, found: " + dotCount
);
}
return Jwts.parser()
.verifyWith(getSigningKey())
.build()

View File

@@ -16,9 +16,13 @@ spring.datasource.hikari.connection-test-query=SELECT 1
# JPA配置
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.show-sql=false
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.format_sql=false
# 数据初始化配置 - 开发环境启动时自动执行 data.sql
spring.sql.init.mode=always
spring.sql.init.continue-on-error=true
# 服务器配置
server.port=8080
@@ -39,6 +43,10 @@ spring.servlet.multipart.enabled=true
# 日志配置
logging.level.com.example.demo=DEBUG
logging.level.org.springframework.security=DEBUG
# 关闭 Hibernate SQL 日志
logging.level.org.hibernate.SQL=WARN
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=WARN
logging.level.org.hibernate.orm.jdbc.bind=WARN
# JWT配置
jwt.secret=mySecretKey123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890

View File

@@ -1,11 +1,30 @@
# 生产环境配置
spring.h2.console.enabled=false
# MySQL DataSource (PROD) - 使用环境变量
spring.datasource.url=${DB_URL}
# ============================================
# MySQL 数据库配置 (生产环境)
# ============================================
# 使用环境变量配置数据库连接,适合线上服务器部署
#
# 部署时需要设置以下环境变量:
# - DB_HOST: 数据库主机地址127.0.0.1 或域名)
# - DB_PORT: 数据库端口默认3306
# - DB_NAME: 数据库名称默认aigc_platform
# - DB_USERNAME: 数据库用户名
# - DB_PASSWORD: 数据库密码
#
# 宝塔部署示例环境变量设置:
# DB_HOST=127.0.0.1
# DB_PORT=3306
# DB_NAME=aigc_platform
# DB_USERNAME=aigc_user
# DB_PASSWORD=your_secure_password_here
# ============================================
spring.datasource.url=jdbc:mysql://43.156.12.172:3306/aigc_platform?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.username=${DB_USERNAME}
spring.datasource.password=${DB_PASSWORD}
spring.datasource.username=aigc_platform
spring.datasource.password=jRbHPZbbkdm24yTT
# 数据库连接池配置 (生产环境 - 支持50人并发)
spring.datasource.hikari.maximum-pool-size=30
@@ -17,8 +36,9 @@ spring.datasource.hikari.leak-detection-threshold=60000
spring.datasource.hikari.validation-timeout=3000
spring.datasource.hikari.connection-test-query=SELECT 1
# 强烈建议生产环境禁用自动建表
spring.jpa.hibernate.ddl-auto=validate
# 生产环境:使用 update 模式自动创建/更新表结构(首次部署)
# 部署完成后可改为 validate 模式以提高安全性
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=false
spring.jpa.properties.hibernate.format_sql=false
@@ -43,8 +63,9 @@ alipay.public-key=${ALIPAY_PUBLIC_KEY}
alipay.gateway-url=https://openapi.alipay.com/gateway.do
alipay.charset=UTF-8
alipay.sign-type=RSA2
alipay.notify-url=${ALIPAY_NOTIFY_URL}
alipay.return-url=${ALIPAY_RETURN_URL}
alipay.domain=${ALIPAY_DOMAIN:https://vionow.com}
alipay.notify-url=${ALIPAY_NOTIFY_URL:https://vionow.com/api/payments/alipay/notify}
alipay.return-url=${ALIPAY_RETURN_URL:https://vionow.com/payment/success}
# JWT配置 - 使用环境变量
jwt.secret=${JWT_SECRET}
@@ -71,6 +92,10 @@ server.tomcat.connection-timeout=20000
logging.level.root=INFO
logging.level.com.example.demo=INFO
logging.level.org.springframework.security=WARN
# 关闭 Hibernate SQL 日志
logging.level.org.hibernate.SQL=WARN
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=WARN
logging.level.org.hibernate.orm.jdbc.bind=WARN
logging.file.name=${LOG_FILE_PATH:./logs/application.log}
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
@@ -88,6 +113,18 @@ app.ffmpeg.path=${FFMPEG_PATH:ffmpeg}
# 注意:确保应用有读写权限
app.upload.path=${UPLOAD_PATH:./uploads}
# SpringDoc OpenAPI (Swagger) 配置
# 生产环境建议禁用或限制访问
springdoc.api-docs.path=/v3/api-docs
springdoc.swagger-ui.path=/swagger-ui.html
springdoc.swagger-ui.enabled=true
springdoc.swagger-ui.operationsSorter=method
springdoc.swagger-ui.tagsSorter=alpha
springdoc.swagger-ui.tryItOutEnabled=true
springdoc.swagger-ui.filter=true
springdoc.swagger-ui.display-request-duration=true
springdoc.swagger-ui.doc-expansion=none

View File

@@ -4,7 +4,7 @@ spring.thymeleaf.cache=false
spring.profiles.active=dev
# 服务器配置
server.address=localhost
server.address=0.0.0.0
server.port=8080
# 文件上传配置扩大请求体大小以支持大图片Base64编码
@@ -25,3 +25,15 @@ jwt.expiration=86400000
# AI API配置
ai.api.base-url=http://116.62.4.26:8081
ai.api.key=ak_5f13ec469e6047d5b8155c3cc91350e2
# SpringDoc OpenAPI (Swagger) 配置
springdoc.api-docs.path=/v3/api-docs
springdoc.swagger-ui.path=/swagger-ui.html
springdoc.swagger-ui.operationsSorter=method
springdoc.swagger-ui.tagsSorter=alpha
springdoc.swagger-ui.tryItOutEnabled=true
springdoc.swagger-ui.filter=true
springdoc.swagger-ui.display-request-duration=true
springdoc.swagger-ui.doc-expansion=none
springdoc.swagger-ui.default-models-expand-depth=1
springdoc.swagger-ui.default-model-expand-depth=1

View File

@@ -1,123 +1,15 @@
-- 用户数据
INSERT IGNORE INTO users (username, email, password_hash, role, points, phone, nickname, gender, birthday, address) VALUES
('admin', 'admin@example.com', 'admin123', 'ROLE_ADMIN', 200, '15538239326', '管理员', 'M', '1990-01-01', '北京市朝阳区'),
('13689270819', '13689270819@example.com', '0627', 'ROLE_USER', 100, '13689270819', '演示用户', 'M', '1995-05-15', '上海市浦东新区'),
('testuser', 'testuser@example.com', 'test123', 'ROLE_USER', 75, '13900139000', '测试用户', 'F', '1992-08-20', '广州市天河区'),
('mingzi_FBx7foZYDS7inLQb', 'mingzi@example.com', '123456', 'ROLE_USER', 25, '13700137000', '名字用户', 'M', '1988-12-10', '深圳市南山区'),
('user001', 'user001@example.com', 'password123', 'ROLE_USER', 150, '13600136000', '用户001', 'M', '1991-07-12', '成都市锦江区'),
('user002', 'user002@example.com', 'password123', 'ROLE_USER', 80, '13500135000', '用户002', 'F', '1994-11-08', '武汉市江汉区'),
('user003', 'user003@example.com', 'password123', 'ROLE_USER', 200, '13400134000', '用户003', 'M', '1989-04-18', '西安市雁塔区'),
('user004', 'user004@example.com', 'password123', 'ROLE_USER', 120, '13300133000', '用户004', 'F', '1996-09-30', '南京市鼓楼区'),
('user005', 'user005@example.com', 'password123', 'ROLE_USER', 90, '13200132000', '用户005', 'M', '1990-06-22', '重庆市渝中区');
-- 初始化数据文件
-- 此文件用于开发/测试环境的初始数据
-- 生产环境请勿使用此文件应通过系统管理界面或API进行数据初始化
-- 会员等级数据
INSERT IGNORE INTO membership_levels (name, display_name, description, price, duration_days, points_bonus, features) VALUES
('standard', '标准会员', '基础会员服务,包含基本功能', 29.00, 30, 50, '{"video_quality": "720p", "storage": "5GB", "support": "email"}'),
('professional', '专业会员', '专业会员服务,包含高级功能', 99.00, 30, 200, '{"video_quality": "1080p", "storage": "20GB", "support": "priority", "api_access": true}'),
('enterprise', '企业会员', '企业级服务,包含所有功能', 299.00, 30, 500, '{"video_quality": "4K", "storage": "100GB", "support": "dedicated", "api_access": true, "custom_branding": true}');
-- 注意:生产环境部署时,此文件应保持为空或仅包含必要的系统配置数据
-- 用户会员信息
INSERT IGNORE INTO user_memberships (user_id, membership_level_id, start_date, end_date, status, auto_renew) VALUES
(1, 2, '2024-01-01 00:00:00', '2025-12-31 23:59:59', 'ACTIVE', true),
(2, 1, '2024-01-01 00:00:00', '2025-12-31 23:59:59', 'ACTIVE', false),
(3, 1, '2024-01-01 00:00:00', '2025-12-31 23:59:59', 'ACTIVE', false),
(4, 2, '2024-01-01 00:00:00', '2025-12-31 23:59:59', 'ACTIVE', true),
(5, 2, '2024-01-01 00:00:00', '2025-12-31 23:59:59', 'ACTIVE', true),
(6, 1, '2024-01-01 00:00:00', '2025-12-31 23:59:59', 'ACTIVE', false),
(7, 1, '2024-01-01 00:00:00', '2025-12-31 23:59:59', 'ACTIVE', false),
(8, 2, '2024-01-01 00:00:00', '2025-12-31 23:59:59', 'ACTIVE', true),
(9, 1, '2024-01-01 00:00:00', '2025-12-31 23:59:59', 'ACTIVE', false),
(10, 1, '2024-01-01 00:00:00', '2025-12-31 23:59:59', 'ACTIVE', false);
-- 订单数据
INSERT IGNORE INTO orders (order_number, total_amount, currency, status, order_type, description, user_id, created_at) VALUES
('ORD20240101001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 1, '2024-01-01 10:00:00'),
('ORD20240101002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-01-01 11:00:00'),
('ORD20240101003', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-01-01 12:00:00'),
('ORD20240101004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-01-01 13:00:00'),
('ORD20240101005', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 5, '2024-01-01 14:00:00'),
('ORD20240101006', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 6, '2024-01-01 15:00:00'),
('ORD20240101007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-01-01 16:00:00'),
('ORD20240101008', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 8, '2024-01-01 17:00:00'),
('ORD20240101009', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 9, '2024-01-01 18:00:00'),
('ORD20240101010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 10, '2024-01-01 19:00:00'),
('ORD20240102001', 199.00, 'CNY', 'PENDING', 'PRODUCT', '视频生成服务包', 1, '2024-01-02 09:00:00'),
('ORD20240102002', 99.00, 'CNY', 'PROCESSING', 'PRODUCT', '高级视频编辑', 2, '2024-01-02 10:00:00'),
('ORD20240102003', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 3, '2024-01-02 11:00:00'),
('ORD20240102004', 49.00, 'CNY', 'CANCELLED', 'PRODUCT', '基础视频生成', 4, '2024-01-02 12:00:00'),
('ORD20240102005', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 5, '2024-01-02 13:00:00');
-- 订单商品数据
INSERT IGNORE INTO order_items (product_name, product_description, unit_price, quantity, subtotal, order_id) VALUES
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 1),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 2),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 3),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 4),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 5),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 6),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 7),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 8),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 9),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 10),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 11),
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 12),
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 13),
('基础视频生成', '单次视频生成服务', 49.00, 1, 49.00, 14),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 15);
-- 支付数据
INSERT IGNORE INTO payments (order_id, amount, currency, payment_method, status, description, user_id, created_at, paid_at) VALUES
('ORD20240101001', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 1, '2024-01-01 10:00:00', '2024-01-01 10:05:00'),
('ORD20240101002', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 2, '2024-01-01 11:00:00', '2024-01-01 11:02:00'),
('ORD20240101003', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 3, '2024-01-01 12:00:00', '2024-01-01 12:03:00'),
('ORD20240101004', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 4, '2024-01-01 13:00:00', '2024-01-01 13:04:00'),
('ORD20240101005', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 5, '2024-01-01 14:00:00', '2024-01-01 14:05:00'),
('ORD20240101006', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 6, '2024-01-01 15:00:00', '2024-01-01 15:02:00'),
('ORD20240101007', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 7, '2024-01-01 16:00:00', '2024-01-01 16:03:00'),
('ORD20240101008', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 8, '2024-01-01 17:00:00', '2024-01-01 17:04:00'),
('ORD20240101009', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 9, '2024-01-01 18:00:00', '2024-01-01 18:02:00'),
('ORD20240101010', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 10, '2024-01-01 19:00:00', '2024-01-01 19:03:00'),
('ORD20240102001', 199.00, 'CNY', 'ALIPAY', 'PENDING', '视频生成服务包', 1, '2024-01-02 09:00:00', NULL),
('ORD20240102002', 99.00, 'CNY', 'WECHAT', 'PROCESSING', '高级视频编辑', 2, '2024-01-02 10:00:00', NULL),
('ORD20240102003', 299.00, 'CNY', 'ALIPAY', 'COMPLETED', '企业会员订阅', 3, '2024-01-02 11:00:00', '2024-01-02 11:05:00'),
('ORD20240102004', 49.00, 'CNY', 'WECHAT', 'CANCELLED', '基础视频生成', 4, '2024-01-02 12:00:00', NULL),
('ORD20240102005', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 5, '2024-01-02 13:00:00', '2024-01-02 13:04:00');
-- 视频生成任务数据
INSERT IGNORE INTO video_tasks (task_id, user_id, task_type, title, description, input_text, status, progress, created_at, completed_at) VALUES
('TASK20240101001', 1, 'TEXT_TO_VIDEO', '产品介绍视频', '为公司新产品制作的介绍视频', '这是一款革命性的AI产品能够帮助用户快速生成高质量的视频内容...', 'COMPLETED', 100, '2024-01-01 10:00:00', '2024-01-01 10:30:00'),
('TASK20240101002', 2, 'IMAGE_TO_VIDEO', '风景动画', '将静态风景图片转换为动态视频', NULL, 'COMPLETED', 100, '2024-01-01 11:00:00', '2024-01-01 11:25:00'),
('TASK20240101003', 3, 'STORYBOARD_VIDEO', '故事板视频', '基于故事板创建的视频', '从前有一个小村庄,村民们过着平静的生活...', 'PROCESSING', 75, '2024-01-01 12:00:00', NULL),
('TASK20240101004', 4, 'TEXT_TO_VIDEO', '教育视频', '在线教育课程视频', '今天我们来学习Vue.js的基础知识...', 'COMPLETED', 100, '2024-01-01 13:00:00', '2024-01-01 13:35:00'),
('TASK20240101005', 5, 'IMAGE_TO_VIDEO', '产品展示', '产品图片转视频展示', NULL, 'COMPLETED', 100, '2024-01-01 14:00:00', '2024-01-01 14:20:00'),
('TASK20240101006', 6, 'TEXT_TO_VIDEO', '营销视频', '产品营销推广视频', '限时优惠现在购买享受8折优惠...', 'PENDING', 0, '2024-01-01 15:00:00', NULL),
('TASK20240101007', 7, 'STORYBOARD_VIDEO', '动画短片', '创意动画短片制作', '在一个遥远的星球上,住着一群可爱的小精灵...', 'COMPLETED', 100, '2024-01-01 16:00:00', '2024-01-01 16:45:00'),
('TASK20240101008', 8, 'TEXT_TO_VIDEO', '技术分享', '技术分享会视频', '今天分享的主题是微服务架构的设计原则...', 'PROCESSING', 60, '2024-01-01 17:00:00', NULL),
('TASK20240101009', 9, 'IMAGE_TO_VIDEO', '艺术创作', '艺术作品动态展示', NULL, 'COMPLETED', 100, '2024-01-01 18:00:00', '2024-01-01 18:15:00'),
('TASK20240101010', 10, 'TEXT_TO_VIDEO', '新闻播报', '新闻播报视频', '今日要闻科技公司发布最新AI技术...', 'FAILED', 0, '2024-01-01 19:00:00', NULL);
-- 用户作品数据
INSERT IGNORE INTO user_works (user_id, title, description, work_type, cover_image, video_url, tags, view_count, like_count, created_at) VALUES
(1, '产品介绍视频', '为公司新产品制作的介绍视频', 'VIDEO', '/images/covers/product_intro.jpg', '/videos/product_intro.mp4', '产品,介绍,商业', 1250, 89, '2024-01-01 10:30:00'),
(2, '风景动画', '将静态风景图片转换为动态视频', 'VIDEO', '/images/covers/landscape.jpg', '/videos/landscape.mp4', '风景,动画,自然', 890, 67, '2024-01-01 11:25:00'),
(3, '故事板视频', '基于故事板创建的视频', 'VIDEO', '/images/covers/storyboard.jpg', '/videos/storyboard.mp4', '故事,创意,动画', 2100, 156, '2024-01-01 12:30:00'),
(4, '教育视频', '在线教育课程视频', 'VIDEO', '/images/covers/education.jpg', '/videos/education.mp4', '教育,课程,学习', 3200, 234, '2024-01-01 13:35:00'),
(5, '产品展示', '产品图片转视频展示', 'VIDEO', '/images/covers/product_show.jpg', '/videos/product_show.mp4', '产品,展示,商业', 1560, 112, '2024-01-01 14:20:00'),
(6, '营销视频', '产品营销推广视频', 'VIDEO', '/images/covers/marketing.jpg', '/videos/marketing.mp4', '营销,推广,商业', 2800, 198, '2024-01-01 15:30:00'),
(7, '动画短片', '创意动画短片制作', 'VIDEO', '/images/covers/animation.jpg', '/videos/animation.mp4', '动画,创意,短片', 4500, 345, '2024-01-01 16:45:00'),
(8, '技术分享', '技术分享会视频', 'VIDEO', '/images/covers/tech_share.jpg', '/videos/tech_share.mp4', '技术,分享,编程', 1800, 134, '2024-01-01 17:30:00'),
(9, '艺术创作', '艺术作品动态展示', 'VIDEO', '/images/covers/art.jpg', '/videos/art.mp4', '艺术,创作,美学', 950, 78, '2024-01-01 18:15:00'),
(10, '新闻播报', '新闻播报视频', 'VIDEO', '/images/covers/news.jpg', '/videos/news.mp4', '新闻,播报,资讯', 1200, 89, '2024-01-01 19:30:00');
-- 系统配置数据
INSERT IGNORE INTO system_configs (config_key, config_value, description, config_type, is_public) VALUES
('site_name', 'AIGC视频生成平台', '网站名称', 'STRING', true),
('site_description', '专业的AI视频生成服务平台', '网站描述', 'STRING', true),
('max_file_size', '100', '最大文件上传大小(MB)', 'NUMBER', false),
('supported_formats', '["mp4", "avi", "mov", "wmv"]', '支持的视频格式', 'JSON', true),
('default_video_quality', '1080p', '默认视频质量', 'STRING', false),
('max_video_duration', '300', '最大视频时长(秒)', 'NUMBER', false),
('api_rate_limit', '100', 'API调用频率限制(次/小时)', 'NUMBER', false),
('maintenance_mode', 'false', '维护模式开关', 'BOOLEAN', false),
('registration_enabled', 'true', '用户注册开关', 'BOOLEAN', true),
('email_verification', 'false', '邮箱验证开关', 'BOOLEAN', false);
-- ============================================
-- 管理员权限自动设置
-- ============================================
-- 应用启动时自动将 984523799@qq.com 设置为管理员
-- 如果该用户存在,则更新其角色为管理员
UPDATE users
SET role = 'ROLE_ADMIN',
updated_at = CURRENT_TIMESTAMP
WHERE email = '984523799@qq.com';

View File

@@ -0,0 +1,4 @@
-- 添加 STORYBOARD_IMAGE 到 user_works 表的 work_type 枚举
ALTER TABLE user_works
MODIFY COLUMN work_type ENUM('TEXT_TO_VIDEO', 'IMAGE_TO_VIDEO', 'STORYBOARD_VIDEO', 'STORYBOARD_IMAGE') NOT NULL COMMENT '作品类型';

View File

@@ -3,7 +3,7 @@ CREATE TABLE IF NOT EXISTS task_queue (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(100) NOT NULL COMMENT '用户名',
task_id VARCHAR(50) NOT NULL UNIQUE COMMENT '任务ID',
task_type ENUM('TEXT_TO_VIDEO', 'IMAGE_TO_VIDEO') NOT NULL COMMENT '任务类型',
task_type ENUM('TEXT_TO_VIDEO', 'IMAGE_TO_VIDEO', 'STORYBOARD_VIDEO') NOT NULL COMMENT '任务类型',
status ENUM('PENDING', 'PROCESSING', 'COMPLETED', 'FAILED', 'CANCELLED', 'TIMEOUT') NOT NULL DEFAULT 'PENDING' COMMENT '队列状态',
priority INT NOT NULL DEFAULT 0 COMMENT '优先级,数字越小优先级越高',
real_task_id VARCHAR(100) COMMENT '外部API返回的真实任务ID',
@@ -37,3 +37,6 @@ CREATE TABLE IF NOT EXISTS task_queue (

View File

@@ -6,7 +6,7 @@ CREATE TABLE IF NOT EXISTS points_freeze_records (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(100) NOT NULL COMMENT '用户名',
task_id VARCHAR(50) NOT NULL UNIQUE COMMENT '任务ID',
task_type ENUM('TEXT_TO_VIDEO', 'IMAGE_TO_VIDEO') NOT NULL COMMENT '任务类型',
task_type ENUM('TEXT_TO_VIDEO', 'IMAGE_TO_VIDEO', 'STORYBOARD_VIDEO') NOT NULL COMMENT '任务类型',
freeze_points INT NOT NULL COMMENT '冻结的积分数量',
status ENUM('FROZEN', 'DEDUCTED', 'RETURNED', 'EXPIRED') NOT NULL DEFAULT 'FROZEN' COMMENT '冻结状态',
freeze_reason VARCHAR(200) COMMENT '冻结原因',
@@ -36,3 +36,6 @@ CREATE TABLE IF NOT EXISTS points_freeze_records (

View File

@@ -3,7 +3,7 @@ CREATE TABLE IF NOT EXISTS user_works (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(100) NOT NULL COMMENT '用户名',
task_id VARCHAR(50) NOT NULL UNIQUE COMMENT '任务ID',
work_type ENUM('TEXT_TO_VIDEO', 'IMAGE_TO_VIDEO') NOT NULL COMMENT '作品类型',
work_type ENUM('TEXT_TO_VIDEO', 'IMAGE_TO_VIDEO', 'STORYBOARD_VIDEO') NOT NULL COMMENT '作品类型',
title VARCHAR(200) COMMENT '作品标题',
description TEXT COMMENT '作品描述',
prompt TEXT COMMENT '生成提示词',

View File

@@ -38,4 +38,8 @@ CREATE TABLE task_status (

View File

@@ -0,0 +1,8 @@
-- V7: 为 task_status 表添加复合索引以加速轮询查询
ALTER TABLE task_status
ADD INDEX idx_status_lastpolled_pollcount (status, last_polled_at, poll_count);
-- 说明:
-- 该索引用于加速下面这类查询:
-- WHERE status = 'PROCESSING' AND poll_count < max_polls AND (last_polled_at IS NULL OR last_polled_at < :cutoffTime)
-- 索引列顺序选择status, last_polled_at, poll_count能让数据库在先按 status 过滤,再按 last_polled_at 范围筛选,最后用 poll_count 进一步过滤,从而减少全表扫描。

View File

@@ -0,0 +1,13 @@
-- 更新任务队列表,添加 STORYBOARD_VIDEO 类型
-- 注意MySQL 不支持直接修改 ENUM需要先修改为 VARCHAR再改回 ENUM
ALTER TABLE task_queue
MODIFY COLUMN task_type ENUM('TEXT_TO_VIDEO', 'IMAGE_TO_VIDEO', 'STORYBOARD_VIDEO') NOT NULL COMMENT '任务类型';
-- 更新积分冻结记录表,添加 STORYBOARD_VIDEO 类型
ALTER TABLE points_freeze_records
MODIFY COLUMN task_type ENUM('TEXT_TO_VIDEO', 'IMAGE_TO_VIDEO', 'STORYBOARD_VIDEO') NOT NULL COMMENT '任务类型';
-- 更新用户作品表,添加 STORYBOARD_VIDEO 类型
ALTER TABLE user_works
MODIFY COLUMN work_type ENUM('TEXT_TO_VIDEO', 'IMAGE_TO_VIDEO', 'STORYBOARD_VIDEO') NOT NULL COMMENT '作品类型';

View File

@@ -1,19 +0,0 @@
-- 数据库迁移脚本为users表添加created_at字段
-- 如果users表不存在created_at字段则添加它
-- 检查字段是否存在,如果不存在则添加
SET @sql = IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'users'
AND COLUMN_NAME = 'created_at') = 0,
'ALTER TABLE users ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP',
'SELECT "created_at column already exists" as message'
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 为现有用户设置创建时间如果为NULL
UPDATE users SET created_at = CURRENT_TIMESTAMP WHERE created_at IS NULL;

View File

@@ -1,34 +0,0 @@
-- 创建图生视频任务表
CREATE TABLE IF NOT EXISTS image_to_video_tasks (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
task_id VARCHAR(50) NOT NULL UNIQUE,
username VARCHAR(100) NOT NULL,
first_frame_url VARCHAR(500) NOT NULL,
last_frame_url VARCHAR(500),
prompt TEXT,
aspect_ratio VARCHAR(10) NOT NULL DEFAULT '16:9',
duration INT NOT NULL DEFAULT 5,
hd_mode BOOLEAN NOT NULL DEFAULT FALSE,
status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
progress INT DEFAULT 0,
result_url VARCHAR(500),
real_task_id VARCHAR(100),
error_message TEXT,
cost_points INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
completed_at TIMESTAMP NULL,
INDEX idx_username (username),
INDEX idx_status (status),
INDEX idx_created_at (created_at),
INDEX idx_task_id (task_id)
);
-- 注意MySQL的CHECK约束支持有限以下约束在应用层进行验证
-- 任务状态应该在应用层验证PENDING, PROCESSING, COMPLETED, FAILED, CANCELLED
-- 时长应该在应用层验证1-60秒
-- 进度应该在应用层验证0-100
-- 如果需要数据库层约束,可以使用触发器或存储过程
-- 这里我们依赖应用层的验证逻辑

View File

@@ -1,32 +0,0 @@
-- 创建文生视频任务表
CREATE TABLE IF NOT EXISTS text_to_video_tasks (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
task_id VARCHAR(50) NOT NULL UNIQUE,
username VARCHAR(100) NOT NULL,
prompt TEXT,
aspect_ratio VARCHAR(10) NOT NULL DEFAULT '16:9',
duration INT NOT NULL DEFAULT 5,
hd_mode BOOLEAN NOT NULL DEFAULT FALSE,
status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
progress INT DEFAULT 0,
result_url VARCHAR(500),
real_task_id VARCHAR(100),
error_message TEXT,
cost_points INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
completed_at TIMESTAMP NULL,
INDEX idx_username (username),
INDEX idx_status (status),
INDEX idx_created_at (created_at),
INDEX idx_task_id (task_id)
);
-- 注意MySQL的CHECK约束支持有限以下约束在应用层进行验证
-- 任务状态应该在应用层验证PENDING, PROCESSING, COMPLETED, FAILED, CANCELLED
-- 时长应该在应用层验证1-60秒
-- 进度应该在应用层验证0-100
-- 如果需要数据库层约束,可以使用触发器或存储过程
-- 这里我们依赖应用层的验证逻辑

View File

@@ -1,207 +0,0 @@
-- 12个月订单商品数据
-- 对应orders_12months.sql中的订单
INSERT IGNORE INTO order_items (product_name, product_description, unit_price, quantity, subtotal, order_id) VALUES
-- 2024年1月订单商品
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 1),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 2),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 3),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 4),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 5),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 6),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 7),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 8),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 9),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 10),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 11),
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 12),
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 13),
('基础视频生成', '单次视频生成服务', 49.00, 1, 49.00, 14),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 15),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 16),
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 17),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 18),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 19),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 20),
-- 2024年2月订单商品
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 21),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 22),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 23),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 24),
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 25),
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 26),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 27),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 28),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 29),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 30),
-- 2024年3月订单商品
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 31),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 32),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 33),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 34),
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 35),
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 36),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 37),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 38),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 39),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 40),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 41),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 42),
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 43),
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 44),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 45),
-- 2024年4月订单商品
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 46),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 47),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 48),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 49),
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 50),
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 51),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 52),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 53),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 54),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 55),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 56),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 57),
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 58),
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 59),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 60),
-- 2024年5月订单商品
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 61),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 62),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 63),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 64),
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 65),
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 66),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 67),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 68),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 69),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 70),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 71),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 72),
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 73),
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 74),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 75),
-- 2024年6月订单商品
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 76),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 77),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 78),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 79),
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 80),
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 81),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 82),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 83),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 84),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 85),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 86),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 87),
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 88),
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 89),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 90),
-- 2024年7月订单商品
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 91),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 92),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 93),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 94),
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 95),
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 96),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 97),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 98),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 99),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 100),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 101),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 102),
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 103),
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 104),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 105),
-- 2024年8月订单商品
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 106),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 107),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 108),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 109),
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 110),
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 111),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 112),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 113),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 114),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 115),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 116),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 117),
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 118),
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 119),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 120),
-- 2024年9月订单商品
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 121),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 122),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 123),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 124),
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 125),
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 126),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 127),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 128),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 129),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 130),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 131),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 132),
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 133),
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 134),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 135),
-- 2024年10月订单商品
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 136),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 137),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 138),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 139),
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 140),
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 141),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 142),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 143),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 144),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 145),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 146),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 147),
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 148),
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 149),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 150),
-- 2024年11月订单商品
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 151),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 152),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 153),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 154),
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 155),
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 156),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 157),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 158),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 159),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 160),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 161),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 162),
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 163),
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 164),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 165),
-- 2024年12月订单商品
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 166),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 167),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 168),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 169),
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 170),
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 171),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 172),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 173),
('专业会员订阅', '30天专业会员服务', 99.00, 1, 99.00, 174),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 175),
('标准会员订阅', '30天标准会员服务', 29.00, 1, 29.00, 176),
('视频生成服务包', '包含10次视频生成', 199.00, 1, 199.00, 177),
('高级视频编辑', '专业级视频编辑服务', 99.00, 1, 99.00, 178),
('企业会员订阅', '30天企业会员服务', 299.00, 1, 299.00, 179),
('专业视频制作', '定制化视频制作', 149.00, 1, 149.00, 180);

View File

@@ -1,25 +0,0 @@
-- 插入订单项数据
INSERT INTO order_items (order_id, product_name, quantity, unit_price, subtotal)
SELECT
o.id as order_id,
CASE
WHEN o.order_type = 'MEMBERSHIP' THEN
CASE
WHEN o.total_amount = 29.00 THEN '标准会员订阅'
WHEN o.total_amount = 99.00 THEN '专业会员订阅'
WHEN o.total_amount = 299.00 THEN '企业会员订阅'
ELSE '会员订阅'
END
WHEN o.order_type = 'PRODUCT' THEN
CASE
WHEN o.total_amount = 49.00 THEN '基础视频生成'
WHEN o.total_amount = 99.00 THEN '高级视频编辑'
WHEN o.total_amount = 199.00 THEN '视频生成服务包'
ELSE '视频服务'
END
ELSE '其他服务'
END as product_name,
1 as quantity,
o.total_amount as unit_price,
o.total_amount as subtotal
FROM orders o;

View File

@@ -1,208 +0,0 @@
-- 12个月订单数据生成脚本
-- 生成2024年1月到12月的订单数据
-- 订单数据 (2024年1月-12月)
INSERT IGNORE INTO orders (order_number, total_amount, currency, status, order_type, description, user_id, created_at) VALUES
-- 2024年1月订单
('ORD20240101001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 1, '2024-01-01 10:00:00'),
('ORD20240101002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-01-01 11:00:00'),
('ORD20240101003', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-01-01 12:00:00'),
('ORD20240101004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-01-01 13:00:00'),
('ORD20240101005', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 5, '2024-01-01 14:00:00'),
('ORD20240101006', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 6, '2024-01-01 15:00:00'),
('ORD20240101007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-01-01 16:00:00'),
('ORD20240101008', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 8, '2024-01-01 17:00:00'),
('ORD20240101009', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 9, '2024-01-01 18:00:00'),
('ORD20240101010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 10, '2024-01-01 19:00:00'),
('ORD20240102001', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 1, '2024-01-02 09:00:00'),
('ORD20240102002', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 2, '2024-01-02 10:00:00'),
('ORD20240102003', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 3, '2024-01-02 11:00:00'),
('ORD20240102004', 49.00, 'CNY', 'CANCELLED', 'PRODUCT', '基础视频生成', 4, '2024-01-02 12:00:00'),
('ORD20240102005', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 5, '2024-01-02 13:00:00'),
('ORD20240115001', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-01-15 14:30:00'),
('ORD20240115002', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 7, '2024-01-15 15:45:00'),
('ORD20240115003', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-01-15 16:20:00'),
('ORD20240128001', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 9, '2024-01-28 10:15:00'),
('ORD20240128002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-01-28 11:30:00'),
-- 2024年2月订单
('ORD20240201001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-02-01 09:00:00'),
('ORD20240201002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 2, '2024-02-01 10:15:00'),
('ORD20240201003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-02-01 11:30:00'),
('ORD20240201004', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 4, '2024-02-01 14:20:00'),
('ORD20240201005', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 5, '2024-02-01 15:45:00'),
('ORD20240214001', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 6, '2024-02-14 10:00:00'),
('ORD20240214002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-02-14 11:30:00'),
('ORD20240214003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-02-14 14:15:00'),
('ORD20240225001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-02-25 16:00:00'),
('ORD20240225002', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 10, '2024-02-25 17:30:00'),
-- 2024年3月订单
('ORD20240301001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-03-01 09:30:00'),
('ORD20240301002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 2, '2024-03-01 10:45:00'),
('ORD20240301003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-03-01 11:20:00'),
('ORD20240301004', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 4, '2024-03-01 14:10:00'),
('ORD20240301005', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 5, '2024-03-01 15:25:00'),
('ORD20240308001', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 6, '2024-03-08 10:00:00'),
('ORD20240308002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-03-08 11:15:00'),
('ORD20240308003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-03-08 14:30:00'),
('ORD20240315001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-03-15 16:45:00'),
('ORD20240315002', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 10, '2024-03-15 17:20:00'),
('ORD20240322001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-03-22 09:15:00'),
('ORD20240322002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-03-22 10:30:00'),
('ORD20240322003', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 3, '2024-03-22 14:45:00'),
('ORD20240330001', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 4, '2024-03-30 11:00:00'),
('ORD20240330002', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 5, '2024-03-30 15:30:00'),
-- 2024年4月订单
('ORD20240401001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 6, '2024-04-01 09:00:00'),
('ORD20240401002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-04-01 10:20:00'),
('ORD20240401003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-04-01 11:40:00'),
('ORD20240401004', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 9, '2024-04-01 14:15:00'),
('ORD20240401005', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 10, '2024-04-01 15:35:00'),
('ORD20240410001', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 1, '2024-04-10 10:30:00'),
('ORD20240410002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-04-10 11:45:00'),
('ORD20240410003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-04-10 14:20:00'),
('ORD20240420001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-04-20 16:10:00'),
('ORD20240420002', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 5, '2024-04-20 17:25:00'),
('ORD20240420003', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 6, '2024-04-20 18:40:00'),
('ORD20240425001', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 7, '2024-04-25 09:15:00'),
('ORD20240425002', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 8, '2024-04-25 10:30:00'),
('ORD20240425003', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 9, '2024-04-25 14:45:00'),
('ORD20240430001', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 10, '2024-04-30 15:20:00'),
-- 2024年5月订单
('ORD20240501001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-05-01 09:30:00'),
('ORD20240501002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 2, '2024-05-01 10:45:00'),
('ORD20240501003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-05-01 11:20:00'),
('ORD20240501004', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 4, '2024-05-01 14:10:00'),
('ORD20240501005', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 5, '2024-05-01 15:25:00'),
('ORD20240510001', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 6, '2024-05-10 10:00:00'),
('ORD20240510002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-05-10 11:15:00'),
('ORD20240510003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-05-10 14:30:00'),
('ORD20240520001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-05-20 16:45:00'),
('ORD20240520002', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 10, '2024-05-20 17:20:00'),
('ORD20240520003', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-05-20 18:35:00'),
('ORD20240525001', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-05-25 09:50:00'),
('ORD20240525002', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 3, '2024-05-25 11:05:00'),
('ORD20240525003', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 4, '2024-05-25 14:20:00'),
('ORD20240530001', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 5, '2024-05-30 15:35:00'),
-- 2024年6月订单
('ORD20240601001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 6, '2024-06-01 09:15:00'),
('ORD20240601002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-06-01 10:30:00'),
('ORD20240601003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-06-01 11:45:00'),
('ORD20240601004', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 9, '2024-06-01 14:00:00'),
('ORD20240601005', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 10, '2024-06-01 15:15:00'),
('ORD20240615001', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 1, '2024-06-15 10:45:00'),
('ORD20240615002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-06-15 12:00:00'),
('ORD20240615003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-06-15 14:15:00'),
('ORD20240620001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-06-20 16:30:00'),
('ORD20240620002', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 5, '2024-06-20 17:45:00'),
('ORD20240620003', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 6, '2024-06-20 19:00:00'),
('ORD20240625001', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 7, '2024-06-25 09:30:00'),
('ORD20240625002', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 8, '2024-06-25 10:45:00'),
('ORD20240625003', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 9, '2024-06-25 14:00:00'),
('ORD20240630001', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 10, '2024-06-30 15:15:00'),
-- 2024年7月订单
('ORD20240701001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-07-01 09:45:00'),
('ORD20240701002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 2, '2024-07-01 11:00:00'),
('ORD20240701003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-07-01 12:15:00'),
('ORD20240701004', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 4, '2024-07-01 14:30:00'),
('ORD20240701005', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 5, '2024-07-01 15:45:00'),
('ORD20240710001', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 6, '2024-07-10 10:20:00'),
('ORD20240710002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-07-10 11:35:00'),
('ORD20240710003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-07-10 14:50:00'),
('ORD20240720001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-07-20 16:05:00'),
('ORD20240720002', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 10, '2024-07-20 17:20:00'),
('ORD20240720003', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-07-20 18:35:00'),
('ORD20240725001', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-07-25 09:50:00'),
('ORD20240725002', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 3, '2024-07-25 11:05:00'),
('ORD20240725003', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 4, '2024-07-25 14:20:00'),
('ORD20240730001', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 5, '2024-07-30 15:35:00'),
-- 2024年8月订单
('ORD20240801001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 6, '2024-08-01 09:30:00'),
('ORD20240801002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-08-01 10:45:00'),
('ORD20240801003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-08-01 12:00:00'),
('ORD20240801004', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 9, '2024-08-01 14:15:00'),
('ORD20240801005', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 10, '2024-08-01 15:30:00'),
('ORD20240810001', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 1, '2024-08-10 10:00:00'),
('ORD20240810002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-08-10 11:15:00'),
('ORD20240810003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-08-10 14:30:00'),
('ORD20240820001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-08-20 16:45:00'),
('ORD20240820002', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 5, '2024-08-20 18:00:00'),
('ORD20240820003', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 6, '2024-08-20 19:15:00'),
('ORD20240825001', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 7, '2024-08-25 09:30:00'),
('ORD20240825002', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 8, '2024-08-25 10:45:00'),
('ORD20240825003', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 9, '2024-08-25 14:00:00'),
('ORD20240830001', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 10, '2024-08-30 15:15:00'),
-- 2024年9月订单
('ORD20240901001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-09-01 09:15:00'),
('ORD20240901002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 2, '2024-09-01 10:30:00'),
('ORD20240901003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-09-01 11:45:00'),
('ORD20240901004', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 4, '2024-09-01 14:00:00'),
('ORD20240901005', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 5, '2024-09-01 15:15:00'),
('ORD20240910001', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 6, '2024-09-10 10:45:00'),
('ORD20240910002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-09-10 12:00:00'),
('ORD20240910003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-09-10 14:15:00'),
('ORD20240920001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-09-20 16:30:00'),
('ORD20240920002', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 10, '2024-09-20 17:45:00'),
('ORD20240920003', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-09-20 19:00:00'),
('ORD20240925001', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-09-25 09:15:00'),
('ORD20240925002', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 3, '2024-09-25 10:30:00'),
('ORD20240925003', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 4, '2024-09-25 14:45:00'),
('ORD20240930001', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 5, '2024-09-30 15:00:00'),
-- 2024年10月订单
('ORD20241001001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 6, '2024-10-01 09:45:00'),
('ORD20241001002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-10-01 11:00:00'),
('ORD20241001003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-10-01 12:15:00'),
('ORD20241001004', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 9, '2024-10-01 14:30:00'),
('ORD20241001005', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 10, '2024-10-01 15:45:00'),
('ORD20241010001', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 1, '2024-10-10 10:20:00'),
('ORD20241010002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-10-10 11:35:00'),
('ORD20241010003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-10-10 14:50:00'),
('ORD20241020001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-10-20 16:05:00'),
('ORD20241020002', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 5, '2024-10-20 17:20:00'),
('ORD20241020003', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 6, '2024-10-20 18:35:00'),
('ORD20241025001', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 7, '2024-10-25 09:50:00'),
('ORD20241025002', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 8, '2024-10-25 11:05:00'),
('ORD20241025003', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 9, '2024-10-25 14:20:00'),
('ORD20241030001', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 10, '2024-10-30 15:35:00'),
-- 2024年11月订单
('ORD20241101001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-11-01 09:30:00'),
('ORD20241101002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 2, '2024-11-01 10:45:00'),
('ORD20241101003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-11-01 12:00:00'),
('ORD20241101004', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 4, '2024-11-01 14:15:00'),
('ORD20241101005', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 5, '2024-11-01 15:30:00'),
('ORD20241111001', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 6, '2024-11-11 10:00:00'),
('ORD20241111002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-11-11 11:15:00'),
('ORD20241111003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-11-11 14:30:00'),
('ORD20241120001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-11-20 16:45:00'),
('ORD20241120002', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 10, '2024-11-20 18:00:00'),
('ORD20241120003', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-11-20 19:15:00'),
('ORD20241125001', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-11-25 09:30:00'),
('ORD20241125002', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 3, '2024-11-25 10:45:00'),
('ORD20241125003', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 4, '2024-11-25 14:00:00'),
('ORD20241130001', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 5, '2024-11-30 15:15:00'),
-- 2024年12月订单
('ORD20241201001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 6, '2024-12-01 09:15:00'),
('ORD20241201002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-12-01 10:30:00'),
('ORD20241201003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-12-01 11:45:00'),
('ORD20241201004', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 9, '2024-12-01 14:00:00'),
('ORD20241201005', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 10, '2024-12-01 15:15:00'),
('ORD20241210001', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 1, '2024-12-10 10:45:00'),
('ORD20241210002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-12-10 12:00:00'),
('ORD20241210003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-12-10 14:15:00'),
('ORD20241220001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-12-20 16:30:00'),
('ORD20241220002', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 5, '2024-12-20 17:45:00'),
('ORD20241220003', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 6, '2024-12-20 19:00:00'),
('ORD20241225001', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 7, '2024-12-25 09:15:00'),
('ORD20241225002', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 8, '2024-12-25 10:30:00'),
('ORD20241225003', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 9, '2024-12-25 14:45:00'),
('ORD20241230001', 149.00, 'CNY', 'COMPLETED', 'PRODUCT', '专业视频制作', 10, '2024-12-30 15:00:00');

View File

@@ -1,265 +0,0 @@
-- 插入12个月的订单数据使用正确的用户ID
INSERT INTO orders (order_number, total_amount, currency, status, order_type, description, user_id, created_at) VALUES
-- 2024年1月
('ORD20240101001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-01-01 10:00:00'),
('ORD20240101002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 209, '2024-01-01 11:00:00'),
('ORD20240101003', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-01-01 12:00:00'),
('ORD20240101004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 212, '2024-01-01 13:00:00'),
('ORD20240101005', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-01-01 14:00:00'),
('ORD20240101006', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-01-01 15:00:00'),
('ORD20240101007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-01-01 16:00:00'),
('ORD20240101008', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-01-01 17:00:00'),
('ORD20240101009', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-01-01 18:00:00'),
('ORD20240101010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-01-01 19:00:00'),
('ORD20240102001', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-01-02 09:00:00'),
('ORD20240102002', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 231, '2024-01-02 10:00:00'),
('ORD20240102003', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 3, '2024-01-02 11:00:00'),
('ORD20240102004', 49.00, 'CNY', 'CANCELLED', 'PRODUCT', '基础视频生成', 209, '2024-01-02 12:00:00'),
('ORD20240102005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 211, '2024-01-02 13:00:00'),
('ORD20240102006', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 212, '2024-01-02 14:00:00'),
('ORD20240102007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 213, '2024-01-02 15:00:00'),
('ORD20240102008', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-01-02 16:00:00'),
('ORD20240102009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-01-02 17:00:00'),
('ORD20240102010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 209, '2024-01-02 18:00:00'),
-- 2024年2月
('ORD20240201001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-02-01 10:00:00'),
('ORD20240201002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-02-01 11:00:00'),
('ORD20240201003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-02-01 11:30:00'),
('ORD20240201004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-02-01 12:00:00'),
('ORD20240201005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-02-01 13:00:00'),
('ORD20240201006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 209, '2024-02-01 14:00:00'),
('ORD20240201007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-02-01 15:00:00'),
('ORD20240201008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-02-01 16:00:00'),
('ORD20240201009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-02-01 17:00:00'),
('ORD20240201010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-02-01 18:00:00'),
('ORD20240202001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-02-02 09:00:00'),
('ORD20240202002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 209, '2024-02-02 10:00:00'),
('ORD20240202003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-02-02 11:00:00'),
('ORD20240202004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-02-02 12:00:00'),
('ORD20240202005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-02-02 13:00:00'),
('ORD20240202006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-02-02 14:00:00'),
('ORD20240202007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-02-02 15:00:00'),
('ORD20240202008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 209, '2024-02-02 16:00:00'),
('ORD20240202009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-02-02 17:00:00'),
('ORD20240202010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-02-02 18:00:00'),
-- 2024年3月
('ORD20240301001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-03-01 10:00:00'),
('ORD20240301002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-03-01 11:00:00'),
('ORD20240301003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-03-01 11:20:00'),
('ORD20240301004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-03-01 12:00:00'),
('ORD20240301005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-03-01 13:00:00'),
('ORD20240301006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 212, '2024-03-01 14:00:00'),
('ORD20240301007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-03-01 15:00:00'),
('ORD20240301008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-03-01 16:00:00'),
('ORD20240301009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-03-01 17:00:00'),
('ORD20240301010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-03-01 18:00:00'),
('ORD20240322001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-03-22 14:30:00'),
('ORD20240322002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 212, '2024-03-22 14:40:00'),
('ORD20240322003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-03-22 14:45:00'),
('ORD20240322004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-03-22 14:50:00'),
('ORD20240322005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-03-22 14:55:00'),
('ORD20240322006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-03-22 15:00:00'),
('ORD20240322007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-03-22 15:05:00'),
('ORD20240322008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 212, '2024-03-22 15:10:00'),
('ORD20240322009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-03-22 15:15:00'),
('ORD20240322010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-03-22 15:20:00'),
-- 2024年4月
('ORD20240401001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-04-01 10:00:00'),
('ORD20240401002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 209, '2024-04-01 11:00:00'),
('ORD20240401003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 211, '2024-04-01 12:00:00'),
('ORD20240401004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 212, '2024-04-01 13:00:00'),
('ORD20240401005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 213, '2024-04-01 14:00:00'),
('ORD20240401006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 231, '2024-04-01 15:00:00'),
('ORD20240401007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-04-01 16:00:00'),
('ORD20240401008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 209, '2024-04-01 17:00:00'),
('ORD20240401009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 211, '2024-04-01 18:00:00'),
('ORD20240401010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 212, '2024-04-01 19:00:00'),
('ORD20240410001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 213, '2024-04-10 14:15:00'),
('ORD20240410002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 231, '2024-04-10 14:18:00'),
('ORD20240410003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-04-10 14:20:00'),
('ORD20240410004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-04-10 14:25:00'),
('ORD20240410005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-04-10 14:30:00'),
('ORD20240410006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 212, '2024-04-10 14:35:00'),
('ORD20240410007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-04-10 14:40:00'),
('ORD20240410008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-04-10 14:45:00'),
('ORD20240410009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-04-10 14:50:00'),
('ORD20240410010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-04-10 14:55:00'),
-- 2024年5月
('ORD20240501001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-05-01 10:00:00'),
('ORD20240501002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-05-01 11:00:00'),
('ORD20240501003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-05-01 11:20:00'),
('ORD20240501004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-05-01 12:00:00'),
('ORD20240501005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-05-01 13:00:00'),
('ORD20240501006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 209, '2024-05-01 14:00:00'),
('ORD20240501007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-05-01 15:00:00'),
('ORD20240501008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-05-01 16:00:00'),
('ORD20240501009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-05-01 17:00:00'),
('ORD20240501010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-05-01 18:00:00'),
('ORD20240525001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-05-25 11:00:00'),
('ORD20240525002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-05-25 11:05:00'),
('ORD20240525003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 211, '2024-05-25 11:10:00'),
('ORD20240525004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-05-25 11:15:00'),
('ORD20240525005', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-05-25 11:20:00'),
('ORD20240525006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 231, '2024-05-25 11:25:00'),
('ORD20240525007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-05-25 11:30:00'),
('ORD20240525008', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-05-25 11:35:00'),
('ORD20240525009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 211, '2024-05-25 11:40:00'),
('ORD20240525010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-05-25 11:45:00'),
-- 2024年6月
('ORD20240601001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-06-01 10:00:00'),
('ORD20240601002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-06-01 11:00:00'),
('ORD20240601003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-06-01 12:00:00'),
('ORD20240601004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-06-01 13:00:00'),
('ORD20240601005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-06-01 14:00:00'),
('ORD20240601006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 212, '2024-06-01 15:00:00'),
('ORD20240601007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-06-01 16:00:00'),
('ORD20240601008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-06-01 17:00:00'),
('ORD20240601009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-06-01 18:00:00'),
('ORD20240601010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-06-01 19:00:00'),
('ORD20240615001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-06-15 14:10:00'),
('ORD20240615002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 212, '2024-06-15 14:12:00'),
('ORD20240615003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-06-15 14:15:00'),
('ORD20240615004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-06-15 14:18:00'),
('ORD20240615005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-06-15 14:20:00'),
('ORD20240615006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 209, '2024-06-15 14:25:00'),
('ORD20240615007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-06-15 14:30:00'),
('ORD20240615008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-06-15 14:35:00'),
('ORD20240615009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-06-15 14:40:00'),
('ORD20240615010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-06-15 14:45:00'),
-- 2024年7月
('ORD20240701001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-07-01 10:00:00'),
('ORD20240701002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 209, '2024-07-01 11:00:00'),
('ORD20240701003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 211, '2024-07-01 12:15:00'),
('ORD20240701004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 212, '2024-07-01 13:00:00'),
('ORD20240701005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 213, '2024-07-01 14:00:00'),
('ORD20240701006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 231, '2024-07-01 15:00:00'),
('ORD20240701007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-07-01 16:00:00'),
('ORD20240701008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 209, '2024-07-01 17:00:00'),
('ORD20240701009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 211, '2024-07-01 18:00:00'),
('ORD20240701010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 212, '2024-07-01 19:00:00'),
('ORD20240720001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 213, '2024-07-20 16:00:00'),
('ORD20240720002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 231, '2024-07-20 16:05:00'),
('ORD20240720003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-07-20 16:10:00'),
('ORD20240720004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 209, '2024-07-20 16:15:00'),
('ORD20240720005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 211, '2024-07-20 16:20:00'),
('ORD20240720006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 212, '2024-07-20 16:25:00'),
('ORD20240720007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 213, '2024-07-20 16:30:00'),
('ORD20240720008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 231, '2024-07-20 16:35:00'),
('ORD20240720009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-07-20 16:40:00'),
('ORD20240720010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 209, '2024-07-20 16:45:00'),
-- 2024年8月
('ORD20240801001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-08-01 10:00:00'),
('ORD20240801002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-08-01 11:00:00'),
('ORD20240801003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-08-01 12:00:00'),
('ORD20240801004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-08-01 13:00:00'),
('ORD20240801005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-08-01 14:00:00'),
('ORD20240801006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 209, '2024-08-01 15:00:00'),
('ORD20240801007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-08-01 16:00:00'),
('ORD20240801008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-08-01 17:00:00'),
('ORD20240801009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-08-01 18:00:00'),
('ORD20240801010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-08-01 19:00:00'),
('ORD20240815001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-08-15 15:00:00'),
('ORD20240815002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 209, '2024-08-15 15:05:00'),
('ORD20240815003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-08-15 15:10:00'),
('ORD20240815004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-08-15 15:15:00'),
('ORD20240815005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-08-15 15:20:00'),
('ORD20240815006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-08-15 15:25:00'),
('ORD20240815007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-08-15 15:30:00'),
('ORD20240815008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 209, '2024-08-15 15:35:00'),
('ORD20240815009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-08-15 15:40:00'),
('ORD20240815010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-08-15 15:45:00'),
-- 2024年9月
('ORD20240901001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-09-01 10:00:00'),
('ORD20240901002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-09-01 11:00:00'),
('ORD20240901003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-09-01 12:00:00'),
('ORD20240901004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-09-01 13:00:00'),
('ORD20240901005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-09-01 14:00:00'),
('ORD20240901006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 212, '2024-09-01 15:00:00'),
('ORD20240901007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-09-01 16:00:00'),
('ORD20240901008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-09-01 17:00:00'),
('ORD20240901009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-09-01 18:00:00'),
('ORD20240901010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-09-01 19:00:00'),
('ORD20240910001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-09-10 17:00:00'),
('ORD20240910002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 212, '2024-09-10 17:05:00'),
('ORD20240910003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-09-10 17:10:00'),
('ORD20240910004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-09-10 17:15:00'),
('ORD20240910005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-09-10 17:20:00'),
('ORD20240910006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-09-10 17:25:00'),
('ORD20240910007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-09-10 17:30:00'),
('ORD20240910008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 212, '2024-09-10 17:35:00'),
('ORD20240910009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-09-10 17:40:00'),
('ORD20240910010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-09-10 17:45:00'),
-- 2024年10月
('ORD20241001001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-10-01 10:00:00'),
('ORD20241001002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 209, '2024-10-01 11:00:00'),
('ORD20241001003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 211, '2024-10-01 12:00:00'),
('ORD20241001004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 212, '2024-10-01 13:00:00'),
('ORD20241001005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 213, '2024-10-01 14:00:00'),
('ORD20241001006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 231, '2024-10-01 15:00:00'),
('ORD20241001007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-10-01 16:00:00'),
('ORD20241001008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 209, '2024-10-01 17:00:00'),
('ORD20241001009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 211, '2024-10-01 18:00:00'),
('ORD20241001010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 212, '2024-10-01 19:00:00'),
('ORD20241020001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 213, '2024-10-20 18:00:00'),
('ORD20241020002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 231, '2024-10-20 18:05:00'),
('ORD20241020003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-10-20 18:10:00'),
('ORD20241020004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 209, '2024-10-20 18:15:00'),
('ORD20241020005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 211, '2024-10-20 18:20:00'),
('ORD20241020006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 212, '2024-10-20 18:25:00'),
('ORD20241020007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 213, '2024-10-20 18:30:00'),
('ORD20241020008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 231, '2024-10-20 18:35:00'),
('ORD20241020009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-10-20 18:40:00'),
('ORD20241020010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 209, '2024-10-20 18:45:00'),
-- 2024年11月
('ORD20241101001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-11-01 10:00:00'),
('ORD20241101002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-11-01 11:00:00'),
('ORD20241101003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-11-01 12:00:00'),
('ORD20241101004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-11-01 13:00:00'),
('ORD20241101005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-11-01 14:00:00'),
('ORD20241101006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 209, '2024-11-01 15:00:00'),
('ORD20241101007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-11-01 16:00:00'),
('ORD20241101008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-11-01 17:00:00'),
('ORD20241101009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-11-01 18:00:00'),
('ORD20241101010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-11-01 19:00:00'),
('ORD20241115001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-11-15 19:00:00'),
('ORD20241115002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 209, '2024-11-15 19:05:00'),
('ORD20241115003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-11-15 19:10:00'),
('ORD20241115004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-11-15 19:15:00'),
('ORD20241115005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 213, '2024-11-15 19:20:00'),
('ORD20241115006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 231, '2024-11-15 19:25:00'),
('ORD20241115007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-11-15 19:30:00'),
('ORD20241115008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 209, '2024-11-15 19:35:00'),
('ORD20241115009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 211, '2024-11-15 19:40:00'),
('ORD20241115010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 212, '2024-11-15 19:45:00'),
-- 2024年12月
('ORD20241201001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-12-01 10:00:00'),
('ORD20241201002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-12-01 11:00:00'),
('ORD20241201003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-12-01 12:00:00'),
('ORD20241201004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-12-01 13:00:00'),
('ORD20241201005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-12-01 14:00:00'),
('ORD20241201006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 212, '2024-12-01 15:00:00'),
('ORD20241201007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-12-01 16:00:00'),
('ORD20241201008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-12-01 17:00:00'),
('ORD20241201009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-12-01 18:00:00'),
('ORD20241201010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-12-01 19:00:00'),
('ORD20241220001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-12-20 20:00:00'),
('ORD20241220002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 212, '2024-12-20 20:05:00'),
('ORD20241220003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-12-20 20:10:00'),
('ORD20241220004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-12-20 20:15:00'),
('ORD20241220005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-12-20 20:20:00'),
('ORD20241220006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 209, '2024-12-20 20:25:00'),
('ORD20241220007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 211, '2024-12-20 20:30:00'),
('ORD20241220008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 212, '2024-12-20 20:35:00'),
('ORD20241220009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 213, '2024-12-20 20:40:00'),
('ORD20241220010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 231, '2024-12-20 20:45:00');

View File

@@ -1,270 +0,0 @@
-- 删除现有订单数据(如果需要重新插入)
-- DELETE FROM payments WHERE order_id IN (SELECT id FROM orders);
-- DELETE FROM order_items WHERE order_id IN (SELECT id FROM orders);
-- DELETE FROM orders;
-- 插入12个月的订单数据
INSERT INTO orders (order_number, total_amount, currency, status, order_type, description, user_id, created_at) VALUES
-- 2024年1月
('ORD20240101001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 1, '2024-01-01 10:00:00'),
('ORD20240101002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-01-01 11:00:00'),
('ORD20240101003', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 3, '2024-01-01 12:00:00'),
('ORD20240101004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-01-01 13:00:00'),
('ORD20240101005', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 5, '2024-01-01 14:00:00'),
('ORD20240101006', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 6, '2024-01-01 15:00:00'),
('ORD20240101007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-01-01 16:00:00'),
('ORD20240101008', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 8, '2024-01-01 17:00:00'),
('ORD20240101009', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 9, '2024-01-01 18:00:00'),
('ORD20240101010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 10, '2024-01-01 19:00:00'),
('ORD20240102001', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 1, '2024-01-02 09:00:00'),
('ORD20240102002', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 2, '2024-01-02 10:00:00'),
('ORD20240102003', 299.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '企业会员订阅', 3, '2024-01-02 11:00:00'),
('ORD20240102004', 49.00, 'CNY', 'CANCELLED', 'PRODUCT', '基础视频生成', 4, '2024-01-02 12:00:00'),
('ORD20240102005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 5, '2024-01-02 13:00:00'),
('ORD20240102006', 99.00, 'CNY', 'COMPLETED', 'PRODUCT', '高级视频编辑', 6, '2024-01-02 14:00:00'),
('ORD20240102007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-01-02 15:00:00'),
('ORD20240102008', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 8, '2024-01-02 16:00:00'),
('ORD20240102009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-01-02 17:00:00'),
('ORD20240102010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 10, '2024-01-02 18:00:00'),
-- 2024年2月
('ORD20240201001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 1, '2024-02-01 10:00:00'),
('ORD20240201002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-02-01 11:00:00'),
('ORD20240201003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-02-01 11:30:00'),
('ORD20240201004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-02-01 12:00:00'),
('ORD20240201005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 5, '2024-02-01 13:00:00'),
('ORD20240201006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-02-01 14:00:00'),
('ORD20240201007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-02-01 15:00:00'),
('ORD20240201008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-02-01 16:00:00'),
('ORD20240201009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-02-01 17:00:00'),
('ORD20240201010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-02-01 18:00:00'),
('ORD20240202001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-02-02 09:00:00'),
('ORD20240202002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-02-02 10:00:00'),
('ORD20240202003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-02-02 11:00:00'),
('ORD20240202004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 4, '2024-02-02 12:00:00'),
('ORD20240202005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 5, '2024-02-02 13:00:00'),
('ORD20240202006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 6, '2024-02-02 14:00:00'),
('ORD20240202007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-02-02 15:00:00'),
('ORD20240202008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-02-02 16:00:00'),
('ORD20240202009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-02-02 17:00:00'),
('ORD20240202010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 10, '2024-02-02 18:00:00'),
-- 2024年3月
('ORD20240301001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 1, '2024-03-01 10:00:00'),
('ORD20240301002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-03-01 11:00:00'),
('ORD20240301003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-03-01 11:20:00'),
('ORD20240301004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-03-01 12:00:00'),
('ORD20240301005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 5, '2024-03-01 13:00:00'),
('ORD20240301006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-03-01 14:00:00'),
('ORD20240301007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-03-01 15:00:00'),
('ORD20240301008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-03-01 16:00:00'),
('ORD20240301009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-03-01 17:00:00'),
('ORD20240301010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-03-01 18:00:00'),
('ORD20240322001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-03-22 14:30:00'),
('ORD20240322002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-03-22 14:40:00'),
('ORD20240322003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-03-22 14:45:00'),
('ORD20240322004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 4, '2024-03-22 14:50:00'),
('ORD20240322005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 5, '2024-03-22 14:55:00'),
('ORD20240322006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 6, '2024-03-22 15:00:00'),
('ORD20240322007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-03-22 15:05:00'),
('ORD20240322008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-03-22 15:10:00'),
('ORD20240322009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-03-22 15:15:00'),
('ORD20240322010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 10, '2024-03-22 15:20:00'),
-- 2024年4月
('ORD20240401001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 1, '2024-04-01 10:00:00'),
('ORD20240401002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-04-01 11:00:00'),
('ORD20240401003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-04-01 12:00:00'),
('ORD20240401004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-04-01 13:00:00'),
('ORD20240401005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 5, '2024-04-01 14:00:00'),
('ORD20240401006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-04-01 15:00:00'),
('ORD20240401007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-04-01 16:00:00'),
('ORD20240401008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-04-01 17:00:00'),
('ORD20240401009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-04-01 18:00:00'),
('ORD20240401010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-04-01 19:00:00'),
('ORD20240410001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-04-10 14:15:00'),
('ORD20240410002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-04-10 14:18:00'),
('ORD20240410003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-04-10 14:20:00'),
('ORD20240410004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-04-10 14:25:00'),
('ORD20240410005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 5, '2024-04-10 14:30:00'),
('ORD20240410006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-04-10 14:35:00'),
('ORD20240410007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-04-10 14:40:00'),
('ORD20240410008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-04-10 14:45:00'),
('ORD20240410009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-04-10 14:50:00'),
('ORD20240410010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-04-10 14:55:00'),
-- 2024年5月
('ORD20240501001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 1, '2024-05-01 10:00:00'),
('ORD20240501002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-05-01 11:00:00'),
('ORD20240501003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-05-01 11:20:00'),
('ORD20240501004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-05-01 12:00:00'),
('ORD20240501005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 5, '2024-05-01 13:00:00'),
('ORD20240501006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-05-01 14:00:00'),
('ORD20240501007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-05-01 15:00:00'),
('ORD20240501008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-05-01 16:00:00'),
('ORD20240501009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-05-01 17:00:00'),
('ORD20240501010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-05-01 18:00:00'),
('ORD20240525001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-05-25 11:00:00'),
('ORD20240525002', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 2, '2024-05-25 11:05:00'),
('ORD20240525003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-05-25 11:10:00'),
('ORD20240525004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 4, '2024-05-25 11:15:00'),
('ORD20240525005', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 5, '2024-05-25 11:20:00'),
('ORD20240525006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-05-25 11:25:00'),
('ORD20240525007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-05-25 11:30:00'),
('ORD20240525008', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 8, '2024-05-25 11:35:00'),
('ORD20240525009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-05-25 11:40:00'),
('ORD20240525010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 10, '2024-05-25 11:45:00'),
-- 2024年6月
('ORD20240601001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 1, '2024-06-01 10:00:00'),
('ORD20240601002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-06-01 11:00:00'),
('ORD20240601003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-06-01 12:00:00'),
('ORD20240601004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-06-01 13:00:00'),
('ORD20240601005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 5, '2024-06-01 14:00:00'),
('ORD20240601006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-06-01 15:00:00'),
('ORD20240601007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-06-01 16:00:00'),
('ORD20240601008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-06-01 17:00:00'),
('ORD20240601009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-06-01 18:00:00'),
('ORD20240601010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-06-01 19:00:00'),
('ORD20240615001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-06-15 14:10:00'),
('ORD20240615002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-06-15 14:12:00'),
('ORD20240615003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-06-15 14:15:00'),
('ORD20240615004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-06-15 14:18:00'),
('ORD20240615005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 5, '2024-06-15 14:20:00'),
('ORD20240615006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-06-15 14:25:00'),
('ORD20240615007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-06-15 14:30:00'),
('ORD20240615008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-06-15 14:35:00'),
('ORD20240615009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-06-15 14:40:00'),
('ORD20240615010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-06-15 14:45:00'),
-- 2024年7月
('ORD20240701001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 1, '2024-07-01 10:00:00'),
('ORD20240701002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-07-01 11:00:00'),
('ORD20240701003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-07-01 12:15:00'),
('ORD20240701004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-07-01 13:00:00'),
('ORD20240701005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 5, '2024-07-01 14:00:00'),
('ORD20240701006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-07-01 15:00:00'),
('ORD20240701007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-07-01 16:00:00'),
('ORD20240701008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-07-01 17:00:00'),
('ORD20240701009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-07-01 18:00:00'),
('ORD20240701010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-07-01 19:00:00'),
('ORD20240720001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-07-20 16:00:00'),
('ORD20240720002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-07-20 16:05:00'),
('ORD20240720003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-07-20 16:10:00'),
('ORD20240720004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 4, '2024-07-20 16:15:00'),
('ORD20240720005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 5, '2024-07-20 16:20:00'),
('ORD20240720006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 6, '2024-07-20 16:25:00'),
('ORD20240720007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-07-20 16:30:00'),
('ORD20240720008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-07-20 16:35:00'),
('ORD20240720009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-07-20 16:40:00'),
('ORD20240720010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 10, '2024-07-20 16:45:00'),
-- 2024年8月
('ORD20240801001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 1, '2024-08-01 10:00:00'),
('ORD20240801002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-08-01 11:00:00'),
('ORD20240801003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-08-01 12:00:00'),
('ORD20240801004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-08-01 13:00:00'),
('ORD20240801005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 5, '2024-08-01 14:00:00'),
('ORD20240801006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-08-01 15:00:00'),
('ORD20240801007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-08-01 16:00:00'),
('ORD20240801008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-08-01 17:00:00'),
('ORD20240801009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-08-01 18:00:00'),
('ORD20240801010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-08-01 19:00:00'),
('ORD20240815001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-08-15 15:00:00'),
('ORD20240815002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-08-15 15:05:00'),
('ORD20240815003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-08-15 15:10:00'),
('ORD20240815004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 4, '2024-08-15 15:15:00'),
('ORD20240815005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 5, '2024-08-15 15:20:00'),
('ORD20240815006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 6, '2024-08-15 15:25:00'),
('ORD20240815007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-08-15 15:30:00'),
('ORD20240815008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-08-15 15:35:00'),
('ORD20240815009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-08-15 15:40:00'),
('ORD20240815010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 10, '2024-08-15 15:45:00'),
-- 2024年9月
('ORD20240901001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 1, '2024-09-01 10:00:00'),
('ORD20240901002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-09-01 11:00:00'),
('ORD20240901003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-09-01 12:00:00'),
('ORD20240901004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-09-01 13:00:00'),
('ORD20240901005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 5, '2024-09-01 14:00:00'),
('ORD20240901006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-09-01 15:00:00'),
('ORD20240901007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-09-01 16:00:00'),
('ORD20240901008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-09-01 17:00:00'),
('ORD20240901009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-09-01 18:00:00'),
('ORD20240901010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-09-01 19:00:00'),
('ORD20240910001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-09-10 17:00:00'),
('ORD20240910002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-09-10 17:05:00'),
('ORD20240910003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-09-10 17:10:00'),
('ORD20240910004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 4, '2024-09-10 17:15:00'),
('ORD20240910005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 5, '2024-09-10 17:20:00'),
('ORD20240910006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 6, '2024-09-10 17:25:00'),
('ORD20240910007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-09-10 17:30:00'),
('ORD20240910008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-09-10 17:35:00'),
('ORD20240910009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-09-10 17:40:00'),
('ORD20240910010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 10, '2024-09-10 17:45:00'),
-- 2024年10月
('ORD20241001001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 1, '2024-10-01 10:00:00'),
('ORD20241001002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-10-01 11:00:00'),
('ORD20241001003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-10-01 12:00:00'),
('ORD20241001004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-10-01 13:00:00'),
('ORD20241001005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 5, '2024-10-01 14:00:00'),
('ORD20241001006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-10-01 15:00:00'),
('ORD20241001007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-10-01 16:00:00'),
('ORD20241001008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-10-01 17:00:00'),
('ORD20241001009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-10-01 18:00:00'),
('ORD20241001010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-10-01 19:00:00'),
('ORD20241020001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-10-20 18:00:00'),
('ORD20241020002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-10-20 18:05:00'),
('ORD20241020003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-10-20 18:10:00'),
('ORD20241020004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 4, '2024-10-20 18:15:00'),
('ORD20241020005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 5, '2024-10-20 18:20:00'),
('ORD20241020006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 6, '2024-10-20 18:25:00'),
('ORD20241020007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-10-20 18:30:00'),
('ORD20241020008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-10-20 18:35:00'),
('ORD20241020009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-10-20 18:40:00'),
('ORD20241020010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 10, '2024-10-20 18:45:00'),
-- 2024年11月
('ORD20241101001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 1, '2024-11-01 10:00:00'),
('ORD20241101002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-11-01 11:00:00'),
('ORD20241101003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-11-01 12:00:00'),
('ORD20241101004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-11-01 13:00:00'),
('ORD20241101005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 5, '2024-11-01 14:00:00'),
('ORD20241101006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-11-01 15:00:00'),
('ORD20241101007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-11-01 16:00:00'),
('ORD20241101008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-11-01 17:00:00'),
('ORD20241101009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-11-01 18:00:00'),
('ORD20241101010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-11-01 19:00:00'),
('ORD20241115001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-11-15 19:00:00'),
('ORD20241115002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-11-15 19:05:00'),
('ORD20241115003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-11-15 19:10:00'),
('ORD20241115004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 4, '2024-11-15 19:15:00'),
('ORD20241115005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 5, '2024-11-15 19:20:00'),
('ORD20241115006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 6, '2024-11-15 19:25:00'),
('ORD20241115007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-11-15 19:30:00'),
('ORD20241115008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-11-15 19:35:00'),
('ORD20241115009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-11-15 19:40:00'),
('ORD20241115010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 10, '2024-11-15 19:45:00'),
-- 2024年12月
('ORD20241201001', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 1, '2024-12-01 10:00:00'),
('ORD20241201002', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 2, '2024-12-01 11:00:00'),
('ORD20241201003', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 3, '2024-12-01 12:00:00'),
('ORD20241201004', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 4, '2024-12-01 13:00:00'),
('ORD20241201005', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 5, '2024-12-01 14:00:00'),
('ORD20241201006', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 6, '2024-12-01 15:00:00'),
('ORD20241201007', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 7, '2024-12-01 16:00:00'),
('ORD20241201008', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 8, '2024-12-01 17:00:00'),
('ORD20241201009', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 9, '2024-12-01 18:00:00'),
('ORD20241201010', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 10, '2024-12-01 19:00:00'),
('ORD20241220001', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 1, '2024-12-20 20:00:00'),
('ORD20241220002', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 2, '2024-12-20 20:05:00'),
('ORD20241220003', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 3, '2024-12-20 20:10:00'),
('ORD20241220004', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 4, '2024-12-20 20:15:00'),
('ORD20241220005', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 5, '2024-12-20 20:20:00'),
('ORD20241220006', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 6, '2024-12-20 20:25:00'),
('ORD20241220007', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 7, '2024-12-20 20:30:00'),
('ORD20241220008', 199.00, 'CNY', 'COMPLETED', 'PRODUCT', '视频生成服务包', 8, '2024-12-20 20:35:00'),
('ORD20241220009', 99.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '专业会员订阅', 9, '2024-12-20 20:40:00'),
('ORD20241220010', 29.00, 'CNY', 'COMPLETED', 'MEMBERSHIP', '标准会员订阅', 10, '2024-12-20 20:45:00');

View File

@@ -1,207 +0,0 @@
-- 12个月支付数据
-- 对应orders_12months.sql中的订单
INSERT IGNORE INTO payments (order_id, amount, currency, payment_method, status, description, user_id, created_at, paid_at) VALUES
-- 2024年1月支付数据
('ORD20240101001', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 1, '2024-01-01 10:00:00', '2024-01-01 10:05:00'),
('ORD20240101002', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 2, '2024-01-01 11:00:00', '2024-01-01 11:02:00'),
('ORD20240101003', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 3, '2024-01-01 12:00:00', '2024-01-01 12:03:00'),
('ORD20240101004', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 4, '2024-01-01 13:00:00', '2024-01-01 13:04:00'),
('ORD20240101005', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 5, '2024-01-01 14:00:00', '2024-01-01 14:05:00'),
('ORD20240101006', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 6, '2024-01-01 15:00:00', '2024-01-01 15:02:00'),
('ORD20240101007', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 7, '2024-01-01 16:00:00', '2024-01-01 16:03:00'),
('ORD20240101008', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 8, '2024-01-01 17:00:00', '2024-01-01 17:04:00'),
('ORD20240101009', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 9, '2024-01-01 18:00:00', '2024-01-01 18:02:00'),
('ORD20240101010', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 10, '2024-01-01 19:00:00', '2024-01-01 19:03:00'),
('ORD20240102001', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 1, '2024-01-02 09:00:00', '2024-01-02 09:05:00'),
('ORD20240102002', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '高级视频编辑', 2, '2024-01-02 10:00:00', '2024-01-02 10:03:00'),
('ORD20240102003', 299.00, 'CNY', 'ALIPAY', 'COMPLETED', '企业会员订阅', 3, '2024-01-02 11:00:00', '2024-01-02 11:05:00'),
('ORD20240102004', 49.00, 'CNY', 'WECHAT', 'CANCELLED', '基础视频生成', 4, '2024-01-02 12:00:00', NULL),
('ORD20240102005', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 5, '2024-01-02 13:00:00', '2024-01-02 13:04:00'),
('ORD20240115001', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 6, '2024-01-15 14:30:00', '2024-01-15 14:35:00'),
('ORD20240115002', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '高级视频编辑', 7, '2024-01-15 15:45:00', '2024-01-15 15:48:00'),
('ORD20240115003', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 8, '2024-01-15 16:20:00', '2024-01-15 16:22:00'),
('ORD20240128001', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 9, '2024-01-28 10:15:00', '2024-01-28 10:19:00'),
('ORD20240128002', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 10, '2024-01-28 11:30:00', '2024-01-28 11:34:00'),
-- 2024年2月支付数据
('ORD20240201001', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 1, '2024-02-01 09:00:00', '2024-02-01 09:02:00'),
('ORD20240201002', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 2, '2024-02-01 10:15:00', '2024-02-01 10:19:00'),
('ORD20240201003', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 3, '2024-02-01 11:30:00', '2024-02-01 11:35:00'),
('ORD20240201004', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 4, '2024-02-01 14:20:00', '2024-02-01 14:24:00'),
('ORD20240201005', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '高级视频编辑', 5, '2024-02-01 15:45:00', '2024-02-01 15:48:00'),
('ORD20240214001', 299.00, 'CNY', 'WECHAT', 'COMPLETED', '企业会员订阅', 6, '2024-02-14 10:00:00', '2024-02-14 10:05:00'),
('ORD20240214002', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 7, '2024-02-14 11:30:00', '2024-02-14 11:32:00'),
('ORD20240214003', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 8, '2024-02-14 14:15:00', '2024-02-14 14:20:00'),
('ORD20240225001', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 9, '2024-02-25 16:00:00', '2024-02-25 16:04:00'),
('ORD20240225002', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 10, '2024-02-25 17:30:00', '2024-02-25 17:34:00'),
-- 2024年3月支付数据
('ORD20240301001', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 1, '2024-03-01 09:30:00', '2024-03-01 09:32:00'),
('ORD20240301002', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 2, '2024-03-01 10:45:00', '2024-03-01 10:49:00'),
('ORD20240301003', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 3, '2024-03-01 11:20:00', '2024-03-01 11:25:00'),
('ORD20240301004', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 4, '2024-03-01 14:10:00', '2024-03-01 14:14:00'),
('ORD20240301005', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '高级视频编辑', 5, '2024-03-01 15:25:00', '2024-03-01 15:28:00'),
('ORD20240308001', 299.00, 'CNY', 'ALIPAY', 'COMPLETED', '企业会员订阅', 6, '2024-03-08 10:00:00', '2024-03-08 10:05:00'),
('ORD20240308002', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 7, '2024-03-08 11:15:00', '2024-03-08 11:17:00'),
('ORD20240308003', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 8, '2024-03-08 14:30:00', '2024-03-08 14:35:00'),
('ORD20240315001', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 9, '2024-03-15 16:45:00', '2024-03-15 16:49:00'),
('ORD20240315002', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 10, '2024-03-15 17:20:00', '2024-03-15 17:24:00'),
('ORD20240322001', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 1, '2024-03-22 09:15:00', '2024-03-22 09:17:00'),
('ORD20240322002', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 2, '2024-03-22 10:30:00', '2024-03-22 10:35:00'),
('ORD20240322003', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '高级视频编辑', 3, '2024-03-22 14:45:00', '2024-03-22 14:48:00'),
('ORD20240330001', 299.00, 'CNY', 'ALIPAY', 'COMPLETED', '企业会员订阅', 4, '2024-03-30 11:00:00', '2024-03-30 11:05:00'),
('ORD20240330002', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 5, '2024-03-30 15:30:00', '2024-03-30 15:34:00'),
-- 2024年4月支付数据
('ORD20240401001', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 6, '2024-04-01 09:00:00', '2024-04-01 09:02:00'),
('ORD20240401002', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 7, '2024-04-01 10:20:00', '2024-04-01 10:24:00'),
('ORD20240401003', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 8, '2024-04-01 11:40:00', '2024-04-01 11:45:00'),
('ORD20240401004', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 9, '2024-04-01 14:15:00', '2024-04-01 14:19:00'),
('ORD20240401005', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '高级视频编辑', 10, '2024-04-01 15:35:00', '2024-04-01 15:38:00'),
('ORD20240410001', 299.00, 'CNY', 'WECHAT', 'COMPLETED', '企业会员订阅', 1, '2024-04-10 10:30:00', '2024-04-10 10:35:00'),
('ORD20240410002', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 2, '2024-04-10 11:45:00', '2024-04-10 11:47:00'),
('ORD20240410003', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 3, '2024-04-10 14:20:00', '2024-04-10 14:25:00'),
('ORD20240420001', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 4, '2024-04-20 16:10:00', '2024-04-20 16:14:00'),
('ORD20240420002', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 5, '2024-04-20 17:25:00', '2024-04-20 17:29:00'),
('ORD20240420003', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 6, '2024-04-20 18:40:00', '2024-04-20 18:42:00'),
('ORD20240425001', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 7, '2024-04-25 09:15:00', '2024-04-25 09:20:00'),
('ORD20240425002', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '高级视频编辑', 8, '2024-04-25 10:30:00', '2024-04-25 10:33:00'),
('ORD20240425003', 299.00, 'CNY', 'WECHAT', 'COMPLETED', '企业会员订阅', 9, '2024-04-25 14:45:00', '2024-04-25 14:50:00'),
('ORD20240430001', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 10, '2024-04-30 15:20:00', '2024-04-30 15:24:00'),
-- 2024年5月支付数据
('ORD20240501001', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 1, '2024-05-01 09:30:00', '2024-05-01 09:32:00'),
('ORD20240501002', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 2, '2024-05-01 10:45:00', '2024-05-01 10:49:00'),
('ORD20240501003', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 3, '2024-05-01 11:20:00', '2024-05-01 11:25:00'),
('ORD20240501004', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 4, '2024-05-01 14:10:00', '2024-05-01 14:14:00'),
('ORD20240501005', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '高级视频编辑', 5, '2024-05-01 15:25:00', '2024-05-01 15:28:00'),
('ORD20240510001', 299.00, 'CNY', 'ALIPAY', 'COMPLETED', '企业会员订阅', 6, '2024-05-10 10:00:00', '2024-05-10 10:05:00'),
('ORD20240510002', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 7, '2024-05-10 11:15:00', '2024-05-10 11:17:00'),
('ORD20240510003', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 8, '2024-05-10 14:30:00', '2024-05-10 14:35:00'),
('ORD20240520001', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 9, '2024-05-20 16:45:00', '2024-05-20 16:49:00'),
('ORD20240520002', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 10, '2024-05-20 17:20:00', '2024-05-20 17:24:00'),
('ORD20240520003', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 1, '2024-05-20 18:35:00', '2024-05-20 18:37:00'),
('ORD20240525001', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 2, '2024-05-25 09:50:00', '2024-05-25 09:55:00'),
('ORD20240525002', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '高级视频编辑', 3, '2024-05-25 11:05:00', '2024-05-25 11:08:00'),
('ORD20240525003', 299.00, 'CNY', 'ALIPAY', 'COMPLETED', '企业会员订阅', 4, '2024-05-25 14:20:00', '2024-05-25 14:25:00'),
('ORD20240530001', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 5, '2024-05-30 15:35:00', '2024-05-30 15:39:00'),
-- 2024年6月支付数据
('ORD20240601001', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 6, '2024-06-01 09:15:00', '2024-06-01 09:17:00'),
('ORD20240601002', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 7, '2024-06-01 10:30:00', '2024-06-01 10:34:00'),
('ORD20240601003', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 8, '2024-06-01 11:45:00', '2024-06-01 11:50:00'),
('ORD20240601004', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 9, '2024-06-01 14:00:00', '2024-06-01 14:04:00'),
('ORD20240601005', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '高级视频编辑', 10, '2024-06-01 15:15:00', '2024-06-01 15:18:00'),
('ORD20240615001', 299.00, 'CNY', 'WECHAT', 'COMPLETED', '企业会员订阅', 1, '2024-06-15 10:45:00', '2024-06-15 10:50:00'),
('ORD20240615002', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 2, '2024-06-15 12:00:00', '2024-06-15 12:02:00'),
('ORD20240615003', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 3, '2024-06-15 14:15:00', '2024-06-15 14:20:00'),
('ORD20240620001', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 4, '2024-06-20 16:30:00', '2024-06-20 16:34:00'),
('ORD20240620002', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 5, '2024-06-20 17:45:00', '2024-06-20 17:49:00'),
('ORD20240620003', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 6, '2024-06-20 19:00:00', '2024-06-20 19:02:00'),
('ORD20240625001', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 7, '2024-06-25 09:30:00', '2024-06-25 09:35:00'),
('ORD20240625002', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '高级视频编辑', 8, '2024-06-25 10:45:00', '2024-06-25 10:48:00'),
('ORD20240625003', 299.00, 'CNY', 'WECHAT', 'COMPLETED', '企业会员订阅', 9, '2024-06-25 14:00:00', '2024-06-25 14:05:00'),
('ORD20240630001', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 10, '2024-06-30 15:15:00', '2024-06-30 15:19:00'),
-- 2024年7月支付数据
('ORD20240701001', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 1, '2024-07-01 09:45:00', '2024-07-01 09:47:00'),
('ORD20240701002', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 2, '2024-07-01 11:00:00', '2024-07-01 11:04:00'),
('ORD20240701003', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 3, '2024-07-01 12:15:00', '2024-07-01 12:20:00'),
('ORD20240701004', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 4, '2024-07-01 14:30:00', '2024-07-01 14:34:00'),
('ORD20240701005', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '高级视频编辑', 5, '2024-07-01 15:45:00', '2024-07-01 15:48:00'),
('ORD20240710001', 299.00, 'CNY', 'ALIPAY', 'COMPLETED', '企业会员订阅', 6, '2024-07-10 10:20:00', '2024-07-10 10:25:00'),
('ORD20240710002', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 7, '2024-07-10 11:35:00', '2024-07-10 11:37:00'),
('ORD20240710003', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 8, '2024-07-10 14:50:00', '2024-07-10 14:55:00'),
('ORD20240720001', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 9, '2024-07-20 16:05:00', '2024-07-20 16:09:00'),
('ORD20240720002', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 10, '2024-07-20 17:20:00', '2024-07-20 17:24:00'),
('ORD20240720003', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 1, '2024-07-20 18:35:00', '2024-07-20 18:37:00'),
('ORD20240725001', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 2, '2024-07-25 09:50:00', '2024-07-25 09:55:00'),
('ORD20240725002', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '高级视频编辑', 3, '2024-07-25 11:05:00', '2024-07-25 11:08:00'),
('ORD20240725003', 299.00, 'CNY', 'ALIPAY', 'COMPLETED', '企业会员订阅', 4, '2024-07-25 14:20:00', '2024-07-25 14:25:00'),
('ORD20240730001', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 5, '2024-07-30 15:35:00', '2024-07-30 15:39:00'),
-- 2024年8月支付数据
('ORD20240801001', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 6, '2024-08-01 09:30:00', '2024-08-01 09:32:00'),
('ORD20240801002', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 7, '2024-08-01 10:45:00', '2024-08-01 10:49:00'),
('ORD20240801003', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 8, '2024-08-01 12:00:00', '2024-08-01 12:05:00'),
('ORD20240801004', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 9, '2024-08-01 14:15:00', '2024-08-01 14:19:00'),
('ORD20240801005', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '高级视频编辑', 10, '2024-08-01 15:30:00', '2024-08-01 15:33:00'),
('ORD20240810001', 299.00, 'CNY', 'WECHAT', 'COMPLETED', '企业会员订阅', 1, '2024-08-10 10:00:00', '2024-08-10 10:05:00'),
('ORD20240810002', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 2, '2024-08-10 11:15:00', '2024-08-10 11:17:00'),
('ORD20240810003', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 3, '2024-08-10 14:30:00', '2024-08-10 14:35:00'),
('ORD20240820001', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 4, '2024-08-20 16:45:00', '2024-08-20 16:49:00'),
('ORD20240820002', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 5, '2024-08-20 18:00:00', '2024-08-20 18:04:00'),
('ORD20240820003', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 6, '2024-08-20 19:15:00', '2024-08-20 19:17:00'),
('ORD20240825001', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 7, '2024-08-25 09:30:00', '2024-08-25 09:35:00'),
('ORD20240825002', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '高级视频编辑', 8, '2024-08-25 10:45:00', '2024-08-25 10:48:00'),
('ORD20240825003', 299.00, 'CNY', 'WECHAT', 'COMPLETED', '企业会员订阅', 9, '2024-08-25 14:00:00', '2024-08-25 14:05:00'),
('ORD20240830001', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 10, '2024-08-30 15:15:00', '2024-08-30 15:19:00'),
-- 2024年9月支付数据
('ORD20240901001', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 1, '2024-09-01 09:15:00', '2024-09-01 09:17:00'),
('ORD20240901002', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 2, '2024-09-01 10:30:00', '2024-09-01 10:34:00'),
('ORD20240901003', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 3, '2024-09-01 11:45:00', '2024-09-01 11:50:00'),
('ORD20240901004', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 4, '2024-09-01 14:00:00', '2024-09-01 14:04:00'),
('ORD20240901005', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '高级视频编辑', 5, '2024-09-01 15:15:00', '2024-09-01 15:18:00'),
('ORD20240910001', 299.00, 'CNY', 'ALIPAY', 'COMPLETED', '企业会员订阅', 6, '2024-09-10 10:45:00', '2024-09-10 10:50:00'),
('ORD20240910002', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 7, '2024-09-10 12:00:00', '2024-09-10 12:02:00'),
('ORD20240910003', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 8, '2024-09-10 14:15:00', '2024-09-10 14:20:00'),
('ORD20240920001', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 9, '2024-09-20 16:30:00', '2024-09-20 16:34:00'),
('ORD20240920002', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 10, '2024-09-20 17:45:00', '2024-09-20 17:49:00'),
('ORD20240920003', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 1, '2024-09-20 19:00:00', '2024-09-20 19:02:00'),
('ORD20240925001', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 2, '2024-09-25 09:15:00', '2024-09-25 09:20:00'),
('ORD20240925002', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '高级视频编辑', 3, '2024-09-25 10:30:00', '2024-09-25 10:33:00'),
('ORD20240925003', 299.00, 'CNY', 'ALIPAY', 'COMPLETED', '企业会员订阅', 4, '2024-09-25 14:45:00', '2024-09-25 14:50:00'),
('ORD20240930001', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 5, '2024-09-30 15:00:00', '2024-09-30 15:04:00'),
-- 2024年10月支付数据
('ORD20241001001', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 6, '2024-10-01 09:45:00', '2024-10-01 09:47:00'),
('ORD20241001002', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 7, '2024-10-01 11:00:00', '2024-10-01 11:04:00'),
('ORD20241001003', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 8, '2024-10-01 12:15:00', '2024-10-01 12:20:00'),
('ORD20241001004', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 9, '2024-10-01 14:30:00', '2024-10-01 14:34:00'),
('ORD20241001005', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '高级视频编辑', 10, '2024-10-01 15:45:00', '2024-10-01 15:48:00'),
('ORD20241010001', 299.00, 'CNY', 'WECHAT', 'COMPLETED', '企业会员订阅', 1, '2024-10-10 10:20:00', '2024-10-10 10:25:00'),
('ORD20241010002', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 2, '2024-10-10 11:35:00', '2024-10-10 11:37:00'),
('ORD20241010003', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 3, '2024-10-10 14:50:00', '2024-10-10 14:55:00'),
('ORD20241020001', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 4, '2024-10-20 16:05:00', '2024-10-20 16:09:00'),
('ORD20241020002', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 5, '2024-10-20 17:20:00', '2024-10-20 17:24:00'),
('ORD20241020003', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 6, '2024-10-20 18:35:00', '2024-10-20 18:37:00'),
('ORD20241025001', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 7, '2024-10-25 09:50:00', '2024-10-25 09:55:00'),
('ORD20241025002', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '高级视频编辑', 8, '2024-10-25 11:05:00', '2024-10-25 11:08:00'),
('ORD20241025003', 299.00, 'CNY', 'WECHAT', 'COMPLETED', '企业会员订阅', 9, '2024-10-25 14:20:00', '2024-10-25 14:25:00'),
('ORD20241030001', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 10, '2024-10-30 15:35:00', '2024-10-30 15:39:00'),
-- 2024年11月支付数据
('ORD20241101001', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 1, '2024-11-01 09:30:00', '2024-11-01 09:32:00'),
('ORD20241101002', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 2, '2024-11-01 10:45:00', '2024-11-01 10:49:00'),
('ORD20241101003', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 3, '2024-11-01 12:00:00', '2024-11-01 12:05:00'),
('ORD20241101004', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 4, '2024-11-01 14:15:00', '2024-11-01 14:19:00'),
('ORD20241101005', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '高级视频编辑', 5, '2024-11-01 15:30:00', '2024-11-01 15:33:00'),
('ORD20241111001', 299.00, 'CNY', 'ALIPAY', 'COMPLETED', '企业会员订阅', 6, '2024-11-11 10:00:00', '2024-11-11 10:05:00'),
('ORD20241111002', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 7, '2024-11-11 11:15:00', '2024-11-11 11:17:00'),
('ORD20241111003', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 8, '2024-11-11 14:30:00', '2024-11-11 14:35:00'),
('ORD20241120001', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 9, '2024-11-20 16:45:00', '2024-11-20 16:49:00'),
('ORD20241120002', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 10, '2024-11-20 18:00:00', '2024-11-20 18:04:00'),
('ORD20241120003', 29.00, 'CNY', 'WECHAT', 'COMPLETED', '标准会员订阅', 1, '2024-11-20 19:15:00', '2024-11-20 19:17:00'),
('ORD20241125001', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 2, '2024-11-25 09:30:00', '2024-11-25 09:35:00'),
('ORD20241125002', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '高级视频编辑', 3, '2024-11-25 10:45:00', '2024-11-25 10:48:00'),
('ORD20241125003', 299.00, 'CNY', 'ALIPAY', 'COMPLETED', '企业会员订阅', 4, '2024-11-25 14:00:00', '2024-11-25 14:05:00'),
('ORD20241130001', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 5, '2024-11-30 15:15:00', '2024-11-30 15:19:00'),
-- 2024年12月支付数据
('ORD20241201001', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 6, '2024-12-01 09:15:00', '2024-12-01 09:17:00'),
('ORD20241201002', 99.00, 'CNY', 'WECHAT', 'COMPLETED', '专业会员订阅', 7, '2024-12-01 10:30:00', '2024-12-01 10:34:00'),
('ORD20241201003', 199.00, 'CNY', 'ALIPAY', 'COMPLETED', '视频生成服务包', 8, '2024-12-01 11:45:00', '2024-12-01 11:50:00'),
('ORD20241201004', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 9, '2024-12-01 14:00:00', '2024-12-01 14:04:00'),
('ORD20241201005', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '高级视频编辑', 10, '2024-12-01 15:15:00', '2024-12-01 15:18:00'),
('ORD20241210001', 299.00, 'CNY', 'WECHAT', 'COMPLETED', '企业会员订阅', 1, '2024-12-10 10:45:00', '2024-12-10 10:50:00'),
('ORD20241210002', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 2, '2024-12-10 12:00:00', '2024-12-10 12:02:00'),
('ORD20241210003', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 3, '2024-12-10 14:15:00', '2024-12-10 14:20:00'),
('ORD20241220001', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业会员订阅', 4, '2024-12-20 16:30:00', '2024-12-20 16:34:00'),
('ORD20241220002', 149.00, 'CNY', 'WECHAT', 'COMPLETED', '专业视频制作', 5, '2024-12-20 17:45:00', '2024-12-20 17:49:00'),
('ORD20241220003', 29.00, 'CNY', 'ALIPAY', 'COMPLETED', '标准会员订阅', 6, '2024-12-20 19:00:00', '2024-12-20 19:02:00'),
('ORD20241225001', 199.00, 'CNY', 'WECHAT', 'COMPLETED', '视频生成服务包', 7, '2024-12-25 09:15:00', '2024-12-25 09:20:00'),
('ORD20241225002', 99.00, 'CNY', 'ALIPAY', 'COMPLETED', '高级视频编辑', 8, '2024-12-25 10:30:00', '2024-12-25 10:33:00'),
('ORD20241225003', 299.00, 'CNY', 'WECHAT', 'COMPLETED', '企业会员订阅', 9, '2024-12-25 14:45:00', '2024-12-25 14:50:00'),
('ORD20241230001', 149.00, 'CNY', 'ALIPAY', 'COMPLETED', '专业视频制作', 10, '2024-12-30 15:00:00', '2024-12-30 15:04:00');

View File

@@ -1,24 +0,0 @@
-- 插入支付数据
INSERT INTO payments (order_id, user_id, amount, currency, payment_method, status, external_transaction_id, paid_at, created_at)
SELECT
o.id as order_id,
o.user_id,
o.total_amount as amount,
o.currency,
CASE
WHEN RAND() < 0.6 THEN 'ALIPAY'
WHEN RAND() < 0.8 THEN 'WECHAT'
ELSE 'PAYPAL'
END as payment_method,
CASE
WHEN o.status = 'COMPLETED' THEN 'COMPLETED'
WHEN o.status = 'CANCELLED' THEN 'CANCELLED'
ELSE 'PENDING'
END as status,
CONCAT('TXN_', UNIX_TIMESTAMP(o.created_at), '_', o.id) as external_transaction_id,
CASE
WHEN o.status = 'COMPLETED' THEN DATE_ADD(o.created_at, INTERVAL FLOOR(RAND() * 30) MINUTE)
ELSE NULL
END as paid_at,
o.created_at
FROM orders o;

View File

@@ -580,6 +580,10 @@

View File

@@ -496,6 +496,10 @@

View File

@@ -535,6 +535,10 @@

View File

@@ -1,407 +0,0 @@
-- 用户活跃度统计表
CREATE TABLE IF NOT EXISTS user_activity_stats (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
stat_date DATE NOT NULL COMMENT '统计日期',
daily_active_users INT NOT NULL DEFAULT 0 COMMENT '日活用户数',
monthly_active_users INT NOT NULL DEFAULT 0 COMMENT '月活用户数',
new_users INT NOT NULL DEFAULT 0 COMMENT '新增用户数',
returning_users INT NOT NULL DEFAULT 0 COMMENT '回访用户数',
session_count INT NOT NULL DEFAULT 0 COMMENT '会话数',
avg_session_duration DECIMAL(10,2) DEFAULT 0 COMMENT '平均会话时长(分钟)',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uk_stat_date (stat_date),
INDEX idx_stat_date (stat_date)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户活跃度统计表';
-- 插入2024年全年日活数据模拟真实趋势
INSERT IGNORE INTO user_activity_stats (stat_date, daily_active_users, monthly_active_users, new_users, returning_users, session_count, avg_session_duration) VALUES
-- 1月数据
('2024-01-01', 1200, 15000, 50, 1150, 1800, 25.5),
('2024-01-02', 1350, 15200, 45, 1305, 2000, 28.2),
('2024-01-03', 1100, 15400, 40, 1060, 1650, 24.8),
('2024-01-04', 1250, 15600, 55, 1195, 1900, 26.7),
('2024-01-05', 1400, 15800, 60, 1340, 2100, 29.1),
('2024-01-06', 1300, 16000, 50, 1250, 1950, 27.3),
('2024-01-07', 1150, 16200, 45, 1105, 1725, 25.9),
('2024-01-08', 1200, 16400, 55, 1145, 1800, 26.4),
('2024-01-09', 1350, 16600, 65, 1285, 2025, 28.7),
('2024-01-10', 1450, 16800, 70, 1380, 2175, 30.2),
('2024-01-11', 1300, 17000, 60, 1240, 1950, 27.8),
('2024-01-12', 1250, 17200, 55, 1195, 1875, 27.1),
('2024-01-13', 1400, 17400, 75, 1325, 2100, 29.5),
('2024-01-14', 1500, 17600, 80, 1420, 2250, 31.2),
('2024-01-15', 1350, 17800, 65, 1285, 2025, 28.9),
('2024-01-16', 1200, 18000, 50, 1150, 1800, 26.7),
('2024-01-17', 1100, 18200, 45, 1055, 1650, 25.3),
('2024-01-18', 1250, 18400, 60, 1190, 1875, 27.6),
('2024-01-19', 1400, 18600, 70, 1330, 2100, 29.8),
('2024-01-20', 1450, 18800, 75, 1375, 2175, 30.5),
('2024-01-21', 1300, 19000, 60, 1240, 1950, 28.2),
('2024-01-22', 1200, 19200, 55, 1145, 1800, 27.0),
('2024-01-23', 1150, 19400, 50, 1100, 1725, 26.4),
('2024-01-24', 1250, 19600, 65, 1185, 1875, 28.1),
('2024-01-25', 1350, 19800, 70, 1280, 2025, 29.7),
('2024-01-26', 1400, 20000, 75, 1325, 2100, 30.3),
('2024-01-27', 1300, 20200, 65, 1235, 1950, 28.8),
('2024-01-28', 1250, 20400, 60, 1190, 1875, 28.2),
('2024-01-29', 1200, 20600, 55, 1145, 1800, 27.5),
('2024-01-30', 1150, 20800, 50, 1100, 1725, 26.9),
('2024-01-31', 1100, 21000, 45, 1055, 1650, 26.2),
-- 2月数据春节影响数据波动较大
('2024-02-01', 1000, 21200, 40, 960, 1500, 24.8),
('2024-02-02', 950, 21400, 35, 915, 1425, 24.1),
('2024-02-03', 900, 21600, 30, 870, 1350, 23.5),
('2024-02-04', 850, 21800, 25, 825, 1275, 22.9),
('2024-02-05', 800, 22000, 20, 780, 1200, 22.2),
('2024-02-06', 750, 22200, 15, 735, 1125, 21.6),
('2024-02-07', 700, 22400, 10, 690, 1050, 21.0),
('2024-02-08', 650, 22600, 8, 642, 975, 20.4),
('2024-02-09', 600, 22800, 5, 595, 900, 19.8),
('2024-02-10', 550, 23000, 3, 547, 825, 19.2),
('2024-02-11', 500, 23200, 2, 498, 750, 18.6),
('2024-02-12', 450, 23400, 1, 449, 675, 18.0),
('2024-02-13', 400, 23600, 1, 399, 600, 17.4),
('2024-02-14', 350, 23800, 1, 349, 525, 16.8),
('2024-02-15', 300, 24000, 1, 299, 450, 16.2),
('2024-02-16', 250, 24200, 1, 249, 375, 15.6),
('2024-02-17', 200, 24400, 1, 199, 300, 15.0),
('2024-02-18', 150, 24600, 1, 149, 225, 14.4),
('2024-02-19', 100, 24800, 1, 99, 150, 13.8),
('2024-02-20', 80, 25000, 1, 79, 120, 13.2),
('2024-02-21', 60, 25200, 1, 59, 90, 12.6),
('2024-02-22', 50, 25400, 1, 49, 75, 12.0),
('2024-02-23', 40, 25600, 1, 39, 60, 11.4),
('2024-02-24', 30, 25800, 1, 29, 45, 10.8),
('2024-02-25', 25, 26000, 1, 24, 37, 10.2),
('2024-02-26', 20, 26200, 1, 19, 30, 9.6),
('2024-02-27', 15, 26400, 1, 14, 22, 9.0),
('2024-02-28', 10, 26600, 1, 9, 15, 8.4),
('2024-02-29', 5, 26800, 1, 4, 7, 7.8),
-- 3月数据春节后恢复
('2024-03-01', 200, 27000, 5, 195, 300, 12.0),
('2024-03-02', 300, 27200, 10, 290, 450, 15.0),
('2024-03-03', 400, 27400, 15, 385, 600, 18.0),
('2024-03-04', 500, 27600, 20, 480, 750, 21.0),
('2024-03-05', 600, 27800, 25, 575, 900, 24.0),
('2024-03-06', 700, 28000, 30, 670, 1050, 27.0),
('2024-03-07', 800, 28200, 35, 765, 1200, 30.0),
('2024-03-08', 900, 28400, 40, 860, 1350, 33.0),
('2024-03-09', 1000, 28600, 45, 955, 1500, 36.0),
('2024-03-10', 1100, 28800, 50, 1050, 1650, 39.0),
('2024-03-11', 1200, 29000, 55, 1145, 1800, 42.0),
('2024-03-12', 1300, 29200, 60, 1240, 1950, 45.0),
('2024-03-13', 1400, 29400, 65, 1335, 2100, 48.0),
('2024-03-14', 1500, 29600, 70, 1430, 2250, 51.0),
('2024-03-15', 1600, 29800, 75, 1525, 2400, 54.0),
('2024-03-16', 1700, 30000, 80, 1620, 2550, 57.0),
('2024-03-17', 1800, 30200, 85, 1715, 2700, 60.0),
('2024-03-18', 1900, 30400, 90, 1810, 2850, 63.0),
('2024-03-19', 2000, 30600, 95, 1905, 3000, 66.0),
('2024-03-20', 2100, 30800, 100, 2000, 3150, 69.0),
('2024-03-21', 2200, 31000, 105, 2095, 3300, 72.0),
('2024-03-22', 2300, 31200, 110, 2190, 3450, 75.0),
('2024-03-23', 2400, 31400, 115, 2285, 3600, 78.0),
('2024-03-24', 2500, 31600, 120, 2380, 3750, 81.0),
('2024-03-25', 2600, 31800, 125, 2475, 3900, 84.0),
('2024-03-26', 2700, 32000, 130, 2570, 4050, 87.0),
('2024-03-27', 2800, 32200, 135, 2665, 4200, 90.0),
('2024-03-28', 2900, 32400, 140, 2760, 4350, 93.0),
('2024-03-29', 3000, 32600, 145, 2855, 4500, 96.0),
('2024-03-30', 3100, 32800, 150, 2950, 4650, 99.0),
('2024-03-31', 3200, 33000, 155, 3045, 4800, 102.0),
-- 4月数据春季增长期
('2024-04-01', 3300, 33200, 160, 3140, 4950, 105.0),
('2024-04-02', 3400, 33400, 165, 3235, 5100, 108.0),
('2024-04-03', 3500, 33600, 170, 3330, 5250, 111.0),
('2024-04-04', 3600, 33800, 175, 3425, 5400, 114.0),
('2024-04-05', 3700, 34000, 180, 3520, 5550, 117.0),
('2024-04-06', 3800, 34200, 185, 3615, 5700, 120.0),
('2024-04-07', 3900, 34400, 190, 3710, 5850, 123.0),
('2024-04-08', 4000, 34600, 195, 3805, 6000, 126.0),
('2024-04-09', 4100, 34800, 200, 3900, 6150, 129.0),
('2024-04-10', 4200, 35000, 205, 3995, 6300, 132.0),
('2024-04-11', 4300, 35200, 210, 4090, 6450, 135.0),
('2024-04-12', 4400, 35400, 215, 4185, 6600, 138.0),
('2024-04-13', 4500, 35600, 220, 4280, 6750, 141.0),
('2024-04-14', 4600, 35800, 225, 4375, 6900, 144.0),
('2024-04-15', 4700, 36000, 230, 4470, 7050, 147.0),
('2024-04-16', 4800, 36200, 235, 4565, 7200, 150.0),
('2024-04-17', 4900, 36400, 240, 4660, 7350, 153.0),
('2024-04-18', 5000, 36600, 245, 4755, 7500, 156.0),
('2024-04-19', 5100, 36800, 250, 4850, 7650, 159.0),
('2024-04-20', 5200, 37000, 255, 4945, 7800, 162.0),
('2024-04-21', 5300, 37200, 260, 5040, 7950, 165.0),
('2024-04-22', 5400, 37400, 265, 5135, 8100, 168.0),
('2024-04-23', 5500, 37600, 270, 5230, 8250, 171.0),
('2024-04-24', 5600, 37800, 275, 5325, 8400, 174.0),
('2024-04-25', 5700, 38000, 280, 5420, 8550, 177.0),
('2024-04-26', 5800, 38200, 285, 5515, 8700, 180.0),
('2024-04-27', 5900, 38400, 290, 5610, 8850, 183.0),
('2024-04-28', 6000, 38600, 295, 5705, 9000, 186.0),
('2024-04-29', 6100, 38800, 300, 5800, 9150, 189.0),
('2024-04-30', 6200, 39000, 305, 5895, 9300, 192.0),
-- 5月数据五一假期影响
('2024-05-01', 5000, 39200, 200, 4800, 7500, 150.0),
('2024-05-02', 4500, 39400, 180, 4320, 6750, 135.0),
('2024-05-03', 4000, 39600, 160, 3840, 6000, 120.0),
('2024-05-04', 3500, 39800, 140, 3360, 5250, 105.0),
('2024-05-05', 3000, 40000, 120, 2880, 4500, 90.0),
('2024-05-06', 2500, 40200, 100, 2400, 3750, 75.0),
('2024-05-07', 2000, 40400, 80, 1920, 3000, 60.0),
('2024-05-08', 1500, 40600, 60, 1440, 2250, 45.0),
('2024-05-09', 1000, 40800, 40, 960, 1500, 30.0),
('2024-05-10', 800, 41000, 30, 770, 1200, 24.0),
('2024-05-11', 600, 41200, 20, 580, 900, 18.0),
('2024-05-12', 500, 41400, 15, 485, 750, 15.0),
('2024-05-13', 400, 41600, 10, 390, 600, 12.0),
('2024-05-14', 300, 41800, 8, 292, 450, 9.0),
('2024-05-15', 250, 42000, 5, 245, 375, 7.5),
('2024-05-16', 200, 42200, 3, 197, 300, 6.0),
('2024-05-17', 150, 42400, 2, 148, 225, 4.5),
('2024-05-18', 100, 42600, 1, 99, 150, 3.0),
('2024-05-19', 80, 42800, 1, 79, 120, 2.4),
('2024-05-20', 60, 43000, 1, 59, 90, 1.8),
('2024-05-21', 50, 43200, 1, 49, 75, 1.5),
('2024-05-22', 40, 43400, 1, 39, 60, 1.2),
('2024-05-23', 30, 43600, 1, 29, 45, 0.9),
('2024-05-24', 25, 43800, 1, 24, 37, 0.75),
('2024-05-25', 20, 44000, 1, 19, 30, 0.6),
('2024-05-26', 15, 44200, 1, 14, 22, 0.45),
('2024-05-27', 10, 44400, 1, 9, 15, 0.3),
('2024-05-28', 8, 44600, 1, 7, 12, 0.24),
('2024-05-29', 5, 44800, 1, 4, 7, 0.15),
('2024-05-30', 3, 45000, 1, 2, 4, 0.09),
('2024-05-31', 2, 45200, 1, 1, 3, 0.06),
-- 6月数据夏季恢复期
('2024-06-01', 100, 45400, 5, 95, 150, 3.0),
('2024-06-02', 200, 45600, 10, 190, 300, 6.0),
('2024-06-03', 300, 45800, 15, 285, 450, 9.0),
('2024-06-04', 400, 46000, 20, 380, 600, 12.0),
('2024-06-05', 500, 46200, 25, 475, 750, 15.0),
('2024-06-06', 600, 46400, 30, 570, 900, 18.0),
('2024-06-07', 700, 46600, 35, 665, 1050, 21.0),
('2024-06-08', 800, 46800, 40, 760, 1200, 24.0),
('2024-06-09', 900, 47000, 45, 855, 1350, 27.0),
('2024-06-10', 1000, 47200, 50, 950, 1500, 30.0),
('2024-06-11', 1100, 47400, 55, 1045, 1650, 33.0),
('2024-06-12', 1200, 47600, 60, 1140, 1800, 36.0),
('2024-06-13', 1300, 47800, 65, 1235, 1950, 39.0),
('2024-06-14', 1400, 48000, 70, 1330, 2100, 42.0),
('2024-06-15', 1500, 48200, 75, 1425, 2250, 45.0),
('2024-06-16', 1600, 48400, 80, 1520, 2400, 48.0),
('2024-06-17', 1700, 48600, 85, 1615, 2550, 51.0),
('2024-06-18', 1800, 48800, 90, 1710, 2700, 54.0),
('2024-06-19', 1900, 49000, 95, 1805, 2850, 57.0),
('2024-06-20', 2000, 49200, 100, 1900, 3000, 60.0),
('2024-06-21', 2100, 49400, 105, 1995, 3150, 63.0),
('2024-06-22', 2200, 49600, 110, 2090, 3300, 66.0),
('2024-06-23', 2300, 49800, 115, 2185, 3450, 69.0),
('2024-06-24', 2400, 50000, 120, 2280, 3600, 72.0),
('2024-06-25', 2500, 50200, 125, 2375, 3750, 75.0),
('2024-06-26', 2600, 50400, 130, 2470, 3900, 78.0),
('2024-06-27', 2700, 50600, 135, 2565, 4050, 81.0),
('2024-06-28', 2800, 50800, 140, 2660, 4200, 84.0),
('2024-06-29', 2900, 51000, 145, 2755, 4350, 87.0),
('2024-06-30', 3000, 51200, 150, 2850, 4500, 90.0),
-- 7月数据夏季高峰期
('2024-07-01', 3100, 51400, 155, 2945, 4650, 93.0),
('2024-07-02', 3200, 51600, 160, 3040, 4800, 96.0),
('2024-07-03', 3300, 51800, 165, 3135, 4950, 99.0),
('2024-07-04', 3400, 52000, 170, 3230, 5100, 102.0),
('2024-07-05', 3500, 52200, 175, 3325, 5250, 105.0),
('2024-07-06', 3600, 52400, 180, 3420, 5400, 108.0),
('2024-07-07', 3700, 52600, 185, 3515, 5550, 111.0),
('2024-07-08', 3800, 52800, 190, 3610, 5700, 114.0),
('2024-07-09', 3900, 53000, 195, 3705, 5850, 117.0),
('2024-07-10', 4000, 53200, 200, 3800, 6000, 120.0),
('2024-07-11', 4100, 53400, 205, 3895, 6150, 123.0),
('2024-07-12', 4200, 53600, 210, 3990, 6300, 126.0),
('2024-07-13', 4300, 53800, 215, 4085, 6450, 129.0),
('2024-07-14', 4400, 54000, 220, 4180, 6600, 132.0),
('2024-07-15', 4500, 54200, 225, 4275, 6750, 135.0),
('2024-07-16', 4600, 54400, 230, 4370, 6900, 138.0),
('2024-07-17', 4700, 54600, 235, 4465, 7050, 141.0),
('2024-07-18', 4800, 54800, 240, 4560, 7200, 144.0),
('2024-07-19', 4900, 55000, 245, 4655, 7350, 147.0),
('2024-07-20', 5000, 55200, 250, 4750, 7500, 150.0),
('2024-07-21', 5100, 55400, 255, 4845, 7650, 153.0),
('2024-07-22', 5200, 55600, 260, 4940, 7800, 156.0),
('2024-07-23', 5300, 55800, 265, 5035, 7950, 159.0),
('2024-07-24', 5400, 56000, 270, 5130, 8100, 162.0),
('2024-07-25', 5500, 56200, 275, 5225, 8250, 165.0),
('2024-07-26', 5600, 56400, 280, 5320, 8400, 168.0),
('2024-07-27', 5700, 56600, 285, 5415, 8550, 171.0),
('2024-07-28', 5800, 56800, 290, 5510, 8700, 174.0),
('2024-07-29', 5900, 57000, 295, 5605, 8850, 177.0),
('2024-07-30', 6000, 57200, 300, 5700, 9000, 180.0),
('2024-07-31', 6100, 57400, 305, 5795, 9150, 183.0),
-- 8月数据夏季高峰延续
('2024-08-01', 6200, 57600, 310, 5890, 9300, 186.0),
('2024-08-02', 6300, 57800, 315, 5985, 9450, 189.0),
('2024-08-03', 6400, 58000, 320, 6080, 9600, 192.0),
('2024-08-04', 6500, 58200, 325, 6175, 9750, 195.0),
('2024-08-05', 6600, 58400, 330, 6270, 9900, 198.0),
('2024-08-06', 6700, 58600, 335, 6365, 10050, 201.0),
('2024-08-07', 6800, 58800, 340, 6460, 10200, 204.0),
('2024-08-08', 6900, 59000, 345, 6555, 10350, 207.0),
('2024-08-09', 7000, 59200, 350, 6650, 10500, 210.0),
('2024-08-10', 7100, 59400, 355, 6745, 10650, 213.0),
('2024-08-11', 7200, 59600, 360, 6840, 10800, 216.0),
('2024-08-12', 7300, 59800, 365, 6935, 10950, 219.0),
('2024-08-13', 7400, 60000, 370, 7030, 11100, 222.0),
('2024-08-14', 7500, 60200, 375, 7125, 11250, 225.0),
('2024-08-15', 7600, 60400, 380, 7220, 11400, 228.0),
('2024-08-16', 7700, 60600, 385, 7315, 11550, 231.0),
('2024-08-17', 7800, 60800, 390, 7410, 11700, 234.0),
('2024-08-18', 7900, 61000, 395, 7505, 11850, 237.0),
('2024-08-19', 8000, 61200, 400, 7600, 12000, 240.0),
('2024-08-20', 8100, 61400, 405, 7695, 12150, 243.0),
('2024-08-21', 8200, 61600, 410, 7790, 12300, 246.0),
('2024-08-22', 8300, 61800, 415, 7885, 12450, 249.0),
('2024-08-23', 8400, 62000, 420, 7980, 12600, 252.0),
('2024-08-24', 8500, 62200, 425, 8075, 12750, 255.0),
('2024-08-25', 8600, 62400, 430, 8170, 12900, 258.0),
('2024-08-26', 8700, 62600, 435, 8265, 13050, 261.0),
('2024-08-27', 8800, 62800, 440, 8360, 13200, 264.0),
('2024-08-28', 8900, 63000, 445, 8455, 13350, 267.0),
('2024-08-29', 9000, 63200, 450, 8550, 13500, 270.0),
('2024-08-30', 9100, 63400, 455, 8645, 13650, 273.0),
('2024-08-31', 9200, 63600, 460, 8740, 13800, 276.0),
-- 9月数据秋季开学季
('2024-09-01', 9300, 63800, 465, 8835, 13950, 279.0),
('2024-09-02', 9400, 64000, 470, 8930, 14100, 282.0),
('2024-09-03', 9500, 64200, 475, 9025, 14250, 285.0),
('2024-09-04', 9600, 64400, 480, 9120, 14400, 288.0),
('2024-09-05', 9700, 64600, 485, 9215, 14550, 291.0),
('2024-09-06', 9800, 64800, 490, 9310, 14700, 294.0),
('2024-09-07', 9900, 65000, 495, 9405, 14850, 297.0),
('2024-09-08', 10000, 65200, 500, 9500, 15000, 300.0),
('2024-09-09', 10100, 65400, 505, 9595, 15150, 303.0),
('2024-09-10', 10200, 65600, 510, 9690, 15300, 306.0),
('2024-09-11', 10300, 65800, 515, 9785, 15450, 309.0),
('2024-09-12', 10400, 66000, 520, 9880, 15600, 312.0),
('2024-09-13', 10500, 66200, 525, 9975, 15750, 315.0),
('2024-09-14', 10600, 66400, 530, 10070, 15900, 318.0),
('2024-09-15', 10700, 66600, 535, 10165, 16050, 321.0),
('2024-09-16', 10800, 66800, 540, 10260, 16200, 324.0),
('2024-09-17', 10900, 67000, 545, 10355, 16350, 327.0),
('2024-09-18', 11000, 67200, 550, 10450, 16500, 330.0),
('2024-09-19', 11100, 67400, 555, 10545, 16650, 333.0),
('2024-09-20', 11200, 67600, 560, 10640, 16800, 336.0),
('2024-09-21', 11300, 67800, 565, 10735, 16950, 339.0),
('2024-09-22', 11400, 68000, 570, 10830, 17100, 342.0),
('2024-09-23', 11500, 68200, 575, 10925, 17250, 345.0),
('2024-09-24', 11600, 68400, 580, 11020, 17400, 348.0),
('2024-09-25', 11700, 68600, 585, 11115, 17550, 351.0),
('2024-09-26', 11800, 68800, 590, 11210, 17700, 354.0),
('2024-09-27', 11900, 69000, 595, 11305, 17850, 357.0),
('2024-09-28', 12000, 69200, 600, 11400, 18000, 360.0),
('2024-09-29', 12100, 69400, 605, 11495, 18150, 363.0),
('2024-09-30', 12200, 69600, 610, 11590, 18300, 366.0),
-- 10月数据秋季稳定期
('2024-10-01', 12000, 69800, 600, 11400, 18000, 360.0),
('2024-10-02', 11800, 70000, 580, 11220, 17700, 354.0),
('2024-10-03', 11600, 70200, 560, 11040, 17400, 348.0),
('2024-10-04', 11400, 70400, 540, 10860, 17100, 342.0),
('2024-10-05', 11200, 70600, 520, 10680, 16800, 336.0),
('2024-10-06', 11000, 70800, 500, 10500, 16500, 330.0),
('2024-10-07', 10800, 71000, 480, 10320, 16200, 324.0),
('2024-10-08', 10600, 71200, 460, 10140, 15900, 318.0),
('2024-10-09', 10400, 71400, 440, 9960, 15600, 312.0),
('2024-10-10', 10200, 71600, 420, 9780, 15300, 306.0),
('2024-10-11', 10000, 71800, 400, 9600, 15000, 300.0),
('2024-10-12', 9800, 72000, 380, 9420, 14700, 294.0),
('2024-10-13', 9600, 72200, 360, 9240, 14400, 288.0),
('2024-10-14', 9400, 72400, 340, 9060, 14100, 282.0),
('2024-10-15', 9200, 72600, 320, 8880, 13800, 276.0),
('2024-10-16', 9000, 72800, 300, 8700, 13500, 270.0),
('2024-10-17', 8800, 73000, 280, 8520, 13200, 264.0),
('2024-10-18', 8600, 73200, 260, 8340, 12900, 258.0),
('2024-10-19', 8400, 73400, 240, 8160, 12600, 252.0),
('2024-10-20', 8200, 73600, 220, 7980, 12300, 246.0),
('2024-10-21', 8000, 73800, 200, 7800, 12000, 240.0),
('2024-10-22', 7800, 74000, 180, 7620, 11700, 234.0),
('2024-10-23', 7600, 74200, 160, 7440, 11400, 228.0),
('2024-10-24', 7400, 74400, 140, 7260, 11100, 222.0),
('2024-10-25', 7200, 74600, 120, 7080, 10800, 216.0),
('2024-10-26', 7000, 74800, 100, 6900, 10500, 210.0),
('2024-10-27', 6800, 75000, 80, 6720, 10200, 204.0),
('2024-10-28', 6600, 75200, 60, 6540, 9900, 198.0),
('2024-10-29', 6400, 75400, 40, 6360, 9600, 192.0),
('2024-10-30', 6200, 75600, 20, 6180, 9300, 186.0),
('2024-10-31', 6000, 75800, 10, 5990, 9000, 180.0),
-- 11月数据冬季开始
('2024-11-01', 5800, 76000, 5, 5795, 8700, 174.0),
('2024-11-02', 5600, 76200, 5, 5595, 8400, 168.0),
('2024-11-03', 5400, 76400, 5, 5395, 8100, 162.0),
('2024-11-04', 5200, 76600, 5, 5195, 7800, 156.0),
('2024-11-05', 5000, 76800, 5, 4995, 7500, 150.0),
('2024-11-06', 4800, 77000, 5, 4795, 7200, 144.0),
('2024-11-07', 4600, 77200, 5, 4595, 6900, 138.0),
('2024-11-08', 4400, 77400, 5, 4395, 6600, 132.0),
('2024-11-09', 4200, 77600, 5, 4195, 6300, 126.0),
('2024-11-10', 4000, 77800, 5, 3995, 6000, 120.0),
('2024-11-11', 3800, 78000, 5, 3795, 5700, 114.0),
('2024-11-12', 3600, 78200, 5, 3595, 5400, 108.0),
('2024-11-13', 3400, 78400, 5, 3395, 5100, 102.0),
('2024-11-14', 3200, 78600, 5, 3195, 4800, 96.0),
('2024-11-15', 3000, 78800, 5, 2995, 4500, 90.0),
('2024-11-16', 2800, 79000, 5, 2795, 4200, 84.0),
('2024-11-17', 2600, 79200, 5, 2595, 3900, 78.0),
('2024-11-18', 2400, 79400, 5, 2395, 3600, 72.0),
('2024-11-19', 2200, 79600, 5, 2195, 3300, 66.0),
('2024-11-20', 2000, 79800, 5, 1995, 3000, 60.0),
('2024-11-21', 1800, 80000, 5, 1795, 2700, 54.0),
('2024-11-22', 1600, 80200, 5, 1595, 2400, 48.0),
('2024-11-23', 1400, 80400, 5, 1395, 2100, 42.0),
('2024-11-24', 1200, 80600, 5, 1195, 1800, 36.0),
('2024-11-25', 1000, 80800, 5, 995, 1500, 30.0),
('2024-11-26', 800, 81000, 5, 795, 1200, 24.0),
('2024-11-27', 600, 81200, 5, 595, 900, 18.0),
('2024-11-28', 400, 81400, 5, 395, 600, 12.0),
('2024-11-29', 200, 81600, 5, 195, 300, 6.0),
('2024-11-30', 100, 81800, 5, 95, 150, 3.0),
-- 12月数据年末总结
('2024-12-01', 500, 82000, 10, 490, 750, 15.0),
('2024-12-02', 600, 82200, 15, 585, 900, 18.0),
('2024-12-03', 700, 82400, 20, 680, 1050, 21.0),
('2024-12-04', 800, 82600, 25, 775, 1200, 24.0),
('2024-12-05', 900, 82800, 30, 870, 1350, 27.0),
('2024-12-06', 1000, 83000, 35, 965, 1500, 30.0),
('2024-12-07', 1100, 83200, 40, 1060, 1650, 33.0),
('2024-12-08', 1200, 83400, 45, 1155, 1800, 36.0),
('2024-12-09', 1300, 83600, 50, 1250, 1950, 39.0),
('2024-12-10', 1400, 83800, 55, 1345, 2100, 42.0),
('2024-12-11', 1500, 84000, 60, 1440, 2250, 45.0),
('2024-12-12', 1600, 84200, 65, 1535, 2400, 48.0),
('2024-12-13', 1700, 84400, 70, 1630, 2550, 51.0),
('2024-12-14', 1800, 84600, 75, 1725, 2700, 54.0),
('2024-12-15', 1900, 84800, 80, 1820, 2850, 57.0),
('2024-12-16', 2000, 85000, 85, 1915, 3000, 60.0),
('2024-12-17', 2100, 85200, 90, 2010, 3150, 63.0),
('2024-12-18', 2200, 85400, 95, 2105, 3300, 66.0),
('2024-12-19', 2300, 85600, 100, 2200, 3450, 69.0),
('2024-12-20', 2400, 85800, 105, 2295, 3600, 72.0),
('2024-12-21', 2500, 86000, 110, 2390, 3750, 75.0),
('2024-12-22', 2600, 86200, 115, 2485, 3900, 78.0),
('2024-12-23', 2700, 86400, 120, 2580, 4050, 81.0),
('2024-12-24', 2800, 86600, 125, 2675, 4200, 84.0),
('2024-12-25', 2900, 86800, 130, 2770, 4350, 87.0),
('2024-12-26', 3000, 87000, 135, 2865, 4500, 90.0),
('2024-12-27', 3100, 87200, 140, 2960, 4650, 93.0),
('2024-12-28', 3200, 87400, 145, 3055, 4800, 96.0),
('2024-12-29', 3300, 87600, 150, 3150, 4950, 99.0),
('2024-12-30', 3400, 87800, 155, 3245, 5100, 102.0),
('2024-12-31', 3500, 88000, 160, 3340, 5250, 105.0);