Compare commits
46 Commits
cf02b59722
...
dev/3.1_re
| Author | SHA1 | Date | |
|---|---|---|---|
| a8c1261c89 | |||
| c35e60dcde | |||
| ad3bc69e5c | |||
| bb682e56fa | |||
| 9a4a5d5504 | |||
| b4354d5975 | |||
| 635d913084 | |||
| 61e8901bb1 | |||
| 1680debd4b | |||
| bd6ba95a25 | |||
| 75efc341be | |||
| 921de43b08 | |||
| c558ebb3d0 | |||
| d20bb27244 | |||
| 6e98f295c5 | |||
| 838a8a13b3 | |||
| c95f3accb9 | |||
| 65cde0b8f5 | |||
| b66877425e | |||
| f6d28fec07 | |||
|
|
f53fca9a09 | ||
|
|
c8dc38575a | ||
|
|
c00d906083 | ||
| 4df3f9cc53 | |||
|
|
b0343be544 | ||
|
|
d33cb9f0bf | ||
|
|
40f2735831 | ||
|
|
d73442d1dd | ||
|
|
c8164cb997 | ||
| 981fc35be4 | |||
| 01d3806d5f | |||
| 107e4e9771 | |||
|
|
716d720782 | ||
|
|
6b5bacc49b | ||
|
|
409bc7b1fd | ||
|
|
ec6a5df8af | ||
|
|
029b96ae99 | ||
|
|
14002e7331 | ||
| 14dfe2806c | |||
| 798c7b0592 | |||
| 9bd10581f4 | |||
| 1f288fe5e3 | |||
| 72602eb245 | |||
| 983d53268d | |||
| f3aeeb3584 | |||
| 5d3692a204 |
@@ -202,7 +202,7 @@ public class MyTaskScheduler {
|
||||
}
|
||||
}
|
||||
|
||||
// @Scheduled(cron = "0 0 9 * * ?")
|
||||
// @Scheduled(cron = "0 0 9 * * ?")
|
||||
public void sendTrialOrderExcelToManagements() {
|
||||
// 获取前一天日期
|
||||
LocalDate yesterday = LocalDate.now().minusDays(1);
|
||||
|
||||
@@ -13,8 +13,9 @@ public class CommonConstant {
|
||||
public static final Integer MINIO_IMAGE_EXPIRE_TIME = 24 * 60;
|
||||
// 单位 秒 一天过期 in redis
|
||||
public static final Long GENERATE_RESULT_EXPIRE_TIME = 24 * 60 * 60L;
|
||||
// 单位 秒 7天过期
|
||||
public static final Long REDIS_SET_EXPIRE_TIME = 24 * 60 * 60 * 7L;
|
||||
// 单位 秒 7天过期 (todo 测试状态下 3小时过期)
|
||||
// public static final Long REDIS_SET_EXPIRE_TIME = 24 * 60 * 60 * 7L;
|
||||
public static final Long REDIS_SET_EXPIRE_TIME = 3 * 60 * 60L;
|
||||
|
||||
public static class Numbers{
|
||||
public static final Integer NUMBER_10 = 10;
|
||||
|
||||
@@ -18,8 +18,8 @@ public class ModelConstants {
|
||||
|
||||
// 模型名称常量
|
||||
public static final String PRINTBOARD_ADVANCED_T2I = "qwen-image";
|
||||
public static final String MOODBOARD_ADVANCED = "doubao-seedream-3-0-t2i-250415";
|
||||
public static final String PRINTBOARD_HIGH_T2I = "doubao-seedream-3-0-t2i-250415";
|
||||
public static final String MOODBOARD_ADVANCED = "doubao-seedream-4-5-251128";
|
||||
public static final String PRINTBOARD_HIGH_T2I = "doubao-seedream-4-0-250828-high";
|
||||
public static final String PRINTBOARD_HIGH_I2I = "doubao-seedream-4-0-250828-fast";
|
||||
public static final String PRINTBOARD_ADVANCED_I2I = "doubao-seedream-4-0-250828";
|
||||
public static final String IMAGEN_MODEL = "imagen-4.0-generate-001";
|
||||
|
||||
@@ -61,10 +61,7 @@ public class AuthenticationFilter extends OncePerRequestFilter {
|
||||
, "/api/account/schoolLogin", "/api/account/enterpriseLogin", "/api/account/organizationNameSearch",
|
||||
"/api/llm/stream",
|
||||
//GlobalAwardController
|
||||
"/api/global-award/uploads/pdf/init", "/api/global-award/uploads/pdf/chunk", "/api/global-award/uploads/pdf/complete", "/api/global-award/uploads/pdf/status",
|
||||
"/api/global-award/uploads/video/init", "/api/global-award/uploads/video/chunk", "/api/global-award/uploads/video/complete", "/api/global-award/uploads/video/status",
|
||||
"/api/global-award/contestants/save", "/api/global-award/contestants/by-email", "/api/global-award/checkEmail", "/api/global-award/checkCode","/api/global-award/contestants/export",
|
||||
"/api/global-award/contestants/export/files"
|
||||
"/api/global-award"
|
||||
);
|
||||
|
||||
@Override
|
||||
|
||||
@@ -34,7 +34,7 @@ public class AccountTask {
|
||||
accountService.refreshCreditsMonthly();
|
||||
}
|
||||
|
||||
// @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
|
||||
// @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
|
||||
public void getPaidUser() {
|
||||
// 获取code-create 表中 指定日期之后 订单状态为wc-processing的订单
|
||||
accountService.extendValidityForCC();
|
||||
|
||||
@@ -45,7 +45,7 @@ public class PaymentTask {
|
||||
@Resource
|
||||
private PayPalCheckoutService payPalCheckoutService;
|
||||
|
||||
// @Scheduled(cron = "0/30 * * * * ?")
|
||||
// @Scheduled(cron = "0/30 * * * * ?")
|
||||
public void orderConfirmForPaypal() throws SerializeException {
|
||||
|
||||
// log.info("PayPal orderConfirm 被执行......");
|
||||
@@ -97,7 +97,7 @@ public class PaymentTask {
|
||||
//
|
||||
}
|
||||
|
||||
// @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
|
||||
@Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
|
||||
public void updateAffiliateInfoWithPayment(){
|
||||
// log.info("佣金计算定时器");
|
||||
affiliateService.updateAffiliateInfoWithPayment();
|
||||
@@ -109,7 +109,7 @@ public class PaymentTask {
|
||||
affiliateService.syncLinkViewCountToDB();
|
||||
}
|
||||
|
||||
// @Scheduled(cron = "0 0 8 28-31 * ?")
|
||||
// @Scheduled(cron = "0 0 8 28-31 * ?")
|
||||
public void commissionSummaryReminder(){
|
||||
// 每个月末的最后一天的早上八点执行
|
||||
LocalDate today = LocalDate.now();
|
||||
|
||||
@@ -40,7 +40,7 @@ public class SubscriptionReminderTask {
|
||||
REMINDER_DAYS_CONFIG.put("year", 14);
|
||||
}
|
||||
|
||||
// @Scheduled(cron = "0 0 9 * * ?")
|
||||
// @Scheduled(cron = "0 0 9 * * ?")
|
||||
public void subscriptionReminder() {
|
||||
// 获取所有需要通知的订阅
|
||||
List<SubscriptionInfo> subscriptionInfos = getDueSubscriptions();
|
||||
@@ -97,7 +97,7 @@ public class SubscriptionReminderTask {
|
||||
return subscriptionInfoMapper.selectList(qw);
|
||||
}
|
||||
|
||||
// @Scheduled(cron = "0 0 9 * * ?")
|
||||
// @Scheduled(cron = "0 0 9 * * ?")
|
||||
public void trialReminder() {
|
||||
// 今天的 00:00:00 和 23:59:59
|
||||
LocalDateTime startOfDay = LocalDateTime.now().toLocalDate().atStartOfDay();
|
||||
|
||||
@@ -17,17 +17,38 @@ import com.tencentcloudapi.ses.v20201002.models.SendEmailRequest;
|
||||
import com.tencentcloudapi.ses.v20201002.models.SendEmailResponse;
|
||||
import com.tencentcloudapi.ses.v20201002.models.Template;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 邮件发送类
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class SendEmailUtil {
|
||||
@Value("${merchant.email:}")
|
||||
private String merchantEmailInstance;
|
||||
@Value("${developer.email: xupei@code-create.com.hk}")
|
||||
private String developerEmailInstance;
|
||||
|
||||
private static String merchantEmail;
|
||||
private static String developerEmail;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
merchantEmail = merchantEmailInstance;
|
||||
developerEmail = developerEmailInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 秘钥id
|
||||
*/
|
||||
@@ -765,9 +786,7 @@ public class SendEmailUtil {
|
||||
|
||||
public static boolean subscriptionEmailReminder(String type, SubscriptionEmailParamsDTO subscriptionEmailParamsDTO, String language, String receiverAddress) {
|
||||
try {
|
||||
String merchantEmail = "kimwong@code-create.com.hk";
|
||||
String developer = "xupei3360@163.com";
|
||||
String[] receiverEmail = {/*merchantEmail,*/ developer};
|
||||
String[] receiverEmail = buildMerchantReceiverEmail();
|
||||
Credential cred = new Credential(SECRET_ID, SECRET_KEy);
|
||||
// 实例化一个http选项,可选的,没有特殊需求可以跳过
|
||||
HttpProfile httpProfile = new HttpProfile();
|
||||
@@ -966,9 +985,7 @@ public class SendEmailUtil {
|
||||
// 实例化一个请求对象,每个接口都会对应一个request对象
|
||||
SendEmailRequest req = new SendEmailRequest();
|
||||
req.setFromEmailAddress(SEND_ADDRESS);
|
||||
String merchantEmail = "kimwong@code-create.com.hk";
|
||||
String developerEmail = "xupei@code-create.com.hk";
|
||||
req.setDestination(new String[]{/*merchantEmail,*/ developerEmail});
|
||||
req.setDestination(buildMerchantReceiverEmail());
|
||||
Template template = new Template();
|
||||
req.setSubject("New Credit Purchase Order");
|
||||
template.setTemplateID(CREDITS_PURCHASE_MERCHANT);
|
||||
@@ -1076,4 +1093,25 @@ public class SendEmailUtil {
|
||||
|
||||
}
|
||||
|
||||
public static String[] buildMerchantReceiverEmail() {
|
||||
List<String> emails = new ArrayList<>();
|
||||
if (!StringUtils.isEmpty(merchantEmail)) {
|
||||
for (String e : merchantEmail.split(",")) {
|
||||
String trimmed = e.trim();
|
||||
if (!trimmed.isEmpty()) {
|
||||
emails.add(trimmed);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!StringUtils.isEmpty(developerEmail)) {
|
||||
for (String e : developerEmail.split(",")) {
|
||||
String trimmed = e.trim();
|
||||
if (!trimmed.isEmpty()) {
|
||||
emails.add(trimmed);
|
||||
}
|
||||
}
|
||||
}
|
||||
return emails.toArray(new String[0]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import com.ai.da.common.response.Response;
|
||||
import com.ai.da.model.dto.*;
|
||||
import com.ai.da.model.dto.ContestantDTO;
|
||||
import com.ai.da.model.vo.CheckOTPVO;
|
||||
import com.ai.da.model.vo.ContestantCountVO;
|
||||
import com.ai.da.model.vo.PageVisitCountVO;
|
||||
import com.ai.da.service.GlobalAwardService;
|
||||
import com.ai.da.service.upload.UploadService;
|
||||
import com.ai.da.service.upload.UploadTask;
|
||||
@@ -176,10 +178,38 @@ public class GlobalAwardController {
|
||||
}
|
||||
|
||||
@PostMapping("/contestants/export/files")
|
||||
@ApiOperation(value = "导出参赛者文件到本地", notes = "根据参赛者编号范围导出PDF和视频文件到本地temp/uploads/contestants目录")
|
||||
public Response<Integer> exportContestantFiles(@ApiParam(value = "参赛者文件导出请求", required = true) @RequestBody ContestantExportRequest request) throws Exception {
|
||||
int exportedCount = globalAwardService.exportContestantFiles(request.getMinContestantNumber(), request.getMaxContestantNumber());
|
||||
return Response.success(exportedCount);
|
||||
@ApiOperation(value = "导出参赛者文件为ZIP", notes = "根据参赛者编号范围导出PDF、视频和信息文件为ZIP,直接响应给浏览器")
|
||||
public void exportContestantFiles(@ApiParam(value = "参赛者文件导出请求", required = true) @RequestBody ContestantExportRequest request, HttpServletResponse response) throws Exception {
|
||||
byte[] zipData = globalAwardService.exportContestantFilesAsZip(request.getMinContestantNumber(), request.getMaxContestantNumber());
|
||||
if (zipData.length == 0) {
|
||||
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||
response.getWriter().write("No contestants found in the specified range.");
|
||||
return;
|
||||
}
|
||||
response.setContentType("application/zip");
|
||||
response.setHeader("Content-Disposition", "attachment; filename=\"contestants.zip\"");
|
||||
response.setContentLength(zipData.length);
|
||||
response.getOutputStream().write(zipData);
|
||||
response.getOutputStream().flush();
|
||||
}
|
||||
|
||||
@GetMapping("/contestants/count")
|
||||
@ApiOperation(value = "查询参赛者总数", notes = "查询数据库中参赛者的总数量和最大参赛者编号")
|
||||
public Response<ContestantCountVO> getContestantCount() {
|
||||
return Response.success(globalAwardService.getContestantCount());
|
||||
}
|
||||
|
||||
@PostMapping("/page/visit")
|
||||
@ApiOperation(value = "记录比赛页面访问量", notes = "记录比赛页面的访问量,包含两种统计方式:每次访问/刷新计一次,以及5秒内刷新只计一次")
|
||||
public Response<Void> recordPageVisit(@ApiParam(value = "会话ID,用于5秒内去重判断", required = false) @RequestParam(value = "sessionId", required = false) String sessionId) {
|
||||
globalAwardService.recordPageVisit(sessionId);
|
||||
return Response.success();
|
||||
}
|
||||
|
||||
@GetMapping("/page/visit/count")
|
||||
@ApiOperation(value = "获取比赛页面访问量", notes = "获取比赛页面的两种访问量:rawVisitCount(每次访问/刷新计一次)和 uniqueVisitCount(5秒内刷新只计一次)")
|
||||
public Response<PageVisitCountVO> getPageVisitCount() {
|
||||
return Response.success(globalAwardService.getPageVisitCount());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -68,6 +68,9 @@ public class Contestant {
|
||||
@TableField("pdf_size")
|
||||
private Long pdfSize;
|
||||
|
||||
@TableField("portfolio_url")
|
||||
private String portfolioUrl;
|
||||
|
||||
@TableField("created_at")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
|
||||
17
src/main/java/com/ai/da/model/vo/ContestantCountVO.java
Normal file
17
src/main/java/com/ai/da/model/vo/ContestantCountVO.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package com.ai.da.model.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ContestantCountVO {
|
||||
|
||||
private Long count;
|
||||
|
||||
private Integer maxContestantNumber;
|
||||
}
|
||||
23
src/main/java/com/ai/da/model/vo/PageVisitCountVO.java
Normal file
23
src/main/java/com/ai/da/model/vo/PageVisitCountVO.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package com.ai.da.model.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class PageVisitCountVO {
|
||||
|
||||
/**
|
||||
* 每次访问或刷新都计一次(不去重)
|
||||
*/
|
||||
private Long rawVisitCount;
|
||||
|
||||
/**
|
||||
* 5秒内刷新只算一次(去重后的真实访客数)
|
||||
*/
|
||||
private Long uniqueVisitCount;
|
||||
}
|
||||
@@ -34,4 +34,8 @@ public class QueryUserConditionsVO extends PageQueryBaseVo {
|
||||
|
||||
private Integer systemUser;
|
||||
|
||||
private Long subscriptionPlanId;
|
||||
|
||||
private Long organizationId;
|
||||
|
||||
}
|
||||
|
||||
@@ -2912,72 +2912,71 @@ public class PythonService {
|
||||
|
||||
private PrintToPython resolveDesignSinglePrint(List<DesignSinglePrint> printObject, String partialDesign) {
|
||||
PrintToPython printToPython = new PrintToPython();
|
||||
// DesignPythonItemPrint printSingle = new DesignPythonItemPrint();
|
||||
DesignPythonItemPrint printOverall = new DesignPythonItemPrint();
|
||||
// printToPython.setSingle(printSingle);
|
||||
printToPython.setOverall(printOverall);
|
||||
printToPython.setPartial(StringUtil.isNullOrEmpty(partialDesign) ? null : partialDesign);
|
||||
if (Objects.isNull(printObject) || printObject.isEmpty()) {
|
||||
return printToPython;
|
||||
}
|
||||
|
||||
// 没有印花时的参数设置
|
||||
// if (printObject.getIfSingle().equals(Boolean.FALSE) && CollectionUtil.isEmpty(printObject.getPrints())) {
|
||||
// return new DesignPythonItemPrint(new ArrayList<>(), false);
|
||||
// }
|
||||
// DesignPythonItemPrint print = CopyUtil.copyObject(printObject, DesignPythonItemPrint.class);
|
||||
// 1. 先对 printObject 按 priority 排序(升序)
|
||||
List<DesignSinglePrint> sortedPrints = printObject.stream()
|
||||
.sorted(Comparator.comparingInt(DesignSinglePrint::getPriority))
|
||||
.toList();
|
||||
|
||||
int size = printObject.size();
|
||||
// 占位符填充数组
|
||||
List<List<Float>> locationS = new ArrayList<>(Collections.nCopies(size, null));
|
||||
List<List<Float>> scaleS = new ArrayList<>(Collections.nCopies(size, null));
|
||||
List<Double> angleS = new ArrayList<>(Collections.nCopies(size, null));
|
||||
ArrayList<String> pathsS = new ArrayList<>(Collections.nCopies(size, null));
|
||||
// 2. 分别收集单印和非单印的数据
|
||||
List<DesignSinglePrint> singlePrints = sortedPrints.stream()
|
||||
.filter(DesignSinglePrint::getIfSingle)
|
||||
.toList();
|
||||
|
||||
List<List<Float>> locationO = new ArrayList<>(Collections.nCopies(size, null));
|
||||
List<List<Float>> scaleO = new ArrayList<>(Collections.nCopies(size, null));
|
||||
List<Double> angleO = new ArrayList<>(Collections.nCopies(size, null));
|
||||
ArrayList<String> pathsO = new ArrayList<>(Collections.nCopies(size, null));
|
||||
List<DesignSinglePrint> overallPrints = sortedPrints.stream()
|
||||
.filter(p -> !p.getIfSingle())
|
||||
.toList();
|
||||
|
||||
// 设置印花的位置、大小、旋转角度
|
||||
// 优先级越大,越靠近顶层,在传输给python的数组中,越靠前
|
||||
// List<DesignSinglePrint> prints = printObject.getPrints();
|
||||
printObject.forEach(p -> {
|
||||
p.getLocation().set(0, p.getLocation().get(0));
|
||||
p.getLocation().set(1, p.getLocation().get(1));
|
||||
Integer priority = p.getPriority();
|
||||
setUriToMinioPath(p);
|
||||
// todo 下标越界问题
|
||||
if (p.getIfSingle()) {
|
||||
locationS.set(priority - 1, p.getLocation());
|
||||
scaleS.set(priority - 1, p.getScale());
|
||||
angleS.set(priority - 1, p.getAngle());
|
||||
pathsS.set(priority - 1, p.getMinIOPath());
|
||||
} else {
|
||||
locationO.set(priority - 1, p.getLocation());
|
||||
scaleO.set(priority - 1, p.getScale());
|
||||
angleO.set(priority - 1, p.getAngle());
|
||||
pathsO.set(priority - 1, p.getMinIOPath());
|
||||
// 3. 处理单印数据
|
||||
if (!singlePrints.isEmpty()) {
|
||||
List<List<Float>> locationS = new ArrayList<>();
|
||||
List<List<Float>> scaleS = new ArrayList<>();
|
||||
List<Double> angleS = new ArrayList<>();
|
||||
List<String> pathsS = new ArrayList<>();
|
||||
|
||||
for (DesignSinglePrint p : singlePrints) {
|
||||
setUriToMinioPath(p);
|
||||
locationS.add(p.getLocation());
|
||||
scaleS.add(p.getScale());
|
||||
angleS.add(p.getAngle());
|
||||
pathsS.add(p.getMinIOPath());
|
||||
}
|
||||
// log.info("本次print打点locations###{}###fileVO{}", p.getLocation(), JSON.toJSONString(fileVO));
|
||||
});
|
||||
/*locationS.removeAll(Collections.singleton(null));
|
||||
scaleS.removeAll(Collections.singleton(null));
|
||||
angleS.removeAll(Collections.singleton(null));
|
||||
pathsS.removeAll(Collections.singleton(null));
|
||||
printSingle.setLocation(locationS);
|
||||
printSingle.setPrint_scale_list(scaleS);
|
||||
printSingle.setPrint_angle_list(angleS);
|
||||
printSingle.setPrint_path_list(pathsS);*/
|
||||
|
||||
locationO.removeAll(Collections.singleton(null));
|
||||
scaleO.removeAll(Collections.singleton(null));
|
||||
angleO.removeAll(Collections.singleton(null));
|
||||
pathsO.removeAll(Collections.singleton(null));
|
||||
printOverall.setLocation(locationO);
|
||||
printOverall.setPrint_scale_list(scaleO);
|
||||
printOverall.setPrint_angle_list(angleO);
|
||||
printOverall.setPrint_path_list(pathsO);
|
||||
// 注意:如果 printOverall 中需要设置单印数据,请在这里添加相应的 setter
|
||||
// 根据您的原始代码,似乎只设置了 overall(非单印)的数据
|
||||
// 如果需要设置单印,请取消下面的注释并添加对应的字段
|
||||
// printOverall.setSingleLocation(locationS);
|
||||
// printOverall.setSingleScale(scaleS);
|
||||
// printOverall.setSingleAngle(angleS);
|
||||
// printOverall.setSinglePath(pathsS);
|
||||
}
|
||||
|
||||
// 4. 处理非单印数据(整体印花)
|
||||
if (!overallPrints.isEmpty()) {
|
||||
List<List<Float>> locationO = new ArrayList<>();
|
||||
List<List<Float>> scaleO = new ArrayList<>();
|
||||
List<Double> angleO = new ArrayList<>();
|
||||
List<String> pathsO = new ArrayList<>();
|
||||
|
||||
for (DesignSinglePrint p : overallPrints) {
|
||||
setUriToMinioPath(p);
|
||||
locationO.add(p.getLocation());
|
||||
scaleO.add(p.getScale());
|
||||
angleO.add(p.getAngle());
|
||||
pathsO.add(p.getMinIOPath());
|
||||
}
|
||||
|
||||
printOverall.setLocation(locationO);
|
||||
printOverall.setPrint_scale_list(scaleO);
|
||||
printOverall.setPrint_angle_list(angleO);
|
||||
printOverall.setPrint_path_list(pathsO);
|
||||
}
|
||||
|
||||
return printToPython;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.ai.da.service;
|
||||
|
||||
import com.ai.da.model.dto.ContestantDTO;
|
||||
import com.ai.da.model.vo.CheckOTPVO;
|
||||
import com.ai.da.model.vo.ContestantCountVO;
|
||||
import com.ai.da.model.vo.PageVisitCountVO;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.Map;
|
||||
@@ -33,12 +35,34 @@ public interface GlobalAwardService {
|
||||
void saveContestantsToLocal() throws Exception;
|
||||
|
||||
/**
|
||||
* 根据参赛者编号范围导出参赛者文件到本地目录
|
||||
* 将参赛者文件打包为 ZIP 并返回字节数组(不落盘,直接响应给浏览器)
|
||||
* @param minContestantNumber 最小参赛者编号
|
||||
* @param maxContestantNumber 最大参赛者编号
|
||||
* @return 导出的参赛者数量
|
||||
* @return ZIP 文件的字节数组
|
||||
*/
|
||||
int exportContestantFiles(Integer minContestantNumber, Integer maxContestantNumber) throws Exception;
|
||||
byte[] exportContestantFilesAsZip(Integer minContestantNumber, Integer maxContestantNumber) throws Exception;
|
||||
|
||||
/**
|
||||
* 查询参赛者总数和最大参赛者编号
|
||||
* @return 参赛者数量和最大参赛者编号
|
||||
*/
|
||||
ContestantCountVO getContestantCount();
|
||||
|
||||
/**
|
||||
* 记录比赛页面的访问量
|
||||
* <ul>
|
||||
* <li>rawVisitCount: 每次访问或刷新都计一次(不去重)</li>
|
||||
* <li>uniqueVisitCount: 5秒内刷新只算一次(基于会话去重)</li>
|
||||
* </ul>
|
||||
* @param sessionId 会话ID(用于5秒去重判断)
|
||||
*/
|
||||
void recordPageVisit(String sessionId);
|
||||
|
||||
/**
|
||||
* 获取比赛页面的两种访问量
|
||||
* @return 原始访问量和去重访问量
|
||||
*/
|
||||
PageVisitCountVO getPageVisitCount();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3383,12 +3383,14 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
|
||||
Account account = accountMapper.selectById(accountId);
|
||||
if (!Objects.isNull(account.getValidEndTime())
|
||||
&& account.getValidEndTime().equals(currentPeriodEnd * 1000)) {
|
||||
log.info("accountId:{}未更新账号有效期。current validEnd:{}, new validEnd:{}", accountId, account.getValidEndTime(), currentPeriodEnd);
|
||||
return false;
|
||||
} else {
|
||||
account.setValidEndTime(currentPeriodEnd * 1000);
|
||||
accountMapper.updateById(account);
|
||||
log.info("accountId:{} 将账号有效期更新到 {}", accountId, currentPeriodEnd);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -3416,13 +3418,14 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
|
||||
}
|
||||
account.setCredits(BigDecimal.valueOf(productCredits));
|
||||
accountMapper.updateById(account);
|
||||
log.info("accountId:{},更新用户角色为{},总积分为{}", accountId, account.getSystemUser(), productCredits);
|
||||
|
||||
CreditsService creditsService = SpringUtils.getBean(CreditsService.class);
|
||||
// 添加积分变更记录(订单续订时的积分变更也需要记录) todo 重置的记录不太准确
|
||||
// 添加积分变更记录(订单续订时的积分变更也需要记录)
|
||||
creditsService.insertToCreditsDetail(accountId,
|
||||
description + "--Stripe",
|
||||
String.valueOf(productCredits),
|
||||
"positive", orderNo);
|
||||
"set", orderNo);
|
||||
/*CreditsDetail creditsDetail = creditsService.queryDetailByTaskId(orderNo);
|
||||
if (Objects.isNull(creditsDetail)) {
|
||||
creditsService.insertToCreditsDetail(accountId,
|
||||
|
||||
@@ -34,7 +34,6 @@ import jakarta.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
@@ -80,9 +79,7 @@ public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate
|
||||
affiliate.setPromotionMethod(promotionMethod);
|
||||
baseMapper.insert(affiliate);
|
||||
// 邮件通知审批者
|
||||
String merchantEmail = "kimwong@code-create.com.hk";
|
||||
String developer = "xupei3360@163.com";
|
||||
String[] receiverEmail = {/*merchantEmail,*/ developer};
|
||||
String[] receiverEmail = buildMerchantReceiverEmail();
|
||||
SendEmailUtil.affiliateEmailReminder(receiverEmail, new AffiliateEmailParamsDTO(userHolder.getUsername(), promotionMethod), "new");
|
||||
// emailService.affiliateEmailReminder(Arrays.asList(/*merchantEmail,*/ developer), new AffiliateEmailParamsDTO(userHolder.getUsername(), promotionMethod), "new");
|
||||
}else {
|
||||
@@ -440,9 +437,7 @@ public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate
|
||||
affiliateEmailParamsDTO.setUnpaidEarnings(String.valueOf(unpaidCommission));
|
||||
affiliateEmailParamsDTO.setPaidEarnings(String.valueOf(paidCommission));
|
||||
|
||||
String merchantEmail = "kimwong@code-create.com.hk";
|
||||
String developer = "xupei3360@163.com";
|
||||
String[] receiverEmail = {/*merchantEmail,*/ developer};
|
||||
String[] receiverEmail = buildMerchantReceiverEmail();
|
||||
// 邮件通知
|
||||
SendEmailUtil.affiliateEmailReminder(receiverEmail, affiliateEmailParamsDTO, "summary");
|
||||
// emailService.affiliateEmailReminder(Arrays.asList(/*merchantEmail,*/ developer), affiliateEmailParamsDTO, "summary");
|
||||
@@ -607,4 +602,8 @@ public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate
|
||||
coupon.setUnpaidCommission(unpaidCommission);
|
||||
}
|
||||
|
||||
private String[] buildMerchantReceiverEmail() {
|
||||
return SendEmailUtil.buildMerchantReceiverEmail();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -524,7 +524,7 @@ public class CollectionElementServiceImpl extends ServiceImpl<CollectionElementM
|
||||
elementVO.setPrintBoardElements(printBoardElements);
|
||||
if (!CollectionUtils.isEmpty(printBoardIds)) {
|
||||
// 从数据库批量查询printBoard元素
|
||||
printBoardElements = collectionElementMapper.selectBatchIds(printBoardIds);
|
||||
printBoardElements.addAll(collectionElementMapper.selectBatchIds(printBoardIds));
|
||||
// 验证查询结果的完整性
|
||||
if (CollectionUtil.isEmpty(printBoardElements) || printBoardElements.size() != printBoardIds.size()) {
|
||||
throw new BusinessException("get.printBoards.data.is.mismatch");
|
||||
|
||||
@@ -787,6 +787,14 @@ public class ConvenientInquiryServiceImpl extends ServiceImpl<QuestionnaireMappe
|
||||
queryWrapper.lt("create_date", queryUserConditionsVO.getEndTime());
|
||||
}
|
||||
|
||||
if (!Objects.isNull(queryUserConditionsVO.getSubscriptionPlanId())) {
|
||||
queryWrapper.eq("subscription_plan_id", queryUserConditionsVO.getSubscriptionPlanId());
|
||||
}
|
||||
|
||||
if (!Objects.isNull(queryUserConditionsVO.getOrganizationId())) {
|
||||
queryWrapper.eq("organization_id", queryUserConditionsVO.getOrganizationId());
|
||||
}
|
||||
|
||||
// 排序
|
||||
if (!StringUtils.isNullOrEmpty(queryUserConditionsVO.getOrder()) && !StringUtils.isNullOrEmpty(queryUserConditionsVO.getOrderBy())) {
|
||||
String orderBy = "id";
|
||||
|
||||
@@ -83,7 +83,7 @@ public class CreditsServiceImpl extends ServiceImpl<CreditsDetailMapper, Credits
|
||||
*
|
||||
* @param changeEvent 导致积分变更的事件
|
||||
* @param credits 变更的积分
|
||||
* @param changeType 变更类型 : positive->增 negative->减
|
||||
* @param changeType 变更类型 : positive->增 negative->减 set->重置
|
||||
*/
|
||||
@Override
|
||||
public void insertToCreditsDetail(Long accountId, String changeEvent, String credits, String changeType, String orderNo) {
|
||||
@@ -94,9 +94,11 @@ public class CreditsServiceImpl extends ServiceImpl<CreditsDetailMapper, Credits
|
||||
if ("positive".equals(changeType)) {
|
||||
// finalCredits = account.getCredits().add(new BigDecimal(credits));
|
||||
changeCredits = "+" + credits;
|
||||
} else {
|
||||
} else if ("negative".equals(changeType)) {
|
||||
// finalCredits = account.getCredits().subtract(new BigDecimal(credits));
|
||||
changeCredits = "-" + credits;
|
||||
} else {
|
||||
changeCredits = credits;
|
||||
}
|
||||
creditsDetail.setAccountId(accountId);
|
||||
creditsDetail.setChangeEvent(changeEvent);
|
||||
@@ -107,6 +109,7 @@ public class CreditsServiceImpl extends ServiceImpl<CreditsDetailMapper, Credits
|
||||
creditsDetail.setCreateTime(LocalDateTime.now());
|
||||
|
||||
baseMapper.insert(creditsDetail);
|
||||
log.info("creditsDetail inserted");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -756,7 +756,7 @@ public class DesignServiceImpl extends ServiceImpl<DesignMapper, Design> impleme
|
||||
print.setPosition("[0.0,0.0]");
|
||||
// print.setScale(1d);
|
||||
// todo mark 将print默认scale置为0.3
|
||||
print.setScale(Arrays.toString(new Float[]{0.3f, 0.3f}));
|
||||
print.setScale(Arrays.toString(new Float[]{1.0f, 1.0f}));
|
||||
print.setAngle(0.0);
|
||||
print.setPriority(1);
|
||||
QueryWrapper<CollectionElement> getPrintboardLevel2TypeQw = new QueryWrapper<>();
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.ai.da.common.response.ResultEnum;
|
||||
import com.ai.da.common.utils.DateUtil;
|
||||
import com.ai.da.common.utils.MailUtil;
|
||||
import com.ai.da.common.utils.RedisUtil;
|
||||
import com.ai.da.common.utils.SendEmailUtil;
|
||||
import com.ai.da.mapper.primary.AccountMapper;
|
||||
import com.ai.da.mapper.primary.EmailLogMapper;
|
||||
import com.ai.da.mapper.primary.EmailTemplateMapper;
|
||||
@@ -585,9 +586,7 @@ public class EmailServiceImpl implements EmailService {
|
||||
|
||||
public boolean subscriptionEmailReminder(String type, SubscriptionEmailParamsDTO subscriptionEmailParamsDTO, String language, String receiverAddress) {
|
||||
try {
|
||||
String merchantEmail = "kimwong@code-create.com.hk";
|
||||
String developer = "xupei3360@163.com";
|
||||
List<String> merchantReceiver = Arrays.asList(/*merchantEmail,*/ developer);
|
||||
List<String> merchantReceiver = buildMerchantReceiverList();
|
||||
|
||||
String merchantSubject = null;
|
||||
String merchantTemplate = null;
|
||||
@@ -723,15 +722,13 @@ public class EmailServiceImpl implements EmailService {
|
||||
|
||||
private final static String CREDITS_PURCHASE_MERCHANT = "133275_AiDA 积分购买通知-merchant.html";
|
||||
public void creditsPurchaseReminder(String username, String quantity, String amount) {
|
||||
String merchantEmail = "kimwong@code-create.com.hk";
|
||||
String developerEmail = "xupei@code-create.com.hk";
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
// 设置试用订单相关数据
|
||||
jsonObject.put("username", username);
|
||||
jsonObject.put("quantity", quantity);
|
||||
jsonObject.put("totalFee", amount);
|
||||
|
||||
sendEmail(Arrays.asList(/*merchantEmail,*/ developerEmail), jsonObject, CREDITS_PURCHASE_MERCHANT, "New Credit Purchase Order", null, null);
|
||||
sendEmail(buildMerchantReceiverList(), jsonObject, CREDITS_PURCHASE_MERCHANT, "New Credit Purchase Order", null, null);
|
||||
}
|
||||
|
||||
private final static String COMMON_EXCEPTION_REMINDER = "135279_common-exception-reminder.html";
|
||||
@@ -742,6 +739,10 @@ public class EmailServiceImpl implements EmailService {
|
||||
|
||||
sendEmail(destination, param, COMMON_EXCEPTION_REMINDER, "AiDA发生异常,请及时处理", null, null);
|
||||
}
|
||||
|
||||
private List<String> buildMerchantReceiverList() {
|
||||
return Arrays.asList(SendEmailUtil.buildMerchantReceiverEmail());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1553,11 +1553,11 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
|
||||
if (imagePath != null) {
|
||||
requestBuilder.image(finalImagePath1);
|
||||
}
|
||||
if (useModel.equals(ModelConstants.PRINTBOARD_HIGH_I2I)) {
|
||||
if (useModel.equals(ModelConstants.PRINTBOARD_HIGH_I2I)|| useModel.equals(ModelConstants.PRINTBOARD_HIGH_T2I)) {
|
||||
GenerateImagesRequest.OptimizePromptOptions optimizePromptOptions = new GenerateImagesRequest.OptimizePromptOptions();
|
||||
optimizePromptOptions.setMode("fast");
|
||||
requestBuilder.optimizePromptOptions(optimizePromptOptions);
|
||||
//由于PRINTBOARD_HIGH_I2I与PRINTBOARD_ADVANCED_I2I使用模型一致,为了区别积分扣除,PRINTBOARD_HIGH_I2I加入了-fast,但传入模型时需要去掉-fast,用PRINTBOARD_ADVANCED_I2I的常量做替代
|
||||
//由于PRINTBOARD_HIGH_T2I,PRINTBOARD_HIGH_I2I与PRINTBOARD_ADVANCED_I2I使用模型一致,为了区别积分扣除,PRINTBOARD_HIGH_I2I加入了-fast或者-high,但传入模型时需要去掉-fast或者-high,用PRINTBOARD_ADVANCED_I2I的常量做替代
|
||||
requestBuilder.model(ModelConstants.PRINTBOARD_ADVANCED_I2I);
|
||||
}
|
||||
|
||||
@@ -3934,11 +3934,48 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
|
||||
}
|
||||
|
||||
public byte[] downloadVideoOrImage(String url) {
|
||||
try (CloseableHttpClient client = HttpClients.createDefault();
|
||||
InputStream in = client.execute(new HttpGet(url)).getEntity().getContent()) {
|
||||
return IOUtils.toByteArray(in);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
int maxRetries = 3;
|
||||
int retryDelayMs = 1000;
|
||||
IOException lastException = null;
|
||||
|
||||
for (int attempt = 1; attempt <= maxRetries; attempt++) {
|
||||
try {
|
||||
return downloadWithTimeout(url, 30000, 60000);
|
||||
} catch (IOException e) {
|
||||
lastException = e;
|
||||
log.warn("下载失败 (尝试 {}/{}): {}", attempt, maxRetries, e.getMessage());
|
||||
|
||||
if (attempt < maxRetries) {
|
||||
try {
|
||||
Thread.sleep((long) retryDelayMs * attempt); // 递增延迟
|
||||
} catch (InterruptedException ie) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new RuntimeException(ie);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new RuntimeException("下载失败,已重试 " + maxRetries + " 次", lastException);
|
||||
}
|
||||
|
||||
private byte[] downloadWithTimeout(String url, int connectTimeout, int socketTimeout) throws IOException {
|
||||
RequestConfig requestConfig = RequestConfig.custom()
|
||||
.setConnectTimeout(connectTimeout)
|
||||
.setSocketTimeout(socketTimeout)
|
||||
.setConnectionRequestTimeout(connectTimeout)
|
||||
.build();
|
||||
|
||||
try (CloseableHttpClient client = HttpClients.custom()
|
||||
.setDefaultRequestConfig(requestConfig)
|
||||
.build();
|
||||
CloseableHttpResponse response = client.execute(new HttpGet(url))) {
|
||||
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
if (statusCode != 200) {
|
||||
throw new IOException("HTTP Error: " + statusCode);
|
||||
}
|
||||
return IOUtils.toByteArray(response.getEntity().getContent());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@ import com.ai.da.mapper.primary.entity.Notification;
|
||||
import com.ai.da.model.dto.ContestantDTO;
|
||||
import com.ai.da.model.dto.PublishSysNotificationDTO;
|
||||
import com.ai.da.model.vo.CheckOTPVO;
|
||||
import com.ai.da.model.vo.ContestantCountVO;
|
||||
import com.ai.da.model.vo.PageVisitCountVO;
|
||||
import com.ai.da.service.GlobalAwardService;
|
||||
import com.ai.da.service.MessageCenterService;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
@@ -26,24 +28,22 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.io.FileOutputStream;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@@ -187,6 +187,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
||||
.videoSize(request.getVideoSize())
|
||||
.pdfSize(request.getPdfSize())
|
||||
.contestantNumber(nextNumber)
|
||||
.portfolioUrl(request.getPortfolioUrl())
|
||||
.createdAt(now)
|
||||
.updatedAt(now)
|
||||
.build();
|
||||
@@ -227,6 +228,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
||||
existing.setVideoDuration(request.getVideoDuration());
|
||||
existing.setVideoSize(request.getVideoSize());
|
||||
existing.setPdfSize(request.getPdfSize());
|
||||
existing.setPortfolioUrl(request.getPortfolioUrl());
|
||||
existing.setUpdatedAt(now);
|
||||
contestantMapper.updateById(existing);
|
||||
resp.put("success", true);
|
||||
@@ -244,7 +246,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
||||
String[] headers = new String[] {
|
||||
"contestantNumber", "email", "firstName", "lastName", "gender", "occupation",
|
||||
"age", "countryRegionCity", "phoneNumber", "designTitle", "designDescription",
|
||||
"pdfPath", "videoPath", "videoDuration", "videoSizeMB", "pdfSizeMB", "createdAt", "updatedAt"
|
||||
"pdfPath", "videoPath", "videoDuration", "videoSizeMB", "pdfSizeMB", "portfolioUrl", "createdAt", "updatedAt"
|
||||
};
|
||||
for (int i = 0; i < headers.length; i++) {
|
||||
Cell c = header.createCell(i);
|
||||
@@ -265,11 +267,9 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
||||
r.createCell(ci++).setCellValue(cst.getPhoneNumber() == null ? "" : cst.getPhoneNumber());
|
||||
r.createCell(ci++).setCellValue(cst.getDesignTitle() == null ? "" : cst.getDesignTitle());
|
||||
r.createCell(ci++).setCellValue(cst.getDesignDescription() == null ? "" : cst.getDesignDescription());
|
||||
// r.createCell(ci++).setCellValue(cst.getPdfPath() == null ? "" : cst.getPdfPath());
|
||||
// r.createCell(ci++).setCellValue(cst.getVideoPath() == null ? "" : cst.getVideoPath());
|
||||
// 视频时长(秒)
|
||||
r.createCell(ci++).setCellValue(cst.getPdfPath() == null ? "" : cst.getPdfPath());
|
||||
r.createCell(ci++).setCellValue(cst.getVideoPath() == null ? "" : cst.getVideoPath());
|
||||
r.createCell(ci++).setCellValue(cst.getVideoDuration() == null ? "" : cst.getVideoDuration().toString());
|
||||
// 视频大小、PDF 大小:以 MB 导出,保留两位小数
|
||||
if (cst.getVideoSize() == null) {
|
||||
r.createCell(ci++).setCellValue("");
|
||||
} else {
|
||||
@@ -282,6 +282,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
||||
double pMb = cst.getPdfSize() / 1024.0 / 1024.0;
|
||||
r.createCell(ci++).setCellValue(String.format("%.2f", pMb));
|
||||
}
|
||||
r.createCell(ci++).setCellValue(cst.getPortfolioUrl() == null ? "" : cst.getPortfolioUrl());
|
||||
r.createCell(ci++).setCellValue(cst.getCreatedAt() == null ? "" : cst.getCreatedAt().toString());
|
||||
r.createCell(ci++).setCellValue(cst.getUpdatedAt() == null ? "" : cst.getUpdatedAt().toString());
|
||||
}
|
||||
@@ -311,7 +312,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
||||
String[] headers = new String[] {
|
||||
"contestantNumber", "email", "firstName", "lastName", "gender", "occupation",
|
||||
"age", "countryRegionCity", "phoneNumber", "designTitle", "designDescription",
|
||||
"pdfPath", "videoPath", "videoDuration", "videoSizeMB", "pdfSizeMB", "createdAt", "updatedAt"
|
||||
"pdfPath", "videoPath", "videoDuration", "videoSizeMB", "pdfSizeMB", "portfolioUrl", "createdAt", "updatedAt"
|
||||
};
|
||||
for (int i = 0; i < headers.length; i++) {
|
||||
Cell c = header.createCell(i);
|
||||
@@ -332,11 +333,9 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
||||
r.createCell(ci++).setCellValue(cst.getPhoneNumber() == null ? "" : cst.getPhoneNumber());
|
||||
r.createCell(ci++).setCellValue(cst.getDesignTitle() == null ? "" : cst.getDesignTitle());
|
||||
r.createCell(ci++).setCellValue(cst.getDesignDescription() == null ? "" : cst.getDesignDescription());
|
||||
// r.createCell(ci++).setCellValue(cst.getPdfPath() == null ? "" : cst.getPdfPath());
|
||||
// r.createCell(ci++).setCellValue(cst.getVideoPath() == null ? "" : cst.getVideoPath());
|
||||
// 视频时长(秒)
|
||||
r.createCell(ci++).setCellValue(cst.getPdfPath() == null ? "" : cst.getPdfPath());
|
||||
r.createCell(ci++).setCellValue(cst.getVideoPath() == null ? "" : cst.getVideoPath());
|
||||
r.createCell(ci++).setCellValue(cst.getVideoDuration() == null ? "" : cst.getVideoDuration().toString());
|
||||
// 视频大小、PDF 大小:以 MB 导出,保留两位小数
|
||||
if (cst.getVideoSize() == null) {
|
||||
r.createCell(ci++).setCellValue("");
|
||||
} else {
|
||||
@@ -349,6 +348,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
||||
double pMb = cst.getPdfSize() / 1024.0 / 1024.0;
|
||||
r.createCell(ci++).setCellValue(String.format("%.2f", pMb));
|
||||
}
|
||||
r.createCell(ci++).setCellValue(cst.getPortfolioUrl() == null ? "" : cst.getPortfolioUrl());
|
||||
r.createCell(ci++).setCellValue(cst.getCreatedAt() == null ? "" : cst.getCreatedAt().toString());
|
||||
r.createCell(ci++).setCellValue(cst.getUpdatedAt() == null ? "" : cst.getUpdatedAt().toString());
|
||||
}
|
||||
@@ -387,6 +387,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
||||
dto.setVideoDuration(existing.getVideoDuration());
|
||||
dto.setPdfSize(existing.getPdfSize());
|
||||
dto.setVideoSize(existing.getVideoSize());
|
||||
dto.setPortfolioUrl(existing.getPortfolioUrl());
|
||||
return dto;
|
||||
}
|
||||
|
||||
@@ -480,7 +481,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int exportContestantFiles(Integer minContestantNumber, Integer maxContestantNumber) throws Exception {
|
||||
public byte[] exportContestantFilesAsZip(Integer minContestantNumber, Integer maxContestantNumber) throws Exception {
|
||||
if (minContestantNumber == null || maxContestantNumber == null) {
|
||||
throw new BusinessException("minContestantNumber and maxContestantNumber are required.");
|
||||
}
|
||||
@@ -488,7 +489,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
||||
throw new BusinessException("minContestantNumber cannot be greater than maxContestantNumber.");
|
||||
}
|
||||
|
||||
// 1. 根据contestantNumber范围查询参赛者
|
||||
// 1. 根据 contestantNumber 范围查询参赛者
|
||||
QueryWrapper<Contestant> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.lambda()
|
||||
.ge(Contestant::getContestantNumber, minContestantNumber)
|
||||
@@ -498,91 +499,158 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
||||
|
||||
if (contestants.isEmpty()) {
|
||||
log.info("No contestants found in range [{}, {}]", minContestantNumber, maxContestantNumber);
|
||||
return 0;
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
// 2. 创建基础目录
|
||||
String baseDir = uploadDir + "/contestants";
|
||||
Path basePath = Paths.get(baseDir).toAbsolutePath();
|
||||
Files.createDirectories(basePath);
|
||||
log.info("Base directory created: {}", basePath);
|
||||
// 2. 在内存中构建 ZIP
|
||||
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
java.util.zip.ZipOutputStream zos = new java.util.zip.ZipOutputStream(baos)) {
|
||||
|
||||
int exportedCount = 0;
|
||||
|
||||
// 3. 遍历每个参赛者,下载文件
|
||||
for (Contestant contestant : contestants) {
|
||||
Integer contestantNumber = contestant.getContestantNumber();
|
||||
if (contestantNumber == null) {
|
||||
log.warn("Contestant {} has no contestantNumber, skipping", contestant.getId());
|
||||
continue;
|
||||
}
|
||||
|
||||
// 创建参赛者文件夹
|
||||
String contestantDir = baseDir + "/" + contestantNumber;
|
||||
Path contestantPath = Paths.get(contestantDir);
|
||||
Files.createDirectories(contestantPath);
|
||||
|
||||
// 下载PDF文件
|
||||
String pdfPath = contestant.getPdfPath();
|
||||
if (StringUtils.isNotBlank(pdfPath)) {
|
||||
try {
|
||||
String fileName = pdfPath.contains("/") ?
|
||||
pdfPath.substring(pdfPath.lastIndexOf("/") + 1) : "design.pdf";
|
||||
downloadFileFromMinio(pdfPath, contestantPath.toString(), "design.pdf");
|
||||
log.info("Downloaded PDF for contestant {}", fileName);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to download PDF for contestant {}: {}", contestantNumber, e.getMessage());
|
||||
for (Contestant contestant : contestants) {
|
||||
Integer contestantNumber = contestant.getContestantNumber();
|
||||
if (contestantNumber == null) {
|
||||
log.warn("Contestant {} has no contestantNumber, skipping", contestant.getId());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 下载视频文件
|
||||
String videoPath = contestant.getVideoPath();
|
||||
if (StringUtils.isNotBlank(videoPath)) {
|
||||
try {
|
||||
// 根据路径判断视频格式
|
||||
String dirPrefix = contestantNumber + "/";
|
||||
|
||||
// 添加 PDF 文件
|
||||
String pdfPath = contestant.getPdfPath();
|
||||
if (StringUtils.isNotBlank(pdfPath)) {
|
||||
addMinioFileToZip(zos, pdfPath, dirPrefix + "design.pdf");
|
||||
}
|
||||
|
||||
// 添加视频文件
|
||||
String videoPath = contestant.getVideoPath();
|
||||
if (StringUtils.isNotBlank(videoPath)) {
|
||||
String fileName = videoPath.contains("/") ?
|
||||
videoPath.substring(videoPath.lastIndexOf("/") + 1) : "video.mp4";
|
||||
downloadFileFromMinio(videoPath, contestantPath.toString(), fileName);
|
||||
log.info("Downloaded video for contestant {}", contestantNumber);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to download video for contestant {}: {}", contestantNumber, e.getMessage());
|
||||
addMinioFileToZip(zos, videoPath, dirPrefix + fileName);
|
||||
}
|
||||
|
||||
// 添加参赛者信息 txt 文件
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("=== Contestant Information ===\n\n");
|
||||
sb.append("ID: ").append(nullSafe(contestant.getId())).append("\n");
|
||||
sb.append("Email: ").append(nullSafe(contestant.getEmail())).append("\n");
|
||||
sb.append("Contestant Number: ").append(contestantNumber).append("\n");
|
||||
sb.append("First Name: ").append(nullSafe(contestant.getFirstName())).append("\n");
|
||||
sb.append("Last Name: ").append(nullSafe(contestant.getLastName())).append("\n");
|
||||
sb.append("Gender: ").append(nullSafe(contestant.getGender())).append("\n");
|
||||
sb.append("Occupation: ").append(nullSafe(contestant.getOccupation())).append("\n");
|
||||
sb.append("Age: ").append(contestant.getAge() != null ? contestant.getAge() : "N/A").append("\n");
|
||||
sb.append("Country/Region/City: ").append(nullSafe(contestant.getCountryRegionCity())).append("\n");
|
||||
sb.append("Phone Number: ").append(nullSafe(contestant.getPhoneNumber())).append("\n");
|
||||
sb.append("Design Title: ").append(nullSafe(contestant.getDesignTitle())).append("\n");
|
||||
sb.append("Design Description: ").append(nullSafe(contestant.getDesignDescription())).append("\n");
|
||||
sb.append("PDF Path: ").append(nullSafe(pdfPath)).append("\n");
|
||||
sb.append("PDF Size (bytes): ").append(contestant.getPdfSize() != null ? contestant.getPdfSize() : "N/A").append("\n");
|
||||
sb.append("Video Path: ").append(nullSafe(videoPath)).append("\n");
|
||||
sb.append("Video Duration (seconds): ").append(contestant.getVideoDuration() != null ? contestant.getVideoDuration() : "N/A").append("\n");
|
||||
sb.append("Video Size (bytes): ").append(contestant.getVideoSize() != null ? contestant.getVideoSize() : "N/A").append("\n");
|
||||
sb.append("Portfolio URL: ").append(nullSafe(contestant.getPortfolioUrl())).append("\n");
|
||||
sb.append("Created At: ").append(contestant.getCreatedAt() != null ? contestant.getCreatedAt() : "N/A").append("\n");
|
||||
sb.append("Updated At: ").append(contestant.getUpdatedAt() != null ? contestant.getUpdatedAt() : "N/A").append("\n");
|
||||
|
||||
ZipEntry infoEntry = new ZipEntry(dirPrefix + "contestant_info.txt");
|
||||
zos.putNextEntry(infoEntry);
|
||||
zos.write(sb.toString().getBytes(java.nio.charset.StandardCharsets.UTF_8));
|
||||
zos.closeEntry();
|
||||
log.info("Added contestant {} info to zip", contestantNumber);
|
||||
}
|
||||
|
||||
exportedCount++;
|
||||
zos.finish();
|
||||
log.info("ZIP built for {} contestants, size: {} bytes", contestants.size(), baos.size());
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
log.info("Exported {} contestants' files to {}", exportedCount, basePath);
|
||||
return exportedCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从MinIO下载文件到本地
|
||||
* @param minioPath MinIO路径 (格式: bucketName/objectPath)
|
||||
* @param localDir 本地目录
|
||||
* @param fileName 本地文件名
|
||||
* 将 MinIO 文件流式写入 ZIP,不落盘
|
||||
* @param zos ZIP 输出流
|
||||
* @param minioPath MinIO 路径(格式: bucketName/objectPath)
|
||||
* @param entryName ZIP 条目名称
|
||||
*/
|
||||
private void downloadFileFromMinio(String minioPath, String localDir, String fileName) {
|
||||
private void addMinioFileToZip(java.util.zip.ZipOutputStream zos, String minioPath, String entryName) {
|
||||
if (StringUtils.isBlank(minioPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 从路径中提取bucket名称和对象名称
|
||||
int index = minioPath.indexOf("/");
|
||||
if (index == -1) {
|
||||
log.warn("Invalid MinIO path: {}", minioPath);
|
||||
return;
|
||||
}
|
||||
|
||||
String bucketName = minioPath.substring(0, index);
|
||||
String objectName = minioPath.substring(index + 1);
|
||||
|
||||
// 构建本地文件完整路径
|
||||
Path localFilePath = Paths.get(localDir, fileName);
|
||||
|
||||
// 下载文件
|
||||
minioUtil.downloadMinioObjectToLocal(bucketName, objectName, localFilePath.toString());
|
||||
try (InputStream in = minioUtil.download(bucketName, objectName)) {
|
||||
ZipEntry entry = new ZipEntry(entryName);
|
||||
zos.putNextEntry(entry);
|
||||
byte[] buffer = new byte[8192];
|
||||
int bytesRead;
|
||||
while ((bytesRead = in.read(buffer)) != -1) {
|
||||
zos.write(buffer, 0, bytesRead);
|
||||
}
|
||||
zos.closeEntry();
|
||||
log.info("Added {} to zip ({} bytes)", entryName, entry.getSize());
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to add {} to zip: {}", entryName, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContestantCountVO getContestantCount() {
|
||||
long count = contestantMapper.selectCount(null);
|
||||
Integer maxContestantNumber = null;
|
||||
QueryWrapper<Contestant> qMax = new QueryWrapper<>();
|
||||
qMax.isNotNull("contestant_number");
|
||||
qMax.orderByDesc("contestant_number");
|
||||
qMax.last("LIMIT 1");
|
||||
Contestant last = contestantMapper.selectOne(qMax);
|
||||
if (last != null) {
|
||||
maxContestantNumber = last.getContestantNumber();
|
||||
}
|
||||
return ContestantCountVO.builder()
|
||||
.count(count)
|
||||
.maxContestantNumber(maxContestantNumber)
|
||||
.build();
|
||||
}
|
||||
|
||||
private String nullSafe(String value) {
|
||||
return value != null ? value : "N/A";
|
||||
}
|
||||
|
||||
private static final String RAW_VISIT_COUNT_KEY = "GLOBAL_AWARD:visit:raw";
|
||||
private static final String UNIQUE_VISIT_SET_KEY = "GLOBAL_AWARD:visit:unique";
|
||||
private static final String SESSION_VISIT_KEY_PREFIX = "GLOBAL_AWARD:visit:session:";
|
||||
private static final long SESSION_DEDUP_SECONDS = 5L;
|
||||
|
||||
@Override
|
||||
public void recordPageVisit(String sessionId) {
|
||||
redisUtil.increaseCount(RAW_VISIT_COUNT_KEY);
|
||||
|
||||
if (StringUtils.isNotBlank(sessionId)) {
|
||||
String sessionKey = SESSION_VISIT_KEY_PREFIX + sessionId;
|
||||
if (!redisUtil.hasKey(sessionKey)) {
|
||||
redisUtil.increaseCount(UNIQUE_VISIT_SET_KEY);
|
||||
redisUtil.addToString(sessionKey, "1", SESSION_DEDUP_SECONDS);
|
||||
}
|
||||
} else {
|
||||
redisUtil.increaseCount(UNIQUE_VISIT_SET_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageVisitCountVO getPageVisitCount() {
|
||||
Long raw = redisUtil.getIncrementCount(RAW_VISIT_COUNT_KEY);
|
||||
Long unique = redisUtil.getIncrementCount(UNIQUE_VISIT_SET_KEY);
|
||||
return PageVisitCountVO.builder()
|
||||
.rawVisitCount(raw != null ? raw : 0L)
|
||||
.uniqueVisitCount(unique != null ? unique : 0L)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -451,11 +451,12 @@ public class StripeServiceImpl implements StripeService {
|
||||
String periodEnd = DateUtil.changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_yyyy_MM_dd_HH_mm_ss);
|
||||
|
||||
qwPI.lambda().eq(PaymentInfo::getOrderNo, subscriptionInfo.getOrderNo())
|
||||
.eq(PaymentInfo::getTradeState, "paid")
|
||||
.between(PaymentInfo::getCreateTime, periodStart, periodEnd)
|
||||
.orderByDesc(PaymentInfo::getId);
|
||||
List<PaymentInfo> paymentInfos = paymentInfoMapper.selectList(qwPI);
|
||||
if (paymentInfos.isEmpty()) {
|
||||
log.info("不发送邮件,原因:【根据order_no:{},查询到的paymentInfos为空】", orderNo);
|
||||
log.info("不发送邮件,原因:【根据order_no:{},查询到的成功的paymentInfos为空】", orderNo);
|
||||
return false;
|
||||
}
|
||||
PaymentInfo paymentInfo = paymentInfos.get(0);
|
||||
@@ -485,7 +486,8 @@ public class StripeServiceImpl implements StripeService {
|
||||
emailParamsDTO.setEmail(account.getUserEmail());
|
||||
emailParamsDTO.setCountry(paymentInfo.getCountry());
|
||||
emailParamsDTO.setOrderId(paymentInfo.getId().toString());
|
||||
emailParamsDTO.setOrderRef("\"" + orderListLink + paymentInfo.getId().toString() + "\"");
|
||||
// emailParamsDTO.setOrderRef("\"" + orderListLink + paymentInfo.getId().toString() + "\"");
|
||||
emailParamsDTO.setOrderRef("\"" + paymentInfo.getHostedInvoiceUrl() + "\"");
|
||||
emailParamsDTO.setCreateDate(String.valueOf(paymentInfo.getCreateTime()).replace("T", " "));
|
||||
emailParamsDTO.setQuantity(String.valueOf(1));
|
||||
emailParamsDTO.setTotalFee(paymentInfo.getPayerTotal().toString());
|
||||
|
||||
@@ -84,24 +84,29 @@ public class StripeSubscriptionServiceImpl implements StripeSubscriptionService
|
||||
SubscriptionInfo passedSubscriptionInfo) {
|
||||
SubscriptionInfo subscriptionInfo = resolveSubscriptionInfo(subscription, type, orderNo, passedSubscriptionInfo);
|
||||
if (subscriptionInfo == null) {
|
||||
log.info("subscriptionInfo为null,不发送邮件");
|
||||
return false;
|
||||
}
|
||||
OrderInfo orderByOrderNo = orderInfoService.getOrderByOrderNo(subscriptionInfo.getOrderNo());
|
||||
if (orderByOrderNo == null) {
|
||||
log.info("orderByOrderNo为null,不发送邮件");
|
||||
return false;
|
||||
}
|
||||
Account account = accountMapper.selectById(subscriptionInfo.getAccountId());
|
||||
if (account == null) {
|
||||
log.info("account为null,不发送邮件");
|
||||
return false;
|
||||
}
|
||||
|
||||
PaymentInfo paymentInfo = resolvePaymentInfo(subscriptionInfo, orderNo, type);
|
||||
if (paymentInfo == null) {
|
||||
log.info("paymentInfo为null,不发送邮件");
|
||||
return false;
|
||||
}
|
||||
|
||||
String resolvedType = resolveEmailType(type, paymentInfo);
|
||||
if (isEmailAlreadySent(subscriptionInfo, resolvedType, paymentInfo)) {
|
||||
log.info("邮件已发送,取消重复发送");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -130,13 +135,15 @@ public class StripeSubscriptionServiceImpl implements StripeSubscriptionService
|
||||
// renewal 场景:从 InvoicePaidHandler 直接传入已更新的 SubscriptionInfo,避免事务未提交导致查询不到
|
||||
if (passedInfo != null) {
|
||||
long now = Instant.now().getEpochSecond();
|
||||
// 限制当前时间在订阅区间内,避免处理上个周期内的回调而重复发送邮件
|
||||
if (now > passedInfo.getCurrentPeriodStart() && now < passedInfo.getCurrentPeriodEnd()
|
||||
&& "active".equals(passedInfo.getStatus())) {
|
||||
boolean inPeriod = now > passedInfo.getCurrentPeriodStart() && now < passedInfo.getCurrentPeriodEnd();
|
||||
// 续订失败的场景,可能订单状态已被更新为past_due
|
||||
boolean validStatus = "past_due".equals(passedInfo.getStatus()) || "active".equals(passedInfo.getStatus());
|
||||
if (inPeriod && validStatus) {
|
||||
return passedInfo;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!StringUtil.isNullOrEmpty(orderNo)) {
|
||||
long now = Instant.now().getEpochSecond();
|
||||
List<SubscriptionInfo> infos = subscriptionInfoMapper.selectList(
|
||||
@@ -175,7 +182,7 @@ public class StripeSubscriptionServiceImpl implements StripeSubscriptionService
|
||||
.orderByDesc("id")
|
||||
.last("LIMIT 1");
|
||||
if (!type.contains("fail")) {
|
||||
last.in("trade_state", "paid", "COMPLETED");
|
||||
last.in("trade_state", "paid", "COMPLETED", "Refunded");
|
||||
}
|
||||
List<PaymentInfo> infos = paymentInfoMapper.selectList(last);
|
||||
return infos.isEmpty() ? null : infos.getFirst();
|
||||
@@ -348,7 +355,9 @@ public class StripeSubscriptionServiceImpl implements StripeSubscriptionService
|
||||
params.setEmail(account.getUserEmail());
|
||||
params.setCountry(paymentInfo.getCountry());
|
||||
params.setOrderId(paymentInfo.getId().toString());
|
||||
params.setOrderRef("\"" + orderListLink + paymentInfo.getId().toString() + "\"");
|
||||
// params.setOrderRef("\"" + orderListLink + paymentInfo.getId().toString() + "\"");
|
||||
params.setOrderRef("\"" + paymentInfo.getHostedInvoiceUrl() + "\"");
|
||||
|
||||
params.setCreateDate(String.valueOf(paymentInfo.getCreateTime()).replace("T", " "));
|
||||
params.setQuantity("1");
|
||||
params.setTotalFee(paymentInfo.getPayerTotal() != null ? paymentInfo.getPayerTotal().toString() : "0");
|
||||
|
||||
@@ -905,15 +905,15 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
|
||||
}
|
||||
}
|
||||
// 将构建好的结果对象添加到返回列表
|
||||
results.add(magicToolResultVO);
|
||||
// results.add(magicToolResultVO);
|
||||
} else if (Objects.isNull(magicToolResultVO)) {
|
||||
// 如果Redis中没有结果对象,创建执行中状态的结果对象
|
||||
magicToolResultVO = new MagicToolResultVO(taskId, "Executing");
|
||||
results.add(magicToolResultVO);
|
||||
} else {
|
||||
// results.add(magicToolResultVO);
|
||||
}/* else {
|
||||
// 如果Redis中有结果对象但URL为空,直接添加到返回列表
|
||||
results.add(magicToolResultVO);
|
||||
}
|
||||
}*/
|
||||
|
||||
// 收集任务状态用于统计
|
||||
if (!StringUtil.isNullOrEmpty(magicToolResultVO.getStatus())) collect.add(magicToolResultVO.getStatus());
|
||||
@@ -1461,12 +1461,16 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
|
||||
if (StringUtil.isNullOrEmpty(fluxResult)) {
|
||||
toProductImageResult.setStatus("Fail");
|
||||
toProductImageResultMapper.updateById(toProductImageResult);
|
||||
sortRank(toProductImageResult);
|
||||
if (toProductImageResult.getIsLike() != null && toProductImageResult.getIsLike() == 1) {
|
||||
sortRank(toProductImageResult);
|
||||
}
|
||||
results.add(new MagicToolResultVO(taskId, "Fail"));
|
||||
} else if (fluxResult.equals("Fail") || fluxResult.equals("Pending")) {
|
||||
toProductImageResult.setStatus(fluxResult);
|
||||
toProductImageResultMapper.updateById(toProductImageResult);
|
||||
sortRank(toProductImageResult);
|
||||
if (fluxResult.equals("Fail") && toProductImageResult.getIsLike() != null && toProductImageResult.getIsLike() == 1) {
|
||||
sortRank(toProductImageResult);
|
||||
}
|
||||
results.add(new MagicToolResultVO(taskId, fluxResult));
|
||||
} else {
|
||||
results.add(processFluxResult(fluxResult, toProductImageResult, taskId, toProductImageRecord.getPrompt()));
|
||||
@@ -2203,10 +2207,14 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
|
||||
childCollectionQw.lambda().orderByAsc(CollectionSort::getSort);
|
||||
List<CollectionSort> childSortList = collectionSortMapper.selectList(childCollectionQw);
|
||||
List<AllCollectionVO> childList = new ArrayList<>();
|
||||
// 收集需要删除的失败记录ID,用于后续统一清理并重新排序
|
||||
List<Long> failedSortIds = new ArrayList<>();
|
||||
for (CollectionSort userLikeSort : childSortList) {
|
||||
if (userLikeSort.getRelationType().equals(CollectionType.TO_PRODUCT_IMAGE.getValue())) {
|
||||
ToProductImageResult toProductImageResult = toProductImageResultMapper.selectById(userLikeSort.getRelationId());
|
||||
if (isGenerateTaskFailed(toProductImageResult.getStatus(), toProductImageResult.getCreateTime())) {
|
||||
failedSortIds.add(userLikeSort.getId());
|
||||
log.info("【获取内容】TO_PRODUCT_IMAGE结果失败,relationId={},即将从collection_sort中删除", userLikeSort.getRelationId());
|
||||
continue;
|
||||
}
|
||||
toProductImageResult.setUrl(getMinioUrl(toProductImageResult.getUrl()));
|
||||
@@ -2238,6 +2246,8 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
|
||||
} else if (userLikeSort.getRelationType().equals(CollectionType.RELIGHT.getValue())) {
|
||||
ToProductImageResult toProductImageResult = toProductImageResultMapper.selectById(userLikeSort.getRelationId());
|
||||
if (isGenerateTaskFailed(toProductImageResult.getStatus(), toProductImageResult.getCreateTime())) {
|
||||
failedSortIds.add(userLikeSort.getId());
|
||||
log.info("【获取内容】RELIGHT结果失败,relationId={},即将从collection_sort中删除", userLikeSort.getRelationId());
|
||||
continue;
|
||||
}
|
||||
toProductImageResult.setUrl(getMinioUrl(toProductImageResult.getUrl()));
|
||||
@@ -2269,6 +2279,8 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
|
||||
} else if (userLikeSort.getRelationType().equals(CollectionType.POSE_TRANSFORM.getValue())) {
|
||||
PoseTransformation item = poseTransformationMapper.selectById(userLikeSort.getRelationId());
|
||||
if (isGenerateTaskFailed(item.getTaskStatus(), item.getCreateTime())) {
|
||||
failedSortIds.add(userLikeSort.getId());
|
||||
log.info("【获取内容】POSE_TRANSFORM结果失败,relationId={},即将从collection_sort中删除", userLikeSort.getRelationId());
|
||||
continue;
|
||||
}
|
||||
PoseTransformationVO poseTransformationVO = new PoseTransformationVO();
|
||||
@@ -2293,6 +2305,114 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
|
||||
childList.add(poseTransformationVO);
|
||||
}
|
||||
}
|
||||
// 统一处理失败的记录:从collection_sort表中删除失败的记录,并重新排序
|
||||
if (CollectionUtil.isNotEmpty(failedSortIds)) {
|
||||
Long parentId = collectionSort.getId();
|
||||
Long projectId = projectDTO.getId();
|
||||
log.info("【获取内容】检测到{}条失败记录需要清理,parentId={}, projectId={}", failedSortIds.size(), parentId, projectId);
|
||||
for (Long failedSortId : failedSortIds) {
|
||||
CollectionSort failedRecord = collectionSortMapper.selectById(failedSortId);
|
||||
if (failedRecord != null) {
|
||||
String relationType = failedRecord.getRelationType();
|
||||
Long relationId = failedRecord.getRelationId();
|
||||
collectionSortService.deleteCollectionSort(relationId, relationType, projectId, parentId);
|
||||
log.info("【获取内容】已删除失败记录,relationId={}, relationType={}", relationId, relationType);
|
||||
}
|
||||
}
|
||||
// 重新查询子列表,获取更新后的排序
|
||||
childSortList = collectionSortMapper.selectList(childCollectionQw);
|
||||
// 重新构建childList,使用更新后的sort值
|
||||
childList = new ArrayList<>();
|
||||
for (CollectionSort userLikeSort : childSortList) {
|
||||
if (userLikeSort.getRelationType().equals(CollectionType.TO_PRODUCT_IMAGE.getValue())) {
|
||||
ToProductImageResult toProductImageResult = toProductImageResultMapper.selectById(userLikeSort.getRelationId());
|
||||
if (isGenerateTaskFailed(toProductImageResult.getStatus(), toProductImageResult.getCreateTime())) {
|
||||
continue;
|
||||
}
|
||||
toProductImageResult.setUrl(getMinioUrl(toProductImageResult.getUrl()));
|
||||
ToProductImageResultVO toProductImageResultVO = CopyUtil.copyObject(toProductImageResult, ToProductImageResultVO.class);
|
||||
|
||||
ToProductImageRecord toProductImageRecord = toProductImageRecordMapper.selectById(toProductImageResult.getToProductImageRecordId());
|
||||
if (Objects.isNull(toProductImageRecord)) {
|
||||
continue;
|
||||
}
|
||||
toProductImageResultVO.setPrompt(toProductImageRecord.getPrompt());
|
||||
|
||||
if (toProductImageResultVO.getElementType().equals("ProductElement")) {
|
||||
ToProductElement toProductElement = toProductElementMapper.selectById(toProductImageResultVO.getElementId());
|
||||
toProductImageResultVO.setSourceUrl(getMinioUrl(toProductElement.getUrl()));
|
||||
} else if ((toProductImageResultVO.getElementType().equals("DesignOutfit"))) {
|
||||
TDesignPythonOutfit tDesignPythonOutfit = designPythonOutfitMapper.selectById(toProductImageResultVO.getElementId());
|
||||
toProductImageResultVO.setSourceUrl(getMinioUrl(tDesignPythonOutfit.getDesignUrl()));
|
||||
} else {
|
||||
ToProductImageResult toProductImageResult1 = toProductImageResultMapper.selectById(toProductImageResultVO.getElementId());
|
||||
toProductImageResultVO.setSourceUrl(getMinioUrl(toProductImageResult1.getUrl()));
|
||||
}
|
||||
toProductImageResultVO.setCollectionType(CollectionType.TO_PRODUCT_IMAGE.getValue());
|
||||
toProductImageResultVO.setSort(userLikeSort.getSort());
|
||||
toProductImageResultVO.setUserLikeSortId(userLikeSort.getId());
|
||||
toProductImageResultVO.setRelationType(userLikeSort.getRelationType());
|
||||
toProductImageResultVO.setParentId(userLikeSort.getParentId());
|
||||
childList.add(toProductImageResultVO);
|
||||
} else if (userLikeSort.getRelationType().equals(CollectionType.RELIGHT.getValue())) {
|
||||
ToProductImageResult toProductImageResult = toProductImageResultMapper.selectById(userLikeSort.getRelationId());
|
||||
if (isGenerateTaskFailed(toProductImageResult.getStatus(), toProductImageResult.getCreateTime())) {
|
||||
continue;
|
||||
}
|
||||
toProductImageResult.setUrl(getMinioUrl(toProductImageResult.getUrl()));
|
||||
ToProductImageResultVO toProductImageResultVO = CopyUtil.copyObject(toProductImageResult, ToProductImageResultVO.class);
|
||||
|
||||
ToProductImageRecord toProductImageRecord = toProductImageRecordMapper.selectById(toProductImageResult.getToProductImageRecordId());
|
||||
if (Objects.isNull(toProductImageRecord)) {
|
||||
continue;
|
||||
}
|
||||
toProductImageResultVO.setPrompt(toProductImageRecord.getPrompt());
|
||||
|
||||
if (toProductImageResultVO.getElementType().equals("ProductElement")) {
|
||||
ToProductElement toProductElement = toProductElementMapper.selectById(toProductImageResultVO.getElementId());
|
||||
toProductImageResultVO.setSourceUrl(getMinioUrl(toProductElement.getUrl()));
|
||||
} else if ((toProductImageResultVO.getElementType().equals("DesignOutfit"))) {
|
||||
TDesignPythonOutfit tDesignPythonOutfit = designPythonOutfitMapper.selectById(toProductImageResultVO.getElementId());
|
||||
toProductImageResultVO.setSourceUrl(getMinioUrl(tDesignPythonOutfit.getDesignUrl()));
|
||||
} else {
|
||||
ToProductImageResult toProductImageResult1 = toProductImageResultMapper.selectById(toProductImageResultVO.getElementId());
|
||||
toProductImageResultVO.setSourceUrl(getMinioUrl(toProductImageResult1.getUrl()));
|
||||
}
|
||||
toProductImageResultVO.setCollectionType(CollectionType.RELIGHT.getValue());
|
||||
toProductImageResultVO.setSort(userLikeSort.getSort());
|
||||
toProductImageResultVO.setUserLikeSortId(userLikeSort.getId());
|
||||
toProductImageResultVO.setRelationType(userLikeSort.getRelationType());
|
||||
toProductImageResultVO.setParentId(userLikeSort.getParentId());
|
||||
childList.add(toProductImageResultVO);
|
||||
} else if (userLikeSort.getRelationType().equals(CollectionType.POSE_TRANSFORM.getValue())) {
|
||||
PoseTransformation item = poseTransformationMapper.selectById(userLikeSort.getRelationId());
|
||||
if (isGenerateTaskFailed(item.getTaskStatus(), item.getCreateTime())) {
|
||||
continue;
|
||||
}
|
||||
PoseTransformationVO poseTransformationVO = new PoseTransformationVO();
|
||||
poseTransformationVO.setId(item.getId());
|
||||
poseTransformationVO.setTaskId(item.getUniqueId());
|
||||
poseTransformationVO.setProductImage(getMinioUrl(item.getProductImage()));
|
||||
poseTransformationVO.setLastFrameProductImage(getMinioUrl(item.getLastFrameProductImage()));
|
||||
poseTransformationVO.setPrompt(item.getPrompt());
|
||||
poseTransformationVO.setGifUrl(getMinioUrl(item.getGifUrl()));
|
||||
poseTransformationVO.setVideoUrl(getMinioUrl(item.getVideoUrl()));
|
||||
poseTransformationVO.setFirstFrameUrl(getMinioUrl(item.getFirstFrameUrl()));
|
||||
poseTransformationVO.setIsLiked(item.getIsLiked());
|
||||
poseTransformationVO.setCollectionType(CollectionType.POSE_TRANSFORM.getValue());
|
||||
poseTransformationVO.setSort(userLikeSort.getSort());
|
||||
poseTransformationVO.setUserLikeSortId(userLikeSort.getId());
|
||||
poseTransformationVO.setRelationType(userLikeSort.getRelationType());
|
||||
poseTransformationVO.setResultType(CollectionType.POSE_TRANSFORM.getValue());
|
||||
poseTransformationVO.setParentId(userLikeSort.getParentId());
|
||||
poseTransformationVO.setModelName(item.getModelName());
|
||||
poseTransformationVO.setPoseId(item.getPoseId());
|
||||
poseTransformationVO.setStatus(item.getTaskStatus());
|
||||
childList.add(poseTransformationVO);
|
||||
}
|
||||
}
|
||||
log.info("【获取内容】失败记录清理完成,重新排序后childList.size={}", childList.size());
|
||||
}
|
||||
o.setChildList(childList);
|
||||
|
||||
list.add(o);
|
||||
|
||||
@@ -187,10 +187,13 @@ public class CheckoutSessionCompletedHandler implements StripeEventHandler {
|
||||
log.info("[checkout.session.completed] 订阅记录创建完成,orderNo={},subscriptionId={},periodEnd={}",
|
||||
orderNo, subscriptionId, periodEnd);
|
||||
|
||||
stripeSubscriptionService.sendSubscriptionEmail(null, "new", orderNo, null);
|
||||
|
||||
log.info("[checkout.session.completed] 邮件通知完成 类型:new");
|
||||
boolean sent = stripeSubscriptionService.sendSubscriptionEmail(null, "new", orderNo, subscriptionInfo);
|
||||
|
||||
if (sent) {
|
||||
log.info("[checkout.session.completed] 邮件通知完成 类型:new");
|
||||
} else {
|
||||
log.info("[checkout.session.completed] 邮件通知未完成");
|
||||
}
|
||||
} catch (StripeException e) {
|
||||
log.error("[checkout.session.completed] 处理订阅记录失败,orderNo={},error={}", orderNo, e.getMessage());
|
||||
}
|
||||
|
||||
@@ -96,10 +96,6 @@ public class CheckoutSessionExpiredHandler implements StripeEventHandler {
|
||||
// 首次订阅失败
|
||||
stripeSubscriptionService.sendFailedNewOrderEmail(orderNo);
|
||||
log.info("[checkout.session.expired] 首次订阅失败邮件已发送,orderNo={}", orderNo);
|
||||
} else {
|
||||
// 续费失败 todo 续费不走这里吧?
|
||||
stripeSubscriptionService.sendSubscriptionEmail(null, "fail_renewal", subInfoList.getFirst().getOrderNo(), null);
|
||||
log.info("[checkout.session.expired] 续费失败邮件已发送,orderNo={}", orderNo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ public class InvoicePaidHandler implements StripeEventHandler {
|
||||
updateSubscriptionPeriod(invoice, subscriptionInfo);
|
||||
|
||||
// 更新用户积分、账号到期时间,添加积分详细记录
|
||||
accountService.updateAccountValidity(subscriptionInfo.getAccountId(), invoice.getPeriodEnd());
|
||||
accountService.updateAccountValidity(subscriptionInfo.getAccountId(), subscriptionInfo.getCurrentPeriodEnd());
|
||||
accountService.updateUserRoleAndCredits(subscriptionInfo.getAccountId(), subscriptionInfo.getOrderNo());
|
||||
|
||||
// 发送通知邮件
|
||||
|
||||
@@ -67,7 +67,7 @@ public class SubscriptionDeletedHandler implements StripeEventHandler {
|
||||
|
||||
// 发送取消订阅通知邮件
|
||||
if (subscriptionInfo.getCancelNotified() == 0) {
|
||||
boolean sent = stripeSubscriptionService.sendSubscriptionEmail(null, "cancel", subscriptionInfo.getOrderNo(), null);
|
||||
boolean sent = stripeSubscriptionService.sendSubscriptionEmail(null, "cancel", subscriptionInfo.getOrderNo(), subscriptionInfo);
|
||||
if (sent) {
|
||||
subscriptionInfo.setCancelNotified((byte) 1);
|
||||
|
||||
|
||||
@@ -181,4 +181,10 @@ file.upload.max.size.video=104857600
|
||||
# 上传任务过期时间(小时)
|
||||
file.upload.task.expiry.hours=24
|
||||
|
||||
global.award.link=https://aida-global-design-awards.com.hk/contestants?id=
|
||||
global.award.link=https://aida-global-design-awards.com.hk/contestants?id=
|
||||
|
||||
# merchant email receivers (comma-separated, multiple supported)
|
||||
# dev/local: developer.email 不配置,使用默认值 xupei3360@163.com
|
||||
# prod: 两个都配置
|
||||
merchant.email=
|
||||
developer.email=xupei@code-create.com.hk,yizhang@aidlab.hk
|
||||
@@ -179,4 +179,9 @@ file.upload.max.size.video=104857600
|
||||
# 上传任务过期时间(小时)
|
||||
file.upload.task.expiry.hours=24
|
||||
|
||||
global.award.link=https://aida-global-design-awards.com.hk/contestants?id=
|
||||
global.award.link=https://aida-global-design-awards.com.hk/contestants?id=
|
||||
|
||||
# merchant email receivers (comma-separated, multiple supported)
|
||||
# prod: includes merchant email
|
||||
merchant.email=kimwong@code-create.com.hk
|
||||
developer.email=xupei3360@163.com
|
||||
@@ -51,47 +51,41 @@
|
||||
a.user_email email,
|
||||
p.payment_type platform,
|
||||
p.payer_total,
|
||||
p.type,
|
||||
CASE
|
||||
WHEN o.title LIKE '%Subscription' THEN 'Subscription'
|
||||
ELSE 'Credits'
|
||||
END AS type,
|
||||
p.payment_method,
|
||||
p.last4,
|
||||
p.country,
|
||||
p.city,
|
||||
p.create_time,
|
||||
CASE
|
||||
|
||||
WHEN p.trade_state IN ( 'paid', 'COMPLETED', 'complete', 'liquidated' ) THEN
|
||||
'Success'
|
||||
WHEN p.trade_state IN ( 'failed', 'expired', 'VOIDED', 'void', 'uncollectible' ) THEN
|
||||
'Fail'
|
||||
WHEN p.trade_state IN ( 'Refunded' ) THEN
|
||||
'Refunded'
|
||||
WHEN p.trade_state IN ('paid', 'COMPLETED', 'complete', 'liquidated') THEN 'Success'
|
||||
WHEN p.trade_state IN ('failed', 'expired', 'VOIDED', 'void', 'uncollectible') THEN 'Fail'
|
||||
WHEN p.trade_state IN ('Refunded') THEN 'Refunded'
|
||||
ELSE 'Pending'
|
||||
END AS status
|
||||
FROM
|
||||
t_payment_info p
|
||||
LEFT JOIN
|
||||
t_order_info o ON p.order_no = o.order_no
|
||||
LEFT JOIN
|
||||
t_account a ON a.id = o.account_id
|
||||
WHERE
|
||||
1 = 1
|
||||
FROM t_payment_info p
|
||||
LEFT JOIN t_order_info o ON p.order_no = o.order_no
|
||||
LEFT JOIN t_account a ON a.id = o.account_id
|
||||
WHERE 1 = 1
|
||||
<if test="paymentType != null and paymentType != ''">
|
||||
AND p.payment_type = #{paymentType}
|
||||
</if>
|
||||
<if test="payerTotal != null and payerTotal != ''">
|
||||
AND p.payer_total = #{payerTotal}
|
||||
</if>
|
||||
<if test="type != null and type != ''">
|
||||
AND p.type = #{type}
|
||||
</if>
|
||||
<!-- 修复1:删除 type 过滤条件,因为 type 是计算字段 -->
|
||||
<if test="status != null and status != ''">
|
||||
AND
|
||||
CASE
|
||||
WHEN p.trade_state IN ('paid', 'COMPLETED', 'complete', 'liquidated') THEN 'Success'
|
||||
WHEN p.trade_state IN ('failed', 'expired', 'VOIDED', 'void', 'uncollectible') THEN 'Fail'
|
||||
WHEN p.trade_state IN ('Refunded') THEN 'Refunded'
|
||||
ELSE 'Pending'
|
||||
END = #{status}
|
||||
AND (
|
||||
(p.trade_state IN ('paid', 'COMPLETED', 'complete', 'liquidated') AND #{status} = 'Success')
|
||||
OR (p.trade_state IN ('failed', 'expired', 'VOIDED', 'void', 'uncollectible') AND #{status} = 'Fail')
|
||||
OR (p.trade_state IN ('Refunded') AND #{status} = 'Refunded')
|
||||
OR (p.trade_state NOT IN ('paid', 'COMPLETED', 'complete', 'liquidated',
|
||||
'failed', 'expired', 'VOIDED', 'void', 'uncollectible', 'Refunded')
|
||||
AND #{status} = 'Pending')
|
||||
)
|
||||
</if>
|
||||
<if test="country != null and country != ''">
|
||||
AND p.country = #{country}
|
||||
@@ -106,9 +100,8 @@
|
||||
AND a.user_name = #{payer}
|
||||
</if>
|
||||
AND p.transaction_id NOT LIKE 'cs_test%'
|
||||
ORDER BY
|
||||
p.id ${order}
|
||||
LIMIT ${limit} OFFSET ${offset}
|
||||
ORDER BY p.id ${order} <!-- 建议使用白名单校验 -->
|
||||
LIMIT #{limit} OFFSET #{offset} <!-- 修复:改为 #{} -->
|
||||
</select>
|
||||
|
||||
<select id="queryPaymentInfoCount" resultType="java.lang.Long">
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ai.da.mapper.primary.SubscriptionInfoMapper">
|
||||
<insert id="insertIgnore" parameterType="com.ai.da.mapper.primary.entity.SubscriptionInfo">
|
||||
<insert id="insertIgnore" parameterType="com.ai.da.mapper.primary.entity.SubscriptionInfo"
|
||||
useGeneratedKeys="true" keyProperty="id">
|
||||
INSERT IGNORE INTO
|
||||
t_subscription_info (account_id, order_no, subscription_id, type, status, cancel_notified,
|
||||
next_pay_date, current_period_start, current_period_end, create_time)
|
||||
|
||||
@@ -11,18 +11,18 @@
|
||||
#paypal.webhook_id=51V87014T6406322F
|
||||
|
||||
# aida-sandbox-kim
|
||||
#paypal.client-id=AbDDH8jnTrKqjnWLFgEu6LogYzVz2ZLuirE4W54t1M4lrofrP5OzXfhbxqktLLFB-rAO9KeYQVYFJ_tO
|
||||
#paypal.client-secret=EOOoiIAe_dyR2YhY7qCIqWipZvYXCDrmBlFYchphuvkPFms1spsBGTlStlrx580y4hN-EukWwF9m_LAs
|
||||
#paypal.receiver.email=sb-4xe8i29784722@business.example.com
|
||||
#paypal.mode=sandbox
|
||||
#paypal.webhook_id=1WH327112B602422N
|
||||
paypal.client-id=AbDDH8jnTrKqjnWLFgEu6LogYzVz2ZLuirE4W54t1M4lrofrP5OzXfhbxqktLLFB-rAO9KeYQVYFJ_tO
|
||||
paypal.client-secret=EOOoiIAe_dyR2YhY7qCIqWipZvYXCDrmBlFYchphuvkPFms1spsBGTlStlrx580y4hN-EukWwF9m_LAs
|
||||
paypal.receiver.email=sb-4xe8i29784722@business.example.com
|
||||
paypal.mode=sandbox
|
||||
paypal.webhook_id=1WH327112B602422N
|
||||
|
||||
# aida-live-kim
|
||||
paypal.client-id=ASWSIZ3MXJU5w5VOeOHeigWcSw6iinl30ZCipruziKpHclxP0ryf8-7VKG1Ba2VwZwa2DMvGEzTfCTgz
|
||||
paypal.client-secret=EHQg_K5PSqmp4FJlzEcOEH_kFkmq4aBzaI7jridw53L6cOQRULBAnfv2KakRfrsqaU1PDSkO4Co9Vyxc
|
||||
paypal.receiver.email=kimwong@code-create.com.hk
|
||||
paypal.mode=live
|
||||
paypal.webhook_id=1D107312EX592781K
|
||||
#paypal.client-id=ASWSIZ3MXJU5w5VOeOHeigWcSw6iinl30ZCipruziKpHclxP0ryf8-7VKG1Ba2VwZwa2DMvGEzTfCTgz
|
||||
#paypal.client-secret=EHQg_K5PSqmp4FJlzEcOEH_kFkmq4aBzaI7jridw53L6cOQRULBAnfv2KakRfrsqaU1PDSkO4Co9Vyxc
|
||||
#paypal.receiver.email=kimwong@code-create.com.hk
|
||||
#paypal.mode=live
|
||||
#paypal.webhook_id=1D107312EX592781K
|
||||
|
||||
##### Stripe
|
||||
|
||||
|
||||
Reference in New Issue
Block a user