Compare commits
39 Commits
dev-ltx
...
release/3.
| Author | SHA1 | Date | |
|---|---|---|---|
| 3273a61066 | |||
| d055331690 | |||
| 0073f910a7 | |||
| 6dcbfa025a | |||
| 65cde0b8f5 | |||
| b66877425e | |||
|
|
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 | |||
| f2a074b2f6 | |||
| 6a7a37dcec | |||
|
|
c4d2780f0e | ||
|
|
1da6b7728c | ||
|
|
0faf77899b | ||
|
|
5dd862ff79 | ||
|
|
edaec9884d |
@@ -202,7 +202,7 @@ public class MyTaskScheduler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Scheduled(cron = "0 0 9 * * ?")
|
@Scheduled(cron = "0 0 9 * * ?")
|
||||||
public void sendTrialOrderExcelToManagements() {
|
public void sendTrialOrderExcelToManagements() {
|
||||||
// 获取前一天日期
|
// 获取前一天日期
|
||||||
LocalDate yesterday = LocalDate.now().minusDays(1);
|
LocalDate yesterday = LocalDate.now().minusDays(1);
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ public class ModelConstants {
|
|||||||
|
|
||||||
// 模型名称常量
|
// 模型名称常量
|
||||||
public static final String PRINTBOARD_ADVANCED_T2I = "qwen-image";
|
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 MOODBOARD_ADVANCED = "doubao-seedream-4-5-251128";
|
||||||
public static final String PRINTBOARD_HIGH_T2I = "doubao-seedream-3-0-t2i-250415";
|
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";
|
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 PRINTBOARD_ADVANCED_I2I = "doubao-seedream-4-0-250828";
|
||||||
public static final String IMAGEN_MODEL = "imagen-4.0-generate-001";
|
public static final String IMAGEN_MODEL = "imagen-4.0-generate-001";
|
||||||
public static final String NANO_BANANA = "gemini-2.5-flash-image";
|
public static final String NANO_BANANA = "gemini-2.5-flash-image";
|
||||||
|
|||||||
@@ -61,10 +61,7 @@ public class AuthenticationFilter extends OncePerRequestFilter {
|
|||||||
, "/api/account/schoolLogin", "/api/account/enterpriseLogin", "/api/account/organizationNameSearch",
|
, "/api/account/schoolLogin", "/api/account/enterpriseLogin", "/api/account/organizationNameSearch",
|
||||||
"/api/llm/stream",
|
"/api/llm/stream",
|
||||||
//GlobalAwardController
|
//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"
|
||||||
"/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"
|
|
||||||
);
|
);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ public class AccountTask {
|
|||||||
accountService.refreshCreditsMonthly();
|
accountService.refreshCreditsMonthly();
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
|
@Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
|
||||||
public void getPaidUser() {
|
public void getPaidUser() {
|
||||||
// 获取code-create 表中 指定日期之后 订单状态为wc-processing的订单
|
// 获取code-create 表中 指定日期之后 订单状态为wc-processing的订单
|
||||||
accountService.extendValidityForCC();
|
accountService.extendValidityForCC();
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ public class PaymentTask {
|
|||||||
@Resource
|
@Resource
|
||||||
private PayPalCheckoutService payPalCheckoutService;
|
private PayPalCheckoutService payPalCheckoutService;
|
||||||
|
|
||||||
// @Scheduled(cron = "0/30 * * * * ?")
|
@Scheduled(cron = "0/30 * * * * ?")
|
||||||
public void orderConfirmForPaypal() throws SerializeException {
|
public void orderConfirmForPaypal() throws SerializeException {
|
||||||
|
|
||||||
// log.info("PayPal orderConfirm 被执行......");
|
// 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(){
|
public void updateAffiliateInfoWithPayment(){
|
||||||
// log.info("佣金计算定时器");
|
// log.info("佣金计算定时器");
|
||||||
affiliateService.updateAffiliateInfoWithPayment();
|
affiliateService.updateAffiliateInfoWithPayment();
|
||||||
@@ -109,7 +109,7 @@ public class PaymentTask {
|
|||||||
affiliateService.syncLinkViewCountToDB();
|
affiliateService.syncLinkViewCountToDB();
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Scheduled(cron = "0 0 8 28-31 * ?")
|
@Scheduled(cron = "0 0 8 28-31 * ?")
|
||||||
public void commissionSummaryReminder(){
|
public void commissionSummaryReminder(){
|
||||||
// 每个月末的最后一天的早上八点执行
|
// 每个月末的最后一天的早上八点执行
|
||||||
LocalDate today = LocalDate.now();
|
LocalDate today = LocalDate.now();
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ public class SubscriptionReminderTask {
|
|||||||
REMINDER_DAYS_CONFIG.put("year", 14);
|
REMINDER_DAYS_CONFIG.put("year", 14);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Scheduled(cron = "0 0 9 * * ?")
|
@Scheduled(cron = "0 0 9 * * ?")
|
||||||
public void subscriptionReminder() {
|
public void subscriptionReminder() {
|
||||||
// 获取所有需要通知的订阅
|
// 获取所有需要通知的订阅
|
||||||
List<SubscriptionInfo> subscriptionInfos = getDueSubscriptions();
|
List<SubscriptionInfo> subscriptionInfos = getDueSubscriptions();
|
||||||
@@ -97,7 +97,7 @@ public class SubscriptionReminderTask {
|
|||||||
return subscriptionInfoMapper.selectList(qw);
|
return subscriptionInfoMapper.selectList(qw);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Scheduled(cron = "0 0 9 * * ?")
|
@Scheduled(cron = "0 0 9 * * ?")
|
||||||
public void trialReminder() {
|
public void trialReminder() {
|
||||||
// 今天的 00:00:00 和 23:59:59
|
// 今天的 00:00:00 和 23:59:59
|
||||||
LocalDateTime startOfDay = LocalDateTime.now().toLocalDate().atStartOfDay();
|
LocalDateTime startOfDay = LocalDateTime.now().toLocalDate().atStartOfDay();
|
||||||
|
|||||||
@@ -767,7 +767,7 @@ public class SendEmailUtil {
|
|||||||
try {
|
try {
|
||||||
String merchantEmail = "kimwong@code-create.com.hk";
|
String merchantEmail = "kimwong@code-create.com.hk";
|
||||||
String developer = "xupei3360@163.com";
|
String developer = "xupei3360@163.com";
|
||||||
String[] receiverEmail = {/*merchantEmail,*/ developer};
|
String[] receiverEmail = {merchantEmail, developer};
|
||||||
Credential cred = new Credential(SECRET_ID, SECRET_KEy);
|
Credential cred = new Credential(SECRET_ID, SECRET_KEy);
|
||||||
// 实例化一个http选项,可选的,没有特殊需求可以跳过
|
// 实例化一个http选项,可选的,没有特殊需求可以跳过
|
||||||
HttpProfile httpProfile = new HttpProfile();
|
HttpProfile httpProfile = new HttpProfile();
|
||||||
@@ -968,7 +968,7 @@ public class SendEmailUtil {
|
|||||||
req.setFromEmailAddress(SEND_ADDRESS);
|
req.setFromEmailAddress(SEND_ADDRESS);
|
||||||
String merchantEmail = "kimwong@code-create.com.hk";
|
String merchantEmail = "kimwong@code-create.com.hk";
|
||||||
String developerEmail = "xupei@code-create.com.hk";
|
String developerEmail = "xupei@code-create.com.hk";
|
||||||
req.setDestination(new String[]{/*merchantEmail,*/ developerEmail});
|
req.setDestination(new String[]{merchantEmail, developerEmail});
|
||||||
Template template = new Template();
|
Template template = new Template();
|
||||||
req.setSubject("New Credit Purchase Order");
|
req.setSubject("New Credit Purchase Order");
|
||||||
template.setTemplateID(CREDITS_PURCHASE_MERCHANT);
|
template.setTemplateID(CREDITS_PURCHASE_MERCHANT);
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import com.ai.da.common.response.Response;
|
|||||||
import com.ai.da.model.dto.*;
|
import com.ai.da.model.dto.*;
|
||||||
import com.ai.da.model.dto.ContestantDTO;
|
import com.ai.da.model.dto.ContestantDTO;
|
||||||
import com.ai.da.model.vo.CheckOTPVO;
|
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.GlobalAwardService;
|
||||||
import com.ai.da.service.upload.UploadService;
|
import com.ai.da.service.upload.UploadService;
|
||||||
import com.ai.da.service.upload.UploadTask;
|
import com.ai.da.service.upload.UploadTask;
|
||||||
@@ -176,10 +178,38 @@ public class GlobalAwardController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/contestants/export/files")
|
@PostMapping("/contestants/export/files")
|
||||||
@ApiOperation(value = "导出参赛者文件到本地", notes = "根据参赛者编号范围导出PDF和视频文件到本地temp/uploads/contestants目录")
|
@ApiOperation(value = "导出参赛者文件为ZIP", notes = "根据参赛者编号范围导出PDF、视频和信息文件为ZIP,直接响应给浏览器")
|
||||||
public Response<Integer> exportContestantFiles(@ApiParam(value = "参赛者文件导出请求", required = true) @RequestBody ContestantExportRequest request) throws Exception {
|
public void exportContestantFiles(@ApiParam(value = "参赛者文件导出请求", required = true) @RequestBody ContestantExportRequest request, HttpServletResponse response) throws Exception {
|
||||||
int exportedCount = globalAwardService.exportContestantFiles(request.getMinContestantNumber(), request.getMaxContestantNumber());
|
byte[] zipData = globalAwardService.exportContestantFilesAsZip(request.getMinContestantNumber(), request.getMaxContestantNumber());
|
||||||
return Response.success(exportedCount);
|
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")
|
@TableField("pdf_size")
|
||||||
private Long pdfSize;
|
private Long pdfSize;
|
||||||
|
|
||||||
|
@TableField("portfolio_url")
|
||||||
|
private String portfolioUrl;
|
||||||
|
|
||||||
@TableField("created_at")
|
@TableField("created_at")
|
||||||
private LocalDateTime createdAt;
|
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 Integer systemUser;
|
||||||
|
|
||||||
|
private Long subscriptionPlanId;
|
||||||
|
|
||||||
|
private Long organizationId;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2912,72 +2912,71 @@ public class PythonService {
|
|||||||
|
|
||||||
private PrintToPython resolveDesignSinglePrint(List<DesignSinglePrint> printObject, String partialDesign) {
|
private PrintToPython resolveDesignSinglePrint(List<DesignSinglePrint> printObject, String partialDesign) {
|
||||||
PrintToPython printToPython = new PrintToPython();
|
PrintToPython printToPython = new PrintToPython();
|
||||||
// DesignPythonItemPrint printSingle = new DesignPythonItemPrint();
|
|
||||||
DesignPythonItemPrint printOverall = new DesignPythonItemPrint();
|
DesignPythonItemPrint printOverall = new DesignPythonItemPrint();
|
||||||
// printToPython.setSingle(printSingle);
|
|
||||||
printToPython.setOverall(printOverall);
|
printToPython.setOverall(printOverall);
|
||||||
printToPython.setPartial(StringUtil.isNullOrEmpty(partialDesign) ? null : partialDesign);
|
printToPython.setPartial(StringUtil.isNullOrEmpty(partialDesign) ? null : partialDesign);
|
||||||
if (Objects.isNull(printObject) || printObject.isEmpty()) {
|
if (Objects.isNull(printObject) || printObject.isEmpty()) {
|
||||||
return printToPython;
|
return printToPython;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 没有印花时的参数设置
|
// 1. 先对 printObject 按 priority 排序(升序)
|
||||||
// if (printObject.getIfSingle().equals(Boolean.FALSE) && CollectionUtil.isEmpty(printObject.getPrints())) {
|
List<DesignSinglePrint> sortedPrints = printObject.stream()
|
||||||
// return new DesignPythonItemPrint(new ArrayList<>(), false);
|
.sorted(Comparator.comparingInt(DesignSinglePrint::getPriority))
|
||||||
// }
|
.toList();
|
||||||
// DesignPythonItemPrint print = CopyUtil.copyObject(printObject, DesignPythonItemPrint.class);
|
|
||||||
|
|
||||||
int size = printObject.size();
|
// 2. 分别收集单印和非单印的数据
|
||||||
// 占位符填充数组
|
List<DesignSinglePrint> singlePrints = sortedPrints.stream()
|
||||||
List<List<Float>> locationS = new ArrayList<>(Collections.nCopies(size, null));
|
.filter(DesignSinglePrint::getIfSingle)
|
||||||
List<List<Float>> scaleS = new ArrayList<>(Collections.nCopies(size, null));
|
.toList();
|
||||||
List<Double> angleS = new ArrayList<>(Collections.nCopies(size, null));
|
|
||||||
ArrayList<String> pathsS = new ArrayList<>(Collections.nCopies(size, null));
|
|
||||||
|
|
||||||
List<List<Float>> locationO = new ArrayList<>(Collections.nCopies(size, null));
|
List<DesignSinglePrint> overallPrints = sortedPrints.stream()
|
||||||
List<List<Float>> scaleO = new ArrayList<>(Collections.nCopies(size, null));
|
.filter(p -> !p.getIfSingle())
|
||||||
List<Double> angleO = new ArrayList<>(Collections.nCopies(size, null));
|
.toList();
|
||||||
ArrayList<String> pathsO = new ArrayList<>(Collections.nCopies(size, null));
|
|
||||||
|
|
||||||
// 设置印花的位置、大小、旋转角度
|
// 3. 处理单印数据
|
||||||
// 优先级越大,越靠近顶层,在传输给python的数组中,越靠前
|
if (!singlePrints.isEmpty()) {
|
||||||
// List<DesignSinglePrint> prints = printObject.getPrints();
|
List<List<Float>> locationS = new ArrayList<>();
|
||||||
printObject.forEach(p -> {
|
List<List<Float>> scaleS = new ArrayList<>();
|
||||||
p.getLocation().set(0, p.getLocation().get(0));
|
List<Double> angleS = new ArrayList<>();
|
||||||
p.getLocation().set(1, p.getLocation().get(1));
|
List<String> pathsS = new ArrayList<>();
|
||||||
Integer priority = p.getPriority();
|
|
||||||
setUriToMinioPath(p);
|
for (DesignSinglePrint p : singlePrints) {
|
||||||
// todo 下标越界问题
|
setUriToMinioPath(p);
|
||||||
if (p.getIfSingle()) {
|
locationS.add(p.getLocation());
|
||||||
locationS.set(priority - 1, p.getLocation());
|
scaleS.add(p.getScale());
|
||||||
scaleS.set(priority - 1, p.getScale());
|
angleS.add(p.getAngle());
|
||||||
angleS.set(priority - 1, p.getAngle());
|
pathsS.add(p.getMinIOPath());
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
// 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));
|
// 注意:如果 printOverall 中需要设置单印数据,请在这里添加相应的 setter
|
||||||
scaleO.removeAll(Collections.singleton(null));
|
// 根据您的原始代码,似乎只设置了 overall(非单印)的数据
|
||||||
angleO.removeAll(Collections.singleton(null));
|
// 如果需要设置单印,请取消下面的注释并添加对应的字段
|
||||||
pathsO.removeAll(Collections.singleton(null));
|
// printOverall.setSingleLocation(locationS);
|
||||||
printOverall.setLocation(locationO);
|
// printOverall.setSingleScale(scaleS);
|
||||||
printOverall.setPrint_scale_list(scaleO);
|
// printOverall.setSingleAngle(angleS);
|
||||||
printOverall.setPrint_angle_list(angleO);
|
// printOverall.setSinglePath(pathsS);
|
||||||
printOverall.setPrint_path_list(pathsO);
|
}
|
||||||
|
|
||||||
|
// 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;
|
return printToPython;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package com.ai.da.service;
|
|||||||
|
|
||||||
import com.ai.da.model.dto.ContestantDTO;
|
import com.ai.da.model.dto.ContestantDTO;
|
||||||
import com.ai.da.model.vo.CheckOTPVO;
|
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 org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -33,12 +35,34 @@ public interface GlobalAwardService {
|
|||||||
void saveContestantsToLocal() throws Exception;
|
void saveContestantsToLocal() throws Exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据参赛者编号范围导出参赛者文件到本地目录
|
* 将参赛者文件打包为 ZIP 并返回字节数组(不落盘,直接响应给浏览器)
|
||||||
* @param minContestantNumber 最小参赛者编号
|
* @param minContestantNumber 最小参赛者编号
|
||||||
* @param maxContestantNumber 最大参赛者编号
|
* @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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate
|
|||||||
// 邮件通知审批者
|
// 邮件通知审批者
|
||||||
String merchantEmail = "kimwong@code-create.com.hk";
|
String merchantEmail = "kimwong@code-create.com.hk";
|
||||||
String developer = "xupei3360@163.com";
|
String developer = "xupei3360@163.com";
|
||||||
String[] receiverEmail = {/*merchantEmail,*/ developer};
|
String[] receiverEmail = {merchantEmail, developer};
|
||||||
SendEmailUtil.affiliateEmailReminder(receiverEmail, new AffiliateEmailParamsDTO(userHolder.getUsername(), promotionMethod), "new");
|
SendEmailUtil.affiliateEmailReminder(receiverEmail, new AffiliateEmailParamsDTO(userHolder.getUsername(), promotionMethod), "new");
|
||||||
// emailService.affiliateEmailReminder(Arrays.asList(/*merchantEmail,*/ developer), new AffiliateEmailParamsDTO(userHolder.getUsername(), promotionMethod), "new");
|
// emailService.affiliateEmailReminder(Arrays.asList(/*merchantEmail,*/ developer), new AffiliateEmailParamsDTO(userHolder.getUsername(), promotionMethod), "new");
|
||||||
}else {
|
}else {
|
||||||
@@ -442,7 +442,7 @@ public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate
|
|||||||
|
|
||||||
String merchantEmail = "kimwong@code-create.com.hk";
|
String merchantEmail = "kimwong@code-create.com.hk";
|
||||||
String developer = "xupei3360@163.com";
|
String developer = "xupei3360@163.com";
|
||||||
String[] receiverEmail = {/*merchantEmail,*/ developer};
|
String[] receiverEmail = {merchantEmail, developer};
|
||||||
// 邮件通知
|
// 邮件通知
|
||||||
SendEmailUtil.affiliateEmailReminder(receiverEmail, affiliateEmailParamsDTO, "summary");
|
SendEmailUtil.affiliateEmailReminder(receiverEmail, affiliateEmailParamsDTO, "summary");
|
||||||
// emailService.affiliateEmailReminder(Arrays.asList(/*merchantEmail,*/ developer), affiliateEmailParamsDTO, "summary");
|
// emailService.affiliateEmailReminder(Arrays.asList(/*merchantEmail,*/ developer), affiliateEmailParamsDTO, "summary");
|
||||||
|
|||||||
@@ -521,14 +521,15 @@ public class CollectionElementServiceImpl extends ServiceImpl<CollectionElementM
|
|||||||
.map(DesignCollectionPrintElementDTO::getId)
|
.map(DesignCollectionPrintElementDTO::getId)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
List<CollectionElement> printBoardElements = new ArrayList<>();
|
List<CollectionElement> printBoardElements = new ArrayList<>();
|
||||||
|
elementVO.setPrintBoardElements(printBoardElements);
|
||||||
if (!CollectionUtils.isEmpty(printBoardIds)) {
|
if (!CollectionUtils.isEmpty(printBoardIds)) {
|
||||||
// 从数据库批量查询printBoard元素
|
// 从数据库批量查询printBoard元素
|
||||||
printBoardElements = collectionElementMapper.selectBatchIds(printBoardIds);
|
printBoardElements.addAll(collectionElementMapper.selectBatchIds(printBoardIds));
|
||||||
// 验证查询结果的完整性
|
// 验证查询结果的完整性
|
||||||
if (CollectionUtil.isEmpty(printBoardElements) || printBoardElements.size() != printBoardIds.size()) {
|
if (CollectionUtil.isEmpty(printBoardElements) || printBoardElements.size() != printBoardIds.size()) {
|
||||||
throw new BusinessException("get.printBoards.data.is.mismatch");
|
throw new BusinessException("get.printBoards.data.is.mismatch");
|
||||||
}
|
}
|
||||||
elementVO.setPrintBoardElements(printBoardElements);
|
// elementVO.setPrintBoardElements(printBoardElements);
|
||||||
usedElementIds.addAll(printBoardIds); // 记录已使用的元素ID
|
usedElementIds.addAll(printBoardIds); // 记录已使用的元素ID
|
||||||
}
|
}
|
||||||
// 处理类型为LIBRARY的printBoard元素
|
// 处理类型为LIBRARY的printBoard元素
|
||||||
|
|||||||
@@ -787,6 +787,14 @@ public class ConvenientInquiryServiceImpl extends ServiceImpl<QuestionnaireMappe
|
|||||||
queryWrapper.lt("create_date", queryUserConditionsVO.getEndTime());
|
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())) {
|
if (!StringUtils.isNullOrEmpty(queryUserConditionsVO.getOrder()) && !StringUtils.isNullOrEmpty(queryUserConditionsVO.getOrderBy())) {
|
||||||
String orderBy = "id";
|
String orderBy = "id";
|
||||||
|
|||||||
@@ -756,7 +756,7 @@ public class DesignServiceImpl extends ServiceImpl<DesignMapper, Design> impleme
|
|||||||
print.setPosition("[0.0,0.0]");
|
print.setPosition("[0.0,0.0]");
|
||||||
// print.setScale(1d);
|
// print.setScale(1d);
|
||||||
// todo mark 将print默认scale置为0.3
|
// 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.setAngle(0.0);
|
||||||
print.setPriority(1);
|
print.setPriority(1);
|
||||||
QueryWrapper<CollectionElement> getPrintboardLevel2TypeQw = new QueryWrapper<>();
|
QueryWrapper<CollectionElement> getPrintboardLevel2TypeQw = new QueryWrapper<>();
|
||||||
@@ -764,7 +764,20 @@ public class DesignServiceImpl extends ServiceImpl<DesignMapper, Design> impleme
|
|||||||
getPrintboardLevel2TypeQw.lambda().orderByDesc(CollectionElement::getCreateDate);
|
getPrintboardLevel2TypeQw.lambda().orderByDesc(CollectionElement::getCreateDate);
|
||||||
getPrintboardLevel2TypeQw.last("limit 1");
|
getPrintboardLevel2TypeQw.last("limit 1");
|
||||||
CollectionElement one = collectionElementService.getOne(getPrintboardLevel2TypeQw);
|
CollectionElement one = collectionElementService.getOne(getPrintboardLevel2TypeQw);
|
||||||
print.setLevel2Type(one.getLevel2Type());
|
if (Objects.isNull(one)) {
|
||||||
|
QueryWrapper<Library> libraryQueryWrapper = new QueryWrapper<>();
|
||||||
|
libraryQueryWrapper.lambda().eq(Library::getUrl, print.getPath());
|
||||||
|
libraryQueryWrapper.lambda().orderByDesc(Library::getCreateDate);
|
||||||
|
getPrintboardLevel2TypeQw.last("limit 1");
|
||||||
|
Library library = libraryService.getOne(libraryQueryWrapper);
|
||||||
|
if (Objects.isNull(library)) {
|
||||||
|
print.setLevel2Type("Pattern");
|
||||||
|
} else {
|
||||||
|
print.setLevel2Type(library.getLevel2Type());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print.setLevel2Type(one.getLevel2Type());
|
||||||
|
}
|
||||||
print.setCreateDate(LocalDateTime.now());
|
print.setCreateDate(LocalDateTime.now());
|
||||||
designItemDetailPrintService.save(print);
|
designItemDetailPrintService.save(print);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -587,7 +587,7 @@ public class EmailServiceImpl implements EmailService {
|
|||||||
try {
|
try {
|
||||||
String merchantEmail = "kimwong@code-create.com.hk";
|
String merchantEmail = "kimwong@code-create.com.hk";
|
||||||
String developer = "xupei3360@163.com";
|
String developer = "xupei3360@163.com";
|
||||||
List<String> merchantReceiver = Arrays.asList(/*merchantEmail,*/ developer);
|
List<String> merchantReceiver = Arrays.asList(merchantEmail, developer);
|
||||||
|
|
||||||
String merchantSubject = null;
|
String merchantSubject = null;
|
||||||
String merchantTemplate = null;
|
String merchantTemplate = null;
|
||||||
@@ -731,7 +731,7 @@ public class EmailServiceImpl implements EmailService {
|
|||||||
jsonObject.put("quantity", quantity);
|
jsonObject.put("quantity", quantity);
|
||||||
jsonObject.put("totalFee", amount);
|
jsonObject.put("totalFee", amount);
|
||||||
|
|
||||||
sendEmail(Arrays.asList(/*merchantEmail,*/ developerEmail), jsonObject, CREDITS_PURCHASE_MERCHANT, "New Credit Purchase Order", null, null);
|
sendEmail(Arrays.asList(merchantEmail, developerEmail), jsonObject, CREDITS_PURCHASE_MERCHANT, "New Credit Purchase Order", null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final static String COMMON_EXCEPTION_REMINDER = "135279_common-exception-reminder.html";
|
private final static String COMMON_EXCEPTION_REMINDER = "135279_common-exception-reminder.html";
|
||||||
|
|||||||
@@ -198,10 +198,13 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
|
|||||||
generate.setText(text);
|
generate.setText(text);
|
||||||
Long elementId = generateThroughImageTextDTO.getCollectionElementId();
|
Long elementId = generateThroughImageTextDTO.getCollectionElementId();
|
||||||
// validateGeneraType(generate, text, elementId);
|
// validateGeneraType(generate, text, elementId);
|
||||||
if (!StringUtil.isNullOrEmpty(text)) {
|
if (!(generateThroughImageTextDTO.getLevel1Type().equals(MOOD_BOARD.getRealName())&&generateThroughImageTextDTO.getModelName().equals("high"))){
|
||||||
text = modifyPrompt(text, generate, generateThroughImageTextDTO.getLevel1Type(), generateThroughImageTextDTO.getAgeGroup());
|
if (!StringUtil.isNullOrEmpty(text)) {
|
||||||
|
text = modifyPrompt(text, generate, generateThroughImageTextDTO.getLevel1Type(), generateThroughImageTextDTO.getAgeGroup());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// todo 这一步现在还是有必要的吗?
|
// todo 这一步现在还是有必要的吗?
|
||||||
// 2.1 sketch或print在t_collection_element表/t_library表中的信息是否需要更新 如 level2Type
|
// 2.1 sketch或print在t_collection_element表/t_library表中的信息是否需要更新 如 level2Type
|
||||||
CollectionElement collectionElement = collectionElementService.editLevel2Type(elementId, generateThroughImageTextDTO.getLevel2Type(), generateThroughImageTextDTO.getDesignType());
|
CollectionElement collectionElement = collectionElementService.editLevel2Type(elementId, generateThroughImageTextDTO.getLevel2Type(), generateThroughImageTextDTO.getDesignType());
|
||||||
@@ -1550,10 +1553,12 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
|
|||||||
if (imagePath != null) {
|
if (imagePath != null) {
|
||||||
requestBuilder.image(finalImagePath1);
|
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();
|
GenerateImagesRequest.OptimizePromptOptions optimizePromptOptions = new GenerateImagesRequest.OptimizePromptOptions();
|
||||||
optimizePromptOptions.setMode("fast");
|
optimizePromptOptions.setMode("fast");
|
||||||
requestBuilder.optimizePromptOptions(optimizePromptOptions);
|
requestBuilder.optimizePromptOptions(optimizePromptOptions);
|
||||||
|
//由于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);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存生成记录到数据库
|
// 保存生成记录到数据库
|
||||||
@@ -3929,11 +3934,48 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
|
|||||||
}
|
}
|
||||||
|
|
||||||
public byte[] downloadVideoOrImage(String url) {
|
public byte[] downloadVideoOrImage(String url) {
|
||||||
try (CloseableHttpClient client = HttpClients.createDefault();
|
int maxRetries = 3;
|
||||||
InputStream in = client.execute(new HttpGet(url)).getEntity().getContent()) {
|
int retryDelayMs = 1000;
|
||||||
return IOUtils.toByteArray(in);
|
IOException lastException = null;
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
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.ContestantDTO;
|
||||||
import com.ai.da.model.dto.PublishSysNotificationDTO;
|
import com.ai.da.model.dto.PublishSysNotificationDTO;
|
||||||
import com.ai.da.model.vo.CheckOTPVO;
|
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.GlobalAwardService;
|
||||||
import com.ai.da.service.MessageCenterService;
|
import com.ai.da.service.MessageCenterService;
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
@@ -26,24 +28,22 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
|
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
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.LocalDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.util.zip.ZipEntry;
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
import org.apache.poi.ss.usermodel.Cell;
|
import org.apache.poi.ss.usermodel.Cell;
|
||||||
import org.apache.poi.ss.usermodel.Row;
|
import org.apache.poi.ss.usermodel.Row;
|
||||||
import org.apache.poi.ss.usermodel.Sheet;
|
import org.apache.poi.ss.usermodel.Sheet;
|
||||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
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
|
@Service
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@@ -187,6 +187,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
|||||||
.videoSize(request.getVideoSize())
|
.videoSize(request.getVideoSize())
|
||||||
.pdfSize(request.getPdfSize())
|
.pdfSize(request.getPdfSize())
|
||||||
.contestantNumber(nextNumber)
|
.contestantNumber(nextNumber)
|
||||||
|
.portfolioUrl(request.getPortfolioUrl())
|
||||||
.createdAt(now)
|
.createdAt(now)
|
||||||
.updatedAt(now)
|
.updatedAt(now)
|
||||||
.build();
|
.build();
|
||||||
@@ -227,6 +228,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
|||||||
existing.setVideoDuration(request.getVideoDuration());
|
existing.setVideoDuration(request.getVideoDuration());
|
||||||
existing.setVideoSize(request.getVideoSize());
|
existing.setVideoSize(request.getVideoSize());
|
||||||
existing.setPdfSize(request.getPdfSize());
|
existing.setPdfSize(request.getPdfSize());
|
||||||
|
existing.setPortfolioUrl(request.getPortfolioUrl());
|
||||||
existing.setUpdatedAt(now);
|
existing.setUpdatedAt(now);
|
||||||
contestantMapper.updateById(existing);
|
contestantMapper.updateById(existing);
|
||||||
resp.put("success", true);
|
resp.put("success", true);
|
||||||
@@ -244,7 +246,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
|||||||
String[] headers = new String[] {
|
String[] headers = new String[] {
|
||||||
"contestantNumber", "email", "firstName", "lastName", "gender", "occupation",
|
"contestantNumber", "email", "firstName", "lastName", "gender", "occupation",
|
||||||
"age", "countryRegionCity", "phoneNumber", "designTitle", "designDescription",
|
"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++) {
|
for (int i = 0; i < headers.length; i++) {
|
||||||
Cell c = header.createCell(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.getPhoneNumber() == null ? "" : cst.getPhoneNumber());
|
||||||
r.createCell(ci++).setCellValue(cst.getDesignTitle() == null ? "" : cst.getDesignTitle());
|
r.createCell(ci++).setCellValue(cst.getDesignTitle() == null ? "" : cst.getDesignTitle());
|
||||||
r.createCell(ci++).setCellValue(cst.getDesignDescription() == null ? "" : cst.getDesignDescription());
|
r.createCell(ci++).setCellValue(cst.getDesignDescription() == null ? "" : cst.getDesignDescription());
|
||||||
// r.createCell(ci++).setCellValue(cst.getPdfPath() == null ? "" : cst.getPdfPath());
|
r.createCell(ci++).setCellValue(cst.getPdfPath() == null ? "" : cst.getPdfPath());
|
||||||
// r.createCell(ci++).setCellValue(cst.getVideoPath() == null ? "" : cst.getVideoPath());
|
r.createCell(ci++).setCellValue(cst.getVideoPath() == null ? "" : cst.getVideoPath());
|
||||||
// 视频时长(秒)
|
|
||||||
r.createCell(ci++).setCellValue(cst.getVideoDuration() == null ? "" : cst.getVideoDuration().toString());
|
r.createCell(ci++).setCellValue(cst.getVideoDuration() == null ? "" : cst.getVideoDuration().toString());
|
||||||
// 视频大小、PDF 大小:以 MB 导出,保留两位小数
|
|
||||||
if (cst.getVideoSize() == null) {
|
if (cst.getVideoSize() == null) {
|
||||||
r.createCell(ci++).setCellValue("");
|
r.createCell(ci++).setCellValue("");
|
||||||
} else {
|
} else {
|
||||||
@@ -282,6 +282,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
|||||||
double pMb = cst.getPdfSize() / 1024.0 / 1024.0;
|
double pMb = cst.getPdfSize() / 1024.0 / 1024.0;
|
||||||
r.createCell(ci++).setCellValue(String.format("%.2f", pMb));
|
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.getCreatedAt() == null ? "" : cst.getCreatedAt().toString());
|
||||||
r.createCell(ci++).setCellValue(cst.getUpdatedAt() == null ? "" : cst.getUpdatedAt().toString());
|
r.createCell(ci++).setCellValue(cst.getUpdatedAt() == null ? "" : cst.getUpdatedAt().toString());
|
||||||
}
|
}
|
||||||
@@ -311,7 +312,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
|||||||
String[] headers = new String[] {
|
String[] headers = new String[] {
|
||||||
"contestantNumber", "email", "firstName", "lastName", "gender", "occupation",
|
"contestantNumber", "email", "firstName", "lastName", "gender", "occupation",
|
||||||
"age", "countryRegionCity", "phoneNumber", "designTitle", "designDescription",
|
"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++) {
|
for (int i = 0; i < headers.length; i++) {
|
||||||
Cell c = header.createCell(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.getPhoneNumber() == null ? "" : cst.getPhoneNumber());
|
||||||
r.createCell(ci++).setCellValue(cst.getDesignTitle() == null ? "" : cst.getDesignTitle());
|
r.createCell(ci++).setCellValue(cst.getDesignTitle() == null ? "" : cst.getDesignTitle());
|
||||||
r.createCell(ci++).setCellValue(cst.getDesignDescription() == null ? "" : cst.getDesignDescription());
|
r.createCell(ci++).setCellValue(cst.getDesignDescription() == null ? "" : cst.getDesignDescription());
|
||||||
// r.createCell(ci++).setCellValue(cst.getPdfPath() == null ? "" : cst.getPdfPath());
|
r.createCell(ci++).setCellValue(cst.getPdfPath() == null ? "" : cst.getPdfPath());
|
||||||
// r.createCell(ci++).setCellValue(cst.getVideoPath() == null ? "" : cst.getVideoPath());
|
r.createCell(ci++).setCellValue(cst.getVideoPath() == null ? "" : cst.getVideoPath());
|
||||||
// 视频时长(秒)
|
|
||||||
r.createCell(ci++).setCellValue(cst.getVideoDuration() == null ? "" : cst.getVideoDuration().toString());
|
r.createCell(ci++).setCellValue(cst.getVideoDuration() == null ? "" : cst.getVideoDuration().toString());
|
||||||
// 视频大小、PDF 大小:以 MB 导出,保留两位小数
|
|
||||||
if (cst.getVideoSize() == null) {
|
if (cst.getVideoSize() == null) {
|
||||||
r.createCell(ci++).setCellValue("");
|
r.createCell(ci++).setCellValue("");
|
||||||
} else {
|
} else {
|
||||||
@@ -349,6 +348,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
|||||||
double pMb = cst.getPdfSize() / 1024.0 / 1024.0;
|
double pMb = cst.getPdfSize() / 1024.0 / 1024.0;
|
||||||
r.createCell(ci++).setCellValue(String.format("%.2f", pMb));
|
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.getCreatedAt() == null ? "" : cst.getCreatedAt().toString());
|
||||||
r.createCell(ci++).setCellValue(cst.getUpdatedAt() == null ? "" : cst.getUpdatedAt().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.setVideoDuration(existing.getVideoDuration());
|
||||||
dto.setPdfSize(existing.getPdfSize());
|
dto.setPdfSize(existing.getPdfSize());
|
||||||
dto.setVideoSize(existing.getVideoSize());
|
dto.setVideoSize(existing.getVideoSize());
|
||||||
|
dto.setPortfolioUrl(existing.getPortfolioUrl());
|
||||||
return dto;
|
return dto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,7 +481,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int exportContestantFiles(Integer minContestantNumber, Integer maxContestantNumber) throws Exception {
|
public byte[] exportContestantFilesAsZip(Integer minContestantNumber, Integer maxContestantNumber) throws Exception {
|
||||||
if (minContestantNumber == null || maxContestantNumber == null) {
|
if (minContestantNumber == null || maxContestantNumber == null) {
|
||||||
throw new BusinessException("minContestantNumber and maxContestantNumber are required.");
|
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.");
|
throw new BusinessException("minContestantNumber cannot be greater than maxContestantNumber.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. 根据contestantNumber范围查询参赛者
|
// 1. 根据 contestantNumber 范围查询参赛者
|
||||||
QueryWrapper<Contestant> queryWrapper = new QueryWrapper<>();
|
QueryWrapper<Contestant> queryWrapper = new QueryWrapper<>();
|
||||||
queryWrapper.lambda()
|
queryWrapper.lambda()
|
||||||
.ge(Contestant::getContestantNumber, minContestantNumber)
|
.ge(Contestant::getContestantNumber, minContestantNumber)
|
||||||
@@ -498,91 +499,158 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
|||||||
|
|
||||||
if (contestants.isEmpty()) {
|
if (contestants.isEmpty()) {
|
||||||
log.info("No contestants found in range [{}, {}]", minContestantNumber, maxContestantNumber);
|
log.info("No contestants found in range [{}, {}]", minContestantNumber, maxContestantNumber);
|
||||||
return 0;
|
return new byte[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 创建基础目录
|
// 2. 在内存中构建 ZIP
|
||||||
String baseDir = uploadDir + "/contestants";
|
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
Path basePath = Paths.get(baseDir).toAbsolutePath();
|
java.util.zip.ZipOutputStream zos = new java.util.zip.ZipOutputStream(baos)) {
|
||||||
Files.createDirectories(basePath);
|
|
||||||
log.info("Base directory created: {}", basePath);
|
|
||||||
|
|
||||||
int exportedCount = 0;
|
for (Contestant contestant : contestants) {
|
||||||
|
Integer contestantNumber = contestant.getContestantNumber();
|
||||||
// 3. 遍历每个参赛者,下载文件
|
if (contestantNumber == null) {
|
||||||
for (Contestant contestant : contestants) {
|
log.warn("Contestant {} has no contestantNumber, skipping", contestant.getId());
|
||||||
Integer contestantNumber = contestant.getContestantNumber();
|
continue;
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 下载视频文件
|
String dirPrefix = contestantNumber + "/";
|
||||||
String videoPath = contestant.getVideoPath();
|
|
||||||
if (StringUtils.isNotBlank(videoPath)) {
|
// 添加 PDF 文件
|
||||||
try {
|
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("/") ?
|
String fileName = videoPath.contains("/") ?
|
||||||
videoPath.substring(videoPath.lastIndexOf("/") + 1) : "video.mp4";
|
videoPath.substring(videoPath.lastIndexOf("/") + 1) : "video.mp4";
|
||||||
downloadFileFromMinio(videoPath, contestantPath.toString(), fileName);
|
addMinioFileToZip(zos, videoPath, dirPrefix + fileName);
|
||||||
log.info("Downloaded video for contestant {}", contestantNumber);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Failed to download video for contestant {}: {}", contestantNumber, e.getMessage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加参赛者信息 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下载文件到本地
|
* 将 MinIO 文件流式写入 ZIP,不落盘
|
||||||
* @param minioPath MinIO路径 (格式: bucketName/objectPath)
|
* @param zos ZIP 输出流
|
||||||
* @param localDir 本地目录
|
* @param minioPath MinIO 路径(格式: bucketName/objectPath)
|
||||||
* @param fileName 本地文件名
|
* @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)) {
|
if (StringUtils.isBlank(minioPath)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从路径中提取bucket名称和对象名称
|
|
||||||
int index = minioPath.indexOf("/");
|
int index = minioPath.indexOf("/");
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
log.warn("Invalid MinIO path: {}", minioPath);
|
log.warn("Invalid MinIO path: {}", minioPath);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String bucketName = minioPath.substring(0, index);
|
String bucketName = minioPath.substring(0, index);
|
||||||
String objectName = minioPath.substring(index + 1);
|
String objectName = minioPath.substring(index + 1);
|
||||||
|
|
||||||
// 构建本地文件完整路径
|
try (InputStream in = minioUtil.download(bucketName, objectName)) {
|
||||||
Path localFilePath = Paths.get(localDir, fileName);
|
ZipEntry entry = new ZipEntry(entryName);
|
||||||
|
zos.putNextEntry(entry);
|
||||||
// 下载文件
|
byte[] buffer = new byte[8192];
|
||||||
minioUtil.downloadMinioObjectToLocal(bucketName, objectName, localFilePath.toString());
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1060,11 +1060,12 @@ public class StripeServiceImpl implements StripeService {
|
|||||||
String periodEnd = DateUtil.changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_yyyy_MM_dd_HH_mm_ss);
|
String periodEnd = DateUtil.changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_yyyy_MM_dd_HH_mm_ss);
|
||||||
|
|
||||||
qwPI.lambda().eq(PaymentInfo::getOrderNo, subscriptionInfo.getOrderNo())
|
qwPI.lambda().eq(PaymentInfo::getOrderNo, subscriptionInfo.getOrderNo())
|
||||||
|
.eq(PaymentInfo::getTradeState, "paid")
|
||||||
.between(PaymentInfo::getCreateTime, periodStart, periodEnd)
|
.between(PaymentInfo::getCreateTime, periodStart, periodEnd)
|
||||||
.orderByDesc(PaymentInfo::getId);
|
.orderByDesc(PaymentInfo::getId);
|
||||||
List<PaymentInfo> paymentInfos = paymentInfoMapper.selectList(qwPI);
|
List<PaymentInfo> paymentInfos = paymentInfoMapper.selectList(qwPI);
|
||||||
if (paymentInfos.isEmpty()) {
|
if (paymentInfos.isEmpty()) {
|
||||||
log.info("不发送邮件,原因:【根据order_no:{},查询到的paymentInfos为空】", orderNo);
|
log.info("不发送邮件,原因:【根据order_no:{},查询到的成功的paymentInfos为空】", orderNo);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
PaymentInfo paymentInfo = paymentInfos.get(0);
|
PaymentInfo paymentInfo = paymentInfos.get(0);
|
||||||
|
|||||||
@@ -905,15 +905,15 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 将构建好的结果对象添加到返回列表
|
// 将构建好的结果对象添加到返回列表
|
||||||
results.add(magicToolResultVO);
|
// results.add(magicToolResultVO);
|
||||||
} else if (Objects.isNull(magicToolResultVO)) {
|
} else if (Objects.isNull(magicToolResultVO)) {
|
||||||
// 如果Redis中没有结果对象,创建执行中状态的结果对象
|
// 如果Redis中没有结果对象,创建执行中状态的结果对象
|
||||||
magicToolResultVO = new MagicToolResultVO(taskId, "Executing");
|
magicToolResultVO = new MagicToolResultVO(taskId, "Executing");
|
||||||
results.add(magicToolResultVO);
|
// results.add(magicToolResultVO);
|
||||||
} else {
|
}/* else {
|
||||||
// 如果Redis中有结果对象但URL为空,直接添加到返回列表
|
// 如果Redis中有结果对象但URL为空,直接添加到返回列表
|
||||||
results.add(magicToolResultVO);
|
results.add(magicToolResultVO);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
// 收集任务状态用于统计
|
// 收集任务状态用于统计
|
||||||
if (!StringUtil.isNullOrEmpty(magicToolResultVO.getStatus())) collect.add(magicToolResultVO.getStatus());
|
if (!StringUtil.isNullOrEmpty(magicToolResultVO.getStatus())) collect.add(magicToolResultVO.getStatus());
|
||||||
@@ -1461,12 +1461,16 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
|
|||||||
if (StringUtil.isNullOrEmpty(fluxResult)) {
|
if (StringUtil.isNullOrEmpty(fluxResult)) {
|
||||||
toProductImageResult.setStatus("Fail");
|
toProductImageResult.setStatus("Fail");
|
||||||
toProductImageResultMapper.updateById(toProductImageResult);
|
toProductImageResultMapper.updateById(toProductImageResult);
|
||||||
sortRank(toProductImageResult);
|
if (toProductImageResult.getIsLike() != null && toProductImageResult.getIsLike() == 1) {
|
||||||
|
sortRank(toProductImageResult);
|
||||||
|
}
|
||||||
results.add(new MagicToolResultVO(taskId, "Fail"));
|
results.add(new MagicToolResultVO(taskId, "Fail"));
|
||||||
} else if (fluxResult.equals("Fail") || fluxResult.equals("Pending")) {
|
} else if (fluxResult.equals("Fail") || fluxResult.equals("Pending")) {
|
||||||
toProductImageResult.setStatus(fluxResult);
|
toProductImageResult.setStatus(fluxResult);
|
||||||
toProductImageResultMapper.updateById(toProductImageResult);
|
toProductImageResultMapper.updateById(toProductImageResult);
|
||||||
sortRank(toProductImageResult);
|
if (fluxResult.equals("Fail") && toProductImageResult.getIsLike() != null && toProductImageResult.getIsLike() == 1) {
|
||||||
|
sortRank(toProductImageResult);
|
||||||
|
}
|
||||||
results.add(new MagicToolResultVO(taskId, fluxResult));
|
results.add(new MagicToolResultVO(taskId, fluxResult));
|
||||||
} else {
|
} else {
|
||||||
results.add(processFluxResult(fluxResult, toProductImageResult, taskId, toProductImageRecord.getPrompt()));
|
results.add(processFluxResult(fluxResult, toProductImageResult, taskId, toProductImageRecord.getPrompt()));
|
||||||
@@ -2203,10 +2207,14 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
|
|||||||
childCollectionQw.lambda().orderByAsc(CollectionSort::getSort);
|
childCollectionQw.lambda().orderByAsc(CollectionSort::getSort);
|
||||||
List<CollectionSort> childSortList = collectionSortMapper.selectList(childCollectionQw);
|
List<CollectionSort> childSortList = collectionSortMapper.selectList(childCollectionQw);
|
||||||
List<AllCollectionVO> childList = new ArrayList<>();
|
List<AllCollectionVO> childList = new ArrayList<>();
|
||||||
|
// 收集需要删除的失败记录ID,用于后续统一清理并重新排序
|
||||||
|
List<Long> failedSortIds = new ArrayList<>();
|
||||||
for (CollectionSort userLikeSort : childSortList) {
|
for (CollectionSort userLikeSort : childSortList) {
|
||||||
if (userLikeSort.getRelationType().equals(CollectionType.TO_PRODUCT_IMAGE.getValue())) {
|
if (userLikeSort.getRelationType().equals(CollectionType.TO_PRODUCT_IMAGE.getValue())) {
|
||||||
ToProductImageResult toProductImageResult = toProductImageResultMapper.selectById(userLikeSort.getRelationId());
|
ToProductImageResult toProductImageResult = toProductImageResultMapper.selectById(userLikeSort.getRelationId());
|
||||||
if (isGenerateTaskFailed(toProductImageResult.getStatus(), toProductImageResult.getCreateTime())) {
|
if (isGenerateTaskFailed(toProductImageResult.getStatus(), toProductImageResult.getCreateTime())) {
|
||||||
|
failedSortIds.add(userLikeSort.getId());
|
||||||
|
log.info("【获取内容】TO_PRODUCT_IMAGE结果失败,relationId={},即将从collection_sort中删除", userLikeSort.getRelationId());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
toProductImageResult.setUrl(getMinioUrl(toProductImageResult.getUrl()));
|
toProductImageResult.setUrl(getMinioUrl(toProductImageResult.getUrl()));
|
||||||
@@ -2238,6 +2246,8 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
|
|||||||
} else if (userLikeSort.getRelationType().equals(CollectionType.RELIGHT.getValue())) {
|
} else if (userLikeSort.getRelationType().equals(CollectionType.RELIGHT.getValue())) {
|
||||||
ToProductImageResult toProductImageResult = toProductImageResultMapper.selectById(userLikeSort.getRelationId());
|
ToProductImageResult toProductImageResult = toProductImageResultMapper.selectById(userLikeSort.getRelationId());
|
||||||
if (isGenerateTaskFailed(toProductImageResult.getStatus(), toProductImageResult.getCreateTime())) {
|
if (isGenerateTaskFailed(toProductImageResult.getStatus(), toProductImageResult.getCreateTime())) {
|
||||||
|
failedSortIds.add(userLikeSort.getId());
|
||||||
|
log.info("【获取内容】RELIGHT结果失败,relationId={},即将从collection_sort中删除", userLikeSort.getRelationId());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
toProductImageResult.setUrl(getMinioUrl(toProductImageResult.getUrl()));
|
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())) {
|
} else if (userLikeSort.getRelationType().equals(CollectionType.POSE_TRANSFORM.getValue())) {
|
||||||
PoseTransformation item = poseTransformationMapper.selectById(userLikeSort.getRelationId());
|
PoseTransformation item = poseTransformationMapper.selectById(userLikeSort.getRelationId());
|
||||||
if (isGenerateTaskFailed(item.getTaskStatus(), item.getCreateTime())) {
|
if (isGenerateTaskFailed(item.getTaskStatus(), item.getCreateTime())) {
|
||||||
|
failedSortIds.add(userLikeSort.getId());
|
||||||
|
log.info("【获取内容】POSE_TRANSFORM结果失败,relationId={},即将从collection_sort中删除", userLikeSort.getRelationId());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
PoseTransformationVO poseTransformationVO = new PoseTransformationVO();
|
PoseTransformationVO poseTransformationVO = new PoseTransformationVO();
|
||||||
@@ -2293,6 +2305,114 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
|
|||||||
childList.add(poseTransformationVO);
|
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);
|
o.setChildList(childList);
|
||||||
|
|
||||||
list.add(o);
|
list.add(o);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#spring.profiles.active=test
|
#spring.profiles.active=test
|
||||||
|
|
||||||
#<23><><EFBFBD><EFBFBD>application-prod<6F>ļ<EFBFBD>(<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
#<23><><EFBFBD><EFBFBD>application-prod<6F>ļ<EFBFBD>(<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
||||||
#spring.profiles.active=prod
|
spring.profiles.active=prod
|
||||||
|
|
||||||
#<23><><EFBFBD><EFBFBD>application-dev<65>ļ<EFBFBD>(<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
#<23><><EFBFBD><EFBFBD>application-dev<65>ļ<EFBFBD>(<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
||||||
spring.profiles.active=dev
|
#spring.profiles.active=dev
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ paypal.webhook_id=1D107312EX592781K
|
|||||||
##### Stripe
|
##### Stripe
|
||||||
|
|
||||||
# developer
|
# developer
|
||||||
stripe.private-key=sk_test_51P4ZZL02n1TEydyN8qQHjOA9imsFU7Oxs2HMHGy2urHnnQgSHnZuu5vVP6pKhEACwUpsKNyrbZpdcg5TJWJLRHcY008dEO1fn2
|
#stripe.private-key=sk_test_51P4ZZL02n1TEydyN8qQHjOA9imsFU7Oxs2HMHGy2urHnnQgSHnZuu5vVP6pKhEACwUpsKNyrbZpdcg5TJWJLRHcY008dEO1fn2
|
||||||
# dev 端点
|
# dev 端点
|
||||||
stripe.webhook-sign-secret=whsec_e0dBiJngx6qqgJj6yPyJ2A9ouh1Cjv5w
|
#stripe.webhook-sign-secret=whsec_e0dBiJngx6qqgJj6yPyJ2A9ouh1Cjv5w
|
||||||
# local 端点
|
# local 端点
|
||||||
#stripe.webhook-sign-secret=whsec_TJcMSnAkh4uktrNY1M6Iy8XaVze4Rzqm
|
#stripe.webhook-sign-secret=whsec_TJcMSnAkh4uktrNY1M6Iy8XaVze4Rzqm
|
||||||
|
|
||||||
@@ -43,8 +43,8 @@ stripe.webhook-sign-secret=whsec_e0dBiJngx6qqgJj6yPyJ2A9ouh1Cjv5w
|
|||||||
#stripe.webhook-sign-secret=whsec_pX0pPMQm85PaUSWnFMEzoccb3MGNkjoL
|
#stripe.webhook-sign-secret=whsec_pX0pPMQm85PaUSWnFMEzoccb3MGNkjoL
|
||||||
|
|
||||||
# kim - live
|
# kim - live
|
||||||
#stripe.private-key=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
|
stripe.private-key=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
|
||||||
# prod 端点
|
# prod 端点
|
||||||
#stripe.webhook-sign-secret=whsec_hhGDgdelQRHSg4LmChtQe41crj41eb11
|
stripe.webhook-sign-secret=whsec_hhGDgdelQRHSg4LmChtQe41crj41eb11
|
||||||
# dev 端点
|
# dev 端点
|
||||||
#stripe.webhook-sign-secret=whsec_cFUtjUOo8wnrIKZmt4GNvt7ZY1bOfrYr
|
#stripe.webhook-sign-secret=whsec_cFUtjUOo8wnrIKZmt4GNvt7ZY1bOfrYr
|
||||||
|
|||||||
Reference in New Issue
Block a user