From 1d46a3b6d412827d93f50ec5785090d8f7ac035c Mon Sep 17 00:00:00 2001 From: xupei Date: Thu, 27 Mar 2025 15:38:25 +0800 Subject: [PATCH 01/32] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=9C=AC=E5=9C=B0?= =?UTF-8?q?=E7=BC=93=E5=AD=98=E7=9A=84=E8=BF=87=E6=9C=9F=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ai/da/common/utils/LocalCacheUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ai/da/common/utils/LocalCacheUtils.java b/src/main/java/com/ai/da/common/utils/LocalCacheUtils.java index 82235e8c..99858827 100644 --- a/src/main/java/com/ai/da/common/utils/LocalCacheUtils.java +++ b/src/main/java/com/ai/da/common/utils/LocalCacheUtils.java @@ -28,7 +28,7 @@ public final class LocalCacheUtils { private static LoadingCache loadTokenCache() { LoadingCache tokenCache = CacheBuilder.newBuilder() .concurrencyLevel(10) - .expireAfterWrite(24 * 100, TimeUnit.HOURS) + .expireAfterWrite(24 * (7 - 1), TimeUnit.HOURS) .initialCapacity(100) .maximumSize(10000) .recordStats() From 5612b5b1d4db07eceffc3f164c1a277447119edb Mon Sep 17 00:00:00 2001 From: xupei Date: Mon, 31 Mar 2025 09:48:09 +0800 Subject: [PATCH 02/32] =?UTF-8?q?AiDA=208=E6=8A=98=E4=BC=98=E6=83=A0?= =?UTF-8?q?=E6=B4=BB=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ai/da/common/enums/ProductEnum.java | 4 ++-- src/main/java/com/ai/da/service/impl/AccountServiceImpl.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ai/da/common/enums/ProductEnum.java b/src/main/java/com/ai/da/common/enums/ProductEnum.java index 11237ffe..70ad57e6 100644 --- a/src/main/java/com/ai/da/common/enums/ProductEnum.java +++ b/src/main/java/com/ai/da/common/enums/ProductEnum.java @@ -9,9 +9,9 @@ public enum ProductEnum { // 积分购买 CreditsProduct("AiDA credits purchase", 6L), // 年度订阅 - AnnualSubscription("AiDA Annual Subscription", 5000L), + AnnualSubscription("AiDA Annual Subscription", 4000L), // 月度订阅 - MonthlySubscription("AiDA Monthly Subscription", 500L), + MonthlySubscription("AiDA Monthly Subscription", 400L), // 测试 DailySubscription("AiDA Daily Subscription", 5L), ; diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 85d73fc4..103af007 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -1436,11 +1436,11 @@ public class AccountServiceImpl extends ServiceImpl impl // 不管是不是新用户 都要更新用户角色和积分 String credits = "0"; - if (totalSales == 5000.0){ + if (totalSales == 5000.0 || totalSales == 4000.0){ log.info("年付用户,初始积分6000"); credits = CreditsEventsEnum.INIT_MONTHLY.getValue(); systemUserType = 1; - }else if (totalSales == 500.0){ + }else if (totalSales == 500.0 || totalSales == 400.0){ log.info("月付用户,初始积分5000"); credits = CreditsEventsEnum.INIT_MONTHLY.getValue(); systemUserType = 2; From 6b4d82a67dbe4d1bfac5e6d6ad28f42d4f7fb4a0 Mon Sep 17 00:00:00 2001 From: xupei Date: Mon, 31 Mar 2025 17:45:16 +0800 Subject: [PATCH 03/32] =?UTF-8?q?AiDA=208=E6=8A=98=E4=BC=98=E6=83=A0?= =?UTF-8?q?=E6=B4=BB=E5=8A=A8=E6=81=A2=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ai/da/common/enums/ProductEnum.java | 4 ++-- src/main/java/com/ai/da/service/impl/AccountServiceImpl.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ai/da/common/enums/ProductEnum.java b/src/main/java/com/ai/da/common/enums/ProductEnum.java index 70ad57e6..11237ffe 100644 --- a/src/main/java/com/ai/da/common/enums/ProductEnum.java +++ b/src/main/java/com/ai/da/common/enums/ProductEnum.java @@ -9,9 +9,9 @@ public enum ProductEnum { // 积分购买 CreditsProduct("AiDA credits purchase", 6L), // 年度订阅 - AnnualSubscription("AiDA Annual Subscription", 4000L), + AnnualSubscription("AiDA Annual Subscription", 5000L), // 月度订阅 - MonthlySubscription("AiDA Monthly Subscription", 400L), + MonthlySubscription("AiDA Monthly Subscription", 500L), // 测试 DailySubscription("AiDA Daily Subscription", 5L), ; diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 103af007..85d73fc4 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -1436,11 +1436,11 @@ public class AccountServiceImpl extends ServiceImpl impl // 不管是不是新用户 都要更新用户角色和积分 String credits = "0"; - if (totalSales == 5000.0 || totalSales == 4000.0){ + if (totalSales == 5000.0){ log.info("年付用户,初始积分6000"); credits = CreditsEventsEnum.INIT_MONTHLY.getValue(); systemUserType = 1; - }else if (totalSales == 500.0 || totalSales == 400.0){ + }else if (totalSales == 500.0){ log.info("月付用户,初始积分5000"); credits = CreditsEventsEnum.INIT_MONTHLY.getValue(); systemUserType = 2; From 08072001a780b3b83298ae1e39fb45f0aac4af17 Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Mon, 31 Mar 2025 17:47:25 +0800 Subject: [PATCH 04/32] =?UTF-8?q?BUGFIX:dislike=E5=90=88=E5=B9=B6=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E5=8E=BB=E9=99=A4;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/ai/da/service/impl/DesignServiceImpl.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java index 93ecf34f..8ff764ad 100644 --- a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java @@ -1265,10 +1265,10 @@ public class DesignServiceImpl extends ServiceImpl impleme if (Objects.isNull(design)) { throw new BusinessException("design.detail.not.found"); } - if (!userLike.getDesignId().equals(disDesignLikeDTO.getDesignId())) { - //不是相同的design不会合并 - return Boolean.TRUE; - } +// if (!userLike.getDesignId().equals(disDesignLikeDTO.getDesignId())) { +// //不是相同的design不会合并 +// return Boolean.TRUE; +// } //修改designItem为dislike状态 designItemService.updateLikeStatus(userLike.getDesignItemId(), (byte) 0); //删除关联的collection,先不做 From 1f0e8f9cf2b7244a8f9b8d95a0a8a68e4187e99a Mon Sep 17 00:00:00 2001 From: xupei Date: Wed, 7 May 2025 14:10:42 +0800 Subject: [PATCH 05/32] =?UTF-8?q?BUGFIX:=20designSingle=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=9B=B8=E5=90=8C=E7=B1=BB=E5=9E=8B=E7=9A=84?= =?UTF-8?q?=E6=9C=8D=E8=A3=85=E5=AF=BC=E8=87=B4=E6=9C=AA=E5=88=86=E5=89=B2?= =?UTF-8?q?=E5=9B=BE=E5=B1=82=E8=8E=B7=E5=8F=96=E6=B7=B7=E4=B9=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ai/da/service/DesignItemService.java | 2 +- .../service/impl/DesignItemServiceImpl.java | 26 ++++++++++--------- .../ai/da/service/impl/DesignServiceImpl.java | 12 ++++----- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/ai/da/service/DesignItemService.java b/src/main/java/com/ai/da/service/DesignItemService.java index fcc1e78b..09e4adc9 100644 --- a/src/main/java/com/ai/da/service/DesignItemService.java +++ b/src/main/java/com/ai/da/service/DesignItemService.java @@ -53,7 +53,7 @@ public interface DesignItemService extends IService { DesignSingleVO designSingleIncludeLayers(DesignSingleIncludeLayersDTO designSingleIncludeLayersDTO); - Map setTypeAndUndividedLayer(JSONArray layers); + Map setPriorityAndUndividedLayer(JSONArray layers); ComposeLayersVO editLayersPositionAndScale(EditLayersPositionAndScaleVO positionAndScaleVO) throws IOException; diff --git a/src/main/java/com/ai/da/service/impl/DesignItemServiceImpl.java b/src/main/java/com/ai/da/service/impl/DesignItemServiceImpl.java index 0c4159d3..a90b44bd 100644 --- a/src/main/java/com/ai/da/service/impl/DesignItemServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/DesignItemServiceImpl.java @@ -26,7 +26,6 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.google.common.collect.Lists; -import com.mysql.cj.util.StringUtils; import io.netty.util.internal.StringUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.SerializationUtils; @@ -326,7 +325,7 @@ public class DesignItemServiceImpl extends ServiceImpl saveDesignSingleItemDetailAndLayers(DesignPythonObjects pythonObjects , Long designId, Long designItemId, Long userId , JSONObject outfit, String timeZone, List designSingleItemDTOList - , Map categoryAndUndividedLayer) { + , Map priorityAndUndividedLayer) { DesignItem designItem = new DesignItem(); // String url = pythonObjects.getObjects().get(0).getBasic().getSave_name(); @@ -357,7 +356,8 @@ public class DesignItemServiceImpl extends ServiceImpl categoryAndUndividedLayer = setTypeAndUndividedLayer(layers); + Map priorityAndUndividedLayer = setPriorityAndUndividedLayer(layers); if (!designSingleIncludeLayersDTO.getIsPreview()) { // 更新及保存图层信息 tDesignPythonOutfitDetails = saveDesignSingleItemDetailAndLayers(objects, design.getId(), designSingleIncludeLayersDTO.getDesignItemId() , userId, outfit, designSingleIncludeLayersDTO.getTimeZone() , designSingleIncludeLayersDTO.getDesignSingleItemDTOList() - , categoryAndUndividedLayer); + , priorityAndUndividedLayer); saveCollectionElement(designSingleIncludeLayersDTO); } else { @@ -576,7 +576,7 @@ public class DesignItemServiceImpl extends ServiceImpl setTypeAndUndividedLayer(JSONArray layers){ - HashMap categoryAndLayer = new HashMap<>(); + public Map setPriorityAndUndividedLayer(JSONArray layers){ + HashMap priorityAndLayer = new HashMap<>(); for (int i = 0; i < layers.size(); i++) { JSONObject jsonObject = layers.getJSONObject(i); + String priority = jsonObject.getString("priority"); String category = jsonObject.getString("image_category").split("_")[0]; - if (!category.equals("body") && !categoryAndLayer.containsKey(category)) categoryAndLayer.put(category, jsonObject.getString("pattern_image_url")); +// if (!category.equals("body") && !categoryAndLayer.containsKey(category)) categoryAndLayer.put(category, jsonObject.getString("pattern_image_url")); + if (!category.equals("body") && !priorityAndLayer.containsKey(priority)) priorityAndLayer.put(priority, jsonObject.getString("pattern_image_url")); } - return categoryAndLayer; + return priorityAndLayer; } @Override @@ -726,7 +728,7 @@ public class DesignItemServiceImpl extends ServiceImpl designSingleItemDTOList, List layersObject, String singleOrOverall, - Map categoryAndUndividedLayer) { + Map priorityAndUndividedLayer) { DesignSingleVO designSingleVO = new DesignSingleVO(); ArrayList clothes = new ArrayList<>(); @@ -761,7 +763,7 @@ public class DesignItemServiceImpl extends ServiceImpl layers.getImageCategory().equals("body")).collect(Collectors.toList())); clothes.add(designItemClothesDetailVO); diff --git a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java index 8ff764ad..af06bd06 100644 --- a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java @@ -786,7 +786,7 @@ public class DesignServiceImpl extends ServiceImpl impleme Map typePriority = list.stream().collect(Collectors.toMap(d -> d.getImageCategory().split("_")[0], d -> Math.abs(d.getPriority()), (existing, replacement) -> replacement)); - Map typeAndUndividedLayer = designItemService.setTypeAndUndividedLayer(layers); + Map priorityAndUndividedLayer = designItemService.setPriorityAndUndividedLayer(layers); for (DesignPythonItem detail : item.getItems()) { if (null == detail) { continue; @@ -797,7 +797,7 @@ public class DesignServiceImpl extends ServiceImpl impleme designItemDetail.setDesignItemId(designItemId); designItemDetail.setCollectionElementId(detail.getElementId()); designItemDetail.setCreateDate(DateUtil.getByTimeZone(timeZone)); - designItemDetail.setUndividedLayer(typeAndUndividedLayer.get(designItemDetail.getType().toLowerCase())); + if (!detail.getType().equals("Body")) designItemDetail.setUndividedLayer(priorityAndUndividedLayer.get(designItemDetail.getPriority().toString())); if (SysFileLevel2TypeEnum.BODY.getRealName().equals(detail.getType())) { designItemDetail.setPath(detail.getBody_path()); //BODY不关联businessId @@ -917,7 +917,7 @@ public class DesignServiceImpl extends ServiceImpl impleme Map typePriority = list.stream().collect(Collectors.toMap(d -> d.getImageCategory().split("_")[0], d -> Math.abs(d.getPriority()), (existing, replacement) -> replacement)); - Map typeAndUndividedLayer = designItemService.setTypeAndUndividedLayer(layers); + Map priorityAndUndividedLayer = designItemService.setPriorityAndUndividedLayer(layers); for (DesignPythonItem detail : item.getItems()) { if (null == detail) { continue; @@ -928,7 +928,7 @@ public class DesignServiceImpl extends ServiceImpl impleme designItemDetail.setDesignItemId(designItemId); designItemDetail.setCollectionElementId(detail.getElementId()); designItemDetail.setCreateDate(DateUtil.getByTimeZone(timeZone)); - designItemDetail.setUndividedLayer(typeAndUndividedLayer.get(designItemDetail.getType().toLowerCase())); + if (!detail.getType().equals("Body")) designItemDetail.setUndividedLayer(priorityAndUndividedLayer.get(designItemDetail.getPriority().toString())); if (SysFileLevel2TypeEnum.BODY.getRealName().equals(detail.getType())) { designItemDetail.setPath(detail.getBody_path()); //BODY不关联businessId @@ -1977,7 +1977,7 @@ public class DesignServiceImpl extends ServiceImpl impleme Map typePriority = list.stream().collect(Collectors.toMap(d -> d.getImageCategory().split("_")[0], d -> Math.abs(d.getPriority()), (existing, replacement) -> replacement)); - Map typeAndUndividedLayer = designItemService.setTypeAndUndividedLayer(layers); + Map priorityAndUndividedLayer = designItemService.setPriorityAndUndividedLayer(layers); for (DesignPythonItem detail : item.getItems()) { if (null == detail) { continue; @@ -1988,7 +1988,7 @@ public class DesignServiceImpl extends ServiceImpl impleme designItemDetail.setDesignItemId(designItemId); designItemDetail.setCollectionElementId(detail.getElementId()); designItemDetail.setCreateDate(DateUtil.getByTimeZone(timeZone)); - designItemDetail.setUndividedLayer(typeAndUndividedLayer.get(designItemDetail.getType().toLowerCase())); + if (!detail.getType().equals("Body")) designItemDetail.setUndividedLayer(priorityAndUndividedLayer.get(designItemDetail.getPriority().toString())); if (SysFileLevel2TypeEnum.BODY.getRealName().equals(detail.getType())) { designItemDetail.setPath(detail.getBody_path()); //BODY不关联businessId From eea57435e55cbfedea8e4900bd1a92ff6c80249f Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Wed, 7 May 2025 22:04:10 +0800 Subject: [PATCH 06/32] =?UTF-8?q?TASK:minio=E5=9C=B0=E5=9D=80=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-prod.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application-prod.properties b/src/main/resources/application-prod.properties index 3000f6cb..6b1e7b52 100644 --- a/src/main/resources/application-prod.properties +++ b/src/main/resources/application-prod.properties @@ -50,7 +50,7 @@ access.python.port=9990 access.python.generate_sr_port=9990 access.python.address=http://18.167.251.121:9990 -minio.endpoint=https://www.minio.aida.com.hk:12024 +minio.endpoint=https://www.minio-api.aida.com.hk minio.accessKey=admin minio.secretKey=Aidlab123123! minio.bucketName.clothing=aida-clothing From 1a077edf0c78209b99acf915c9d36881000eaf49 Mon Sep 17 00:00:00 2001 From: xupei Date: Thu, 8 May 2025 14:19:26 +0800 Subject: [PATCH 07/32] =?UTF-8?q?designSingle=20=E5=8F=96=E6=B6=88?= =?UTF-8?q?=E9=A2=9C=E8=89=B2=E9=99=90=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ai/da/model/dto/DesignSingleItemDTO.java | 1 - src/main/java/com/ai/da/service/impl/DesignItemServiceImpl.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/ai/da/model/dto/DesignSingleItemDTO.java b/src/main/java/com/ai/da/model/dto/DesignSingleItemDTO.java index c3ffd2e7..3138790c 100644 --- a/src/main/java/com/ai/da/model/dto/DesignSingleItemDTO.java +++ b/src/main/java/com/ai/da/model/dto/DesignSingleItemDTO.java @@ -32,7 +32,6 @@ public class DesignSingleItemDTO implements Serializable { @ApiModelProperty("对应的图片的minIO路径") private String path; - @NotBlank(message = "color.cannot.be.empty") @ApiModelProperty("颜色 存 RGB值 中间空格分隔 比如 \"58 58 169\"") private String color; diff --git a/src/main/java/com/ai/da/service/impl/DesignItemServiceImpl.java b/src/main/java/com/ai/da/service/impl/DesignItemServiceImpl.java index a90b44bd..2d8413aa 100644 --- a/src/main/java/com/ai/da/service/impl/DesignItemServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/DesignItemServiceImpl.java @@ -755,7 +755,7 @@ public class DesignItemServiceImpl extends ServiceImpl Date: Thu, 8 May 2025 14:54:12 +0800 Subject: [PATCH 08/32] =?UTF-8?q?BUGFIX=20:=20design=20=E6=9C=AA=E5=88=86?= =?UTF-8?q?=E5=89=B2=E5=9B=BE=E5=B1=82=E4=BF=9D=E5=AD=98=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ai/da/service/impl/DesignServiceImpl.java | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java index af06bd06..8a8599b3 100644 --- a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java @@ -797,7 +797,13 @@ public class DesignServiceImpl extends ServiceImpl impleme designItemDetail.setDesignItemId(designItemId); designItemDetail.setCollectionElementId(detail.getElementId()); designItemDetail.setCreateDate(DateUtil.getByTimeZone(timeZone)); - if (!detail.getType().equals("Body")) designItemDetail.setUndividedLayer(priorityAndUndividedLayer.get(designItemDetail.getPriority().toString())); + log.info("detail.getType: {}", detail.getType()); + if (!detail.getType().equals("Body")){ + log.info("designItemDetail.getPriority(): {}", designItemDetail.getPriority()); + if (Objects.nonNull(designItemDetail.getPriority())){ + designItemDetail.setUndividedLayer(priorityAndUndividedLayer.get(designItemDetail.getPriority().toString())); + } + } if (SysFileLevel2TypeEnum.BODY.getRealName().equals(detail.getType())) { designItemDetail.setPath(detail.getBody_path()); //BODY不关联businessId @@ -928,7 +934,14 @@ public class DesignServiceImpl extends ServiceImpl impleme designItemDetail.setDesignItemId(designItemId); designItemDetail.setCollectionElementId(detail.getElementId()); designItemDetail.setCreateDate(DateUtil.getByTimeZone(timeZone)); - if (!detail.getType().equals("Body")) designItemDetail.setUndividedLayer(priorityAndUndividedLayer.get(designItemDetail.getPriority().toString())); + log.info("detail.getType: {}", detail.getType()); + if (!detail.getType().equals("Body")){ + log.info("designItemDetail.getPriority(): {}", designItemDetail.getPriority()); + if (Objects.nonNull(designItemDetail.getPriority())){ + designItemDetail.setUndividedLayer(priorityAndUndividedLayer.get(designItemDetail.getPriority().toString())); + } + } + if (SysFileLevel2TypeEnum.BODY.getRealName().equals(detail.getType())) { designItemDetail.setPath(detail.getBody_path()); //BODY不关联businessId @@ -1988,7 +2001,13 @@ public class DesignServiceImpl extends ServiceImpl impleme designItemDetail.setDesignItemId(designItemId); designItemDetail.setCollectionElementId(detail.getElementId()); designItemDetail.setCreateDate(DateUtil.getByTimeZone(timeZone)); - if (!detail.getType().equals("Body")) designItemDetail.setUndividedLayer(priorityAndUndividedLayer.get(designItemDetail.getPriority().toString())); + log.info("detail.getType: {}", detail.getType()); + if (!detail.getType().equals("Body")){ + log.info("designItemDetail.getPriority(): {}", designItemDetail.getPriority()); + if (Objects.nonNull(designItemDetail.getPriority())){ + designItemDetail.setUndividedLayer(priorityAndUndividedLayer.get(designItemDetail.getPriority().toString())); + } + } if (SysFileLevel2TypeEnum.BODY.getRealName().equals(detail.getType())) { designItemDetail.setPath(detail.getBody_path()); //BODY不关联businessId From 0c79739867935e267b7a32faa77699d279baf8be Mon Sep 17 00:00:00 2001 From: xupei Date: Thu, 8 May 2025 15:26:06 +0800 Subject: [PATCH 09/32] =?UTF-8?q?BUGFIX:=20design=E4=B9=8B=E5=90=8E?= =?UTF-8?q?=EF=BC=8C=E6=9C=AA=E5=88=86=E5=89=B2=E5=9B=BE=E7=89=87=E7=9A=84?= =?UTF-8?q?=E4=BF=9D=E5=AD=98=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ai/da/service/DesignItemService.java | 2 ++ .../service/impl/DesignItemServiceImpl.java | 13 +++++++++- .../ai/da/service/impl/DesignServiceImpl.java | 24 +++++-------------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/ai/da/service/DesignItemService.java b/src/main/java/com/ai/da/service/DesignItemService.java index 09e4adc9..6702ad52 100644 --- a/src/main/java/com/ai/da/service/DesignItemService.java +++ b/src/main/java/com/ai/da/service/DesignItemService.java @@ -55,6 +55,8 @@ public interface DesignItemService extends IService { Map setPriorityAndUndividedLayer(JSONArray layers); + Map setTypeAndUndividedLayer(JSONArray layers); + ComposeLayersVO editLayersPositionAndScale(EditLayersPositionAndScaleVO positionAndScaleVO) throws IOException; List selectDesignIdById(List designItemIdList); diff --git a/src/main/java/com/ai/da/service/impl/DesignItemServiceImpl.java b/src/main/java/com/ai/da/service/impl/DesignItemServiceImpl.java index 2d8413aa..92ae196b 100644 --- a/src/main/java/com/ai/da/service/impl/DesignItemServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/DesignItemServiceImpl.java @@ -631,12 +631,23 @@ public class DesignItemServiceImpl extends ServiceImpl setTypeAndUndividedLayer(JSONArray layers){ + HashMap typeAndLayer = new HashMap<>(); + for (int i = 0; i < layers.size(); i++) { + JSONObject jsonObject = layers.getJSONObject(i); + String category = jsonObject.getString("image_category").split("_")[0]; + if (!category.equals("body") && !typeAndLayer.containsKey(category)) typeAndLayer.put(category, jsonObject.getString("pattern_image_url")); + } + return typeAndLayer; + } + @Override @Transactional(rollbackFor = Exception.class) public ComposeLayersVO editLayersPositionAndScale(EditLayersPositionAndScaleVO positionAndScaleVO) throws IOException { diff --git a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java index 8a8599b3..9b49b211 100644 --- a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java @@ -786,7 +786,7 @@ public class DesignServiceImpl extends ServiceImpl impleme Map typePriority = list.stream().collect(Collectors.toMap(d -> d.getImageCategory().split("_")[0], d -> Math.abs(d.getPriority()), (existing, replacement) -> replacement)); - Map priorityAndUndividedLayer = designItemService.setPriorityAndUndividedLayer(layers); + Map typeAndUndividedLayer = designItemService.setTypeAndUndividedLayer(layers); for (DesignPythonItem detail : item.getItems()) { if (null == detail) { continue; @@ -797,12 +797,8 @@ public class DesignServiceImpl extends ServiceImpl impleme designItemDetail.setDesignItemId(designItemId); designItemDetail.setCollectionElementId(detail.getElementId()); designItemDetail.setCreateDate(DateUtil.getByTimeZone(timeZone)); - log.info("detail.getType: {}", detail.getType()); if (!detail.getType().equals("Body")){ - log.info("designItemDetail.getPriority(): {}", designItemDetail.getPriority()); - if (Objects.nonNull(designItemDetail.getPriority())){ - designItemDetail.setUndividedLayer(priorityAndUndividedLayer.get(designItemDetail.getPriority().toString())); - } + designItemDetail.setUndividedLayer(typeAndUndividedLayer.get(designItemDetail.getType())); } if (SysFileLevel2TypeEnum.BODY.getRealName().equals(detail.getType())) { designItemDetail.setPath(detail.getBody_path()); @@ -923,7 +919,7 @@ public class DesignServiceImpl extends ServiceImpl impleme Map typePriority = list.stream().collect(Collectors.toMap(d -> d.getImageCategory().split("_")[0], d -> Math.abs(d.getPriority()), (existing, replacement) -> replacement)); - Map priorityAndUndividedLayer = designItemService.setPriorityAndUndividedLayer(layers); + Map typeAndUndividedLayer = designItemService.setTypeAndUndividedLayer(layers); for (DesignPythonItem detail : item.getItems()) { if (null == detail) { continue; @@ -934,12 +930,8 @@ public class DesignServiceImpl extends ServiceImpl impleme designItemDetail.setDesignItemId(designItemId); designItemDetail.setCollectionElementId(detail.getElementId()); designItemDetail.setCreateDate(DateUtil.getByTimeZone(timeZone)); - log.info("detail.getType: {}", detail.getType()); if (!detail.getType().equals("Body")){ - log.info("designItemDetail.getPriority(): {}", designItemDetail.getPriority()); - if (Objects.nonNull(designItemDetail.getPriority())){ - designItemDetail.setUndividedLayer(priorityAndUndividedLayer.get(designItemDetail.getPriority().toString())); - } + designItemDetail.setUndividedLayer(typeAndUndividedLayer.get(designItemDetail.getType())); } if (SysFileLevel2TypeEnum.BODY.getRealName().equals(detail.getType())) { @@ -1990,7 +1982,7 @@ public class DesignServiceImpl extends ServiceImpl impleme Map typePriority = list.stream().collect(Collectors.toMap(d -> d.getImageCategory().split("_")[0], d -> Math.abs(d.getPriority()), (existing, replacement) -> replacement)); - Map priorityAndUndividedLayer = designItemService.setPriorityAndUndividedLayer(layers); + Map typeAndUndividedLayer = designItemService.setTypeAndUndividedLayer(layers); for (DesignPythonItem detail : item.getItems()) { if (null == detail) { continue; @@ -2001,12 +1993,8 @@ public class DesignServiceImpl extends ServiceImpl impleme designItemDetail.setDesignItemId(designItemId); designItemDetail.setCollectionElementId(detail.getElementId()); designItemDetail.setCreateDate(DateUtil.getByTimeZone(timeZone)); - log.info("detail.getType: {}", detail.getType()); if (!detail.getType().equals("Body")){ - log.info("designItemDetail.getPriority(): {}", designItemDetail.getPriority()); - if (Objects.nonNull(designItemDetail.getPriority())){ - designItemDetail.setUndividedLayer(priorityAndUndividedLayer.get(designItemDetail.getPriority().toString())); - } + designItemDetail.setUndividedLayer(typeAndUndividedLayer.get(designItemDetail.getType())); } if (SysFileLevel2TypeEnum.BODY.getRealName().equals(detail.getType())) { designItemDetail.setPath(detail.getBody_path()); From db55c5597f0f5de39ee2d8ee0919be6c16d159a4 Mon Sep 17 00:00:00 2001 From: xupei Date: Fri, 9 May 2025 00:18:00 +0800 Subject: [PATCH 10/32] =?UTF-8?q?undividedLayers=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E4=BF=9D=E5=AD=98=E5=A4=B1=E8=B4=A5=E5=8E=9F=E5=9B=A0=E6=9F=A5?= =?UTF-8?q?=E6=89=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ai/da/service/impl/DesignServiceImpl.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java index 9b49b211..bf31ddd9 100644 --- a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java @@ -787,6 +787,7 @@ public class DesignServiceImpl extends ServiceImpl impleme d -> Math.abs(d.getPriority()), (existing, replacement) -> replacement)); Map typeAndUndividedLayer = designItemService.setTypeAndUndividedLayer(layers); + log.info("all typeLayers Map:{}", typeAndUndividedLayer); for (DesignPythonItem detail : item.getItems()) { if (null == detail) { continue; @@ -797,7 +798,9 @@ public class DesignServiceImpl extends ServiceImpl impleme designItemDetail.setDesignItemId(designItemId); designItemDetail.setCollectionElementId(detail.getElementId()); designItemDetail.setCreateDate(DateUtil.getByTimeZone(timeZone)); + log.info("detail.getType():{}", detail.getType()); if (!detail.getType().equals("Body")){ + log.info("layer : {}", typeAndUndividedLayer.get(designItemDetail.getType())); designItemDetail.setUndividedLayer(typeAndUndividedLayer.get(designItemDetail.getType())); } if (SysFileLevel2TypeEnum.BODY.getRealName().equals(detail.getType())) { From c19e9094d1ec6750dde5b6474e6ee65a87df333d Mon Sep 17 00:00:00 2001 From: xupei Date: Fri, 9 May 2025 17:03:42 +0800 Subject: [PATCH 11/32] =?UTF-8?q?BUGFIX:=20generate=20mode=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E4=BC=A0=E9=80=92=E4=B8=8D=E5=87=86=E7=A1=AE=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E7=94=9F=E6=88=90=E7=BB=93=E6=9E=9C=E4=B8=8E=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E6=B2=A1=E6=9C=89=E5=85=B3=E8=81=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../da/service/impl/GenerateServiceImpl.java | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java b/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java index cbe440a2..b96d04b0 100644 --- a/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java @@ -111,8 +111,9 @@ public class GenerateServiceImpl extends ServiceImpl i public void generateThroughImageText(GenerateThroughImageTextDTO generateThroughImageTextDTO) { // 1、获取用户信息 Long accountId = generateThroughImageTextDTO.getUserId(); - String generateType = generateThroughImageTextDTO.getGenerateType(); + GenerateModeEnum modeEnum = getMode(generateThroughImageTextDTO); + String generateType = modeEnum.getValue(); // 2、判断必须入参是否为非空(在prepare阶段已校验) Generate generate = new Generate(); generate.setAccountId(accountId); @@ -141,9 +142,7 @@ public class GenerateServiceImpl extends ServiceImpl i CollectionElement collectionElement = collectionElementService.editLevel2Type(elementId, generateThroughImageTextDTO.getLevel2Type(), generateThroughImageTextDTO.getDesignType()); // 3、向模型发起请求 - String mode = GenerateModeEnum.TEXT.getValue().equals(generateType) ? - GenerateModeEnum.TEXT.getType() : - GenerateModeEnum.TEXT_IMAGE.getType(); + String mode = modeEnum.getType(); String category = generateThroughImageTextDTO.getLevel1Type().equals(SKETCH_BOARD.getRealName()) ? "sketch" : generateThroughImageTextDTO.getLevel1Type().equals(PRINT_BOARD.getRealName()) ? "print" : "moodboard"; String path = CommonConstant.GENERATE_PATH; @@ -188,7 +187,6 @@ public class GenerateServiceImpl extends ServiceImpl i jsonString = JSON.toJSONString(generateToPythonDTO, SerializerFeature.WriteMapNullValue); } - Boolean requestResult = pythonService.generateSketchOrPrint(jsonString, port, path); // 4、将请求信息落库,将本次generate的请求信息添加到t_generate表中 @@ -207,6 +205,21 @@ public class GenerateServiceImpl extends ServiceImpl i } + public GenerateModeEnum getMode(GenerateThroughImageTextDTO generateThroughImageTextDTO){ + if (!StringUtil.isNullOrEmpty(generateThroughImageTextDTO.getText())){ + if (Objects.nonNull(generateThroughImageTextDTO.getCollectionElementId())){ + return GenerateModeEnum.TEXT_IMAGE; + }else { + return GenerateModeEnum.TEXT; + } + }else { + if (Objects.nonNull(generateThroughImageTextDTO.getCollectionElementId())){ + return GenerateModeEnum.IMAGE; + } + } + return GenerateModeEnum.TEXT; + } + @Override @Transactional(rollbackFor = Exception.class) public void processGenerateResult(String taskId, String url, String category) { From faf98607c46b89954997e03ff5c5f630ba357b95 Mon Sep 17 00:00:00 2001 From: xupei Date: Mon, 14 Apr 2025 13:37:01 +0800 Subject: [PATCH 12/32] =?UTF-8?q?=E4=BC=98=E6=83=A0=E5=88=B8=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2DTO?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 1ce6c74f2cb79dd3ab12568fdd07fa447e3d2a1d) --- .../mapper/primary/ProductCouponsMapper.java | 8 +++ .../mapper/primary/entity/ProductCoupons.java | 49 +++++++++++++++++++ .../ai/da/model/dto/QueryCouponsPageDTO.java | 22 +++++++++ 3 files changed, 79 insertions(+) create mode 100644 src/main/java/com/ai/da/mapper/primary/ProductCouponsMapper.java create mode 100644 src/main/java/com/ai/da/mapper/primary/entity/ProductCoupons.java create mode 100644 src/main/java/com/ai/da/model/dto/QueryCouponsPageDTO.java diff --git a/src/main/java/com/ai/da/mapper/primary/ProductCouponsMapper.java b/src/main/java/com/ai/da/mapper/primary/ProductCouponsMapper.java new file mode 100644 index 00000000..f66e42a8 --- /dev/null +++ b/src/main/java/com/ai/da/mapper/primary/ProductCouponsMapper.java @@ -0,0 +1,8 @@ +package com.ai.da.mapper.primary; + +import com.ai.da.common.config.mybatis.plus.CommonMapper; +import com.ai.da.mapper.primary.entity.ProductCoupons; + +public interface ProductCouponsMapper extends CommonMapper { + +} diff --git a/src/main/java/com/ai/da/mapper/primary/entity/ProductCoupons.java b/src/main/java/com/ai/da/mapper/primary/entity/ProductCoupons.java new file mode 100644 index 00000000..66c54b0c --- /dev/null +++ b/src/main/java/com/ai/da/mapper/primary/entity/ProductCoupons.java @@ -0,0 +1,49 @@ +package com.ai.da.mapper.primary.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +@TableName("t_product_coupons") +public class ProductCoupons extends BaseEntity{ + // 优惠券id + private String couponId; + // 优惠券有效期的截止日期 + private Long redeemBy; + // 绑定的推广码id + private String promotionCodeId; + // 对应的推广码 + private String promotionCode; + // 最大兑换次数 + private Integer maxRedemptions; + // 优惠券的折扣 + private float percentOff; + // 佣金比例 + private float commissionRate; + // 合作者 + private String cooperator; + // 使用了该优惠券支付的总金额 + private float totalEarnings; + // 佣金 + private float commission; + // 已付佣金 + private float paidCommission; + // 未付佣金 + private float unpaidCommission; + // 备注 + private String remark; + + public ProductCoupons() { + } + + public ProductCoupons(String couponId, Long redeemBy, String promotionCodeId, String promotionCode, float percentOff, float commissionRate) { + this.couponId = couponId; + this.redeemBy = redeemBy; + this.promotionCodeId = promotionCodeId; + this.promotionCode = promotionCode; + this.percentOff = percentOff; + this.commissionRate = commissionRate; + } +} diff --git a/src/main/java/com/ai/da/model/dto/QueryCouponsPageDTO.java b/src/main/java/com/ai/da/model/dto/QueryCouponsPageDTO.java new file mode 100644 index 00000000..3d03dfe6 --- /dev/null +++ b/src/main/java/com/ai/da/model/dto/QueryCouponsPageDTO.java @@ -0,0 +1,22 @@ +package com.ai.da.model.dto; + + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +@ApiModel +public class QueryCouponsPageDTO extends QueryPageByTimeDTO { + @ApiModelProperty("DESC(按id降序) || ASC(按id升序)") + private String orderById; + @ApiModelProperty("推广码") + private String promotionCode; + @ApiModelProperty("查询过期 || 未过期的优惠券") + private Boolean isExpired; + @ApiModelProperty("按合作者名字查询") + private String cooperator; + +} From eae4087b3e9fcc960eeb9de8bef3fb3171292301 Mon Sep 17 00:00:00 2001 From: xupei Date: Tue, 15 Apr 2025 10:22:45 +0800 Subject: [PATCH 13/32] =?UTF-8?q?Stripe=E6=94=AF=E4=BB=98--=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E6=8E=A8=E5=B9=BF=E7=A0=81=E5=8A=9F=E8=83=BD=E5=8F=8A?= =?UTF-8?q?=E7=9B=B8=E5=BA=94=E4=BD=A3=E9=87=91=E8=AE=A1=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 0ba28588da4b8ec528ef894978c9cf0ffc27d5d5) --- .../com/ai/da/common/task/PaymentTask.java | 6 + .../ai/da/controller/StripeController.java | 35 +++ .../da/mapper/primary/PaymentInfoMapper.java | 2 + .../da/mapper/primary/entity/PaymentInfo.java | 2 + .../mapper/primary/entity/ProductCoupons.java | 5 +- .../com/ai/da/model/dto/CreateCouponDTO.java | 20 ++ .../ai/da/model/dto/ProductPurchaseDTO.java | 3 + .../com/ai/da/model/vo/CheckCouponsVO.java | 18 ++ .../com/ai/da/service/AffiliateService.java | 2 + .../com/ai/da/service/PaymentInfoService.java | 2 + .../java/com/ai/da/service/StripeService.java | 17 ++ .../da/service/impl/AffiliateServiceImpl.java | 61 ++++- .../service/impl/PaymentInfoServiceImpl.java | 34 ++- .../ai/da/service/impl/StripeServiceImpl.java | 220 +++++++++++++++++- .../mapper/primary/PaymentInfoMapper.xml | 14 +- src/main/resources/messages_en.properties | 6 + src/main/resources/messages_zh.properties | 7 + 17 files changed, 423 insertions(+), 31 deletions(-) create mode 100644 src/main/java/com/ai/da/model/dto/CreateCouponDTO.java create mode 100644 src/main/java/com/ai/da/model/vo/CheckCouponsVO.java diff --git a/src/main/java/com/ai/da/common/task/PaymentTask.java b/src/main/java/com/ai/da/common/task/PaymentTask.java index 7c148aa5..2fdf2e76 100644 --- a/src/main/java/com/ai/da/common/task/PaymentTask.java +++ b/src/main/java/com/ai/da/common/task/PaymentTask.java @@ -113,4 +113,10 @@ public class PaymentTask { } } +// @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes + public void calcCouponsCommission(){ + log.info("优惠券佣金计算定时器"); + affiliateService.calcCouponsCommission(); + } + } diff --git a/src/main/java/com/ai/da/controller/StripeController.java b/src/main/java/com/ai/da/controller/StripeController.java index 6eea73e8..416b3abe 100644 --- a/src/main/java/com/ai/da/controller/StripeController.java +++ b/src/main/java/com/ai/da/controller/StripeController.java @@ -4,8 +4,13 @@ import com.ai.da.common.response.Response; import com.ai.da.common.utils.DateUtil; import com.ai.da.common.utils.RedisUtil; import com.ai.da.common.utils.SendEmailUtil; +import com.ai.da.mapper.primary.entity.ProductCoupons; +import com.ai.da.model.dto.CreateCouponDTO; import com.ai.da.model.dto.ProductPurchaseDTO; +import com.ai.da.model.dto.QueryCouponsPageDTO; +import com.ai.da.model.vo.CheckCouponsVO; import com.ai.da.service.StripeService; +import com.baomidou.mybatisplus.core.metadata.IPage; import com.paypal.http.HttpResponse; import com.paypal.payments.Refund; import com.stripe.exception.StripeException; @@ -99,6 +104,36 @@ public class StripeController { stripeService.cancelSubscription(subscriptionId, reason); return Response.success("success"); } + + @ApiOperation("创建推广码") + @PostMapping("/createCoupon") + public Response createCoupon(@Valid @RequestBody CreateCouponDTO createCouponDTO){ + return Response.success(stripeService.createCoupon(createCouponDTO)); + } + + @ApiOperation("检查推广码") + @GetMapping("/checkCoupon") + public Response checkCoupon(@RequestParam String promotionCode, @RequestParam Long price){ + return Response.success(stripeService.checkProductCoupon(promotionCode, price)); + } + + @ApiOperation("获取所有推广码") + @PostMapping("/getAllCoupons") + public Response> getAllCoupons(@RequestBody QueryCouponsPageDTO queryCouponsPageDTO){ + return Response.success(stripeService.getAllCoupons(queryCouponsPageDTO)); + } + + @ApiOperation("检索优惠券") + @GetMapping("/retrieveCoupon") + public Response retrieveCoupon(@RequestParam String couponId){ + return Response.success(stripeService.retrieveCoupon(couponId)); + } + + @ApiOperation("检索推广码") + @GetMapping("/retrievePromotionCode") + public Response retrievePromotionCode(@RequestParam String retrievePromotionCode){ + return Response.success(stripeService.retrievePromotionCode(retrievePromotionCode)); + } /*@ApiOperation("临时 取消订阅") @GetMapping("/cancelSubscriptionTemp") public Response cancelSubscriptionTemp(@RequestParam String subscriptionId) { diff --git a/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java b/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java index 8841e85c..9384ad6b 100644 --- a/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java +++ b/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java @@ -29,4 +29,6 @@ public interface PaymentInfoMapper extends BaseMapper { List> getCountries(); int insertIgnore(@Param("paymentInfo")PaymentInfo paymentInfo); + + List selectPaidPaymentsByAccountAndPromotion(Long accountId, String promotionCode); } diff --git a/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java b/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java index 12470d20..a0b5dbfc 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java @@ -47,4 +47,6 @@ public class PaymentInfo extends BaseEntity{ private String country; private String city; + + private String promotionCode; } diff --git a/src/main/java/com/ai/da/mapper/primary/entity/ProductCoupons.java b/src/main/java/com/ai/da/mapper/primary/entity/ProductCoupons.java index 66c54b0c..07ebb3bb 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/ProductCoupons.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/ProductCoupons.java @@ -17,7 +17,7 @@ public class ProductCoupons extends BaseEntity{ // 对应的推广码 private String promotionCode; // 最大兑换次数 - private Integer maxRedemptions; + private Long maxRedemptions; // 优惠券的折扣 private float percentOff; // 佣金比例 @@ -38,11 +38,12 @@ public class ProductCoupons extends BaseEntity{ public ProductCoupons() { } - public ProductCoupons(String couponId, Long redeemBy, String promotionCodeId, String promotionCode, float percentOff, float commissionRate) { + public ProductCoupons(String couponId, Long redeemBy, String promotionCodeId, String promotionCode, Long maxRedemptions, float percentOff, float commissionRate) { this.couponId = couponId; this.redeemBy = redeemBy; this.promotionCodeId = promotionCodeId; this.promotionCode = promotionCode; + this.maxRedemptions = maxRedemptions; this.percentOff = percentOff; this.commissionRate = commissionRate; } diff --git a/src/main/java/com/ai/da/model/dto/CreateCouponDTO.java b/src/main/java/com/ai/da/model/dto/CreateCouponDTO.java new file mode 100644 index 00000000..5985baba --- /dev/null +++ b/src/main/java/com/ai/da/model/dto/CreateCouponDTO.java @@ -0,0 +1,20 @@ +package com.ai.da.model.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Data +public class CreateCouponDTO { + @ApiModelProperty("折扣率") + @NotNull(message = "Please set the percentOff") + private Float percentOff; + @ApiModelProperty("佣金比例") + @NotNull(message = "Please set the commissionRate.") + private Float commissionRate; + @ApiModelProperty("推广码到期时间 秒级时间戳") + private Long timestamp; + @ApiModelProperty("推广码最大使用次数") + private Long maxRedemptions; +} diff --git a/src/main/java/com/ai/da/model/dto/ProductPurchaseDTO.java b/src/main/java/com/ai/da/model/dto/ProductPurchaseDTO.java index 371439f9..b243a4a9 100644 --- a/src/main/java/com/ai/da/model/dto/ProductPurchaseDTO.java +++ b/src/main/java/com/ai/da/model/dto/ProductPurchaseDTO.java @@ -30,4 +30,7 @@ public class ProductPurchaseDTO { @ApiModelProperty("使用Alipay-HK时需要选择 ALIPAYHK || ALIPAYCN") private String wallet; + + @ApiModelProperty("优惠码") + private String promotionCode; } diff --git a/src/main/java/com/ai/da/model/vo/CheckCouponsVO.java b/src/main/java/com/ai/da/model/vo/CheckCouponsVO.java new file mode 100644 index 00000000..97b72d9c --- /dev/null +++ b/src/main/java/com/ai/da/model/vo/CheckCouponsVO.java @@ -0,0 +1,18 @@ +package com.ai.da.model.vo; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.NoArgsConstructor; + + +@Data +@NoArgsConstructor +public class CheckCouponsVO { + + @ApiModelProperty("expired || invalid || valid") + private String status; + + private String message; + + private Float discountedPrice; +} diff --git a/src/main/java/com/ai/da/service/AffiliateService.java b/src/main/java/com/ai/da/service/AffiliateService.java index fa03936f..a083e9d2 100644 --- a/src/main/java/com/ai/da/service/AffiliateService.java +++ b/src/main/java/com/ai/da/service/AffiliateService.java @@ -29,4 +29,6 @@ public interface AffiliateService extends IService { Affiliate getByAccountId(Long accountId); void commissionCalculation(Integer year, Integer month); + + void calcCouponsCommission(); } diff --git a/src/main/java/com/ai/da/service/PaymentInfoService.java b/src/main/java/com/ai/da/service/PaymentInfoService.java index 03db46a4..c0434e94 100644 --- a/src/main/java/com/ai/da/service/PaymentInfoService.java +++ b/src/main/java/com/ai/da/service/PaymentInfoService.java @@ -32,4 +32,6 @@ public interface PaymentInfoService extends IService { void updatePaymentStatusById(Long id, String status, String content); PageBaseResponse getPaymentInfo(QueryPageByTimeDTO queryPageByTimeDTO); + + List getPaymentInfoByPromCode(Long accountId, String promCode); } diff --git a/src/main/java/com/ai/da/service/StripeService.java b/src/main/java/com/ai/da/service/StripeService.java index 3b91fed1..97f94b17 100644 --- a/src/main/java/com/ai/da/service/StripeService.java +++ b/src/main/java/com/ai/da/service/StripeService.java @@ -1,7 +1,12 @@ package com.ai.da.service; +import com.ai.da.mapper.primary.entity.ProductCoupons; import com.ai.da.mapper.primary.entity.SubscriptionInfo; +import com.ai.da.model.dto.CreateCouponDTO; import com.ai.da.model.dto.ProductPurchaseDTO; +import com.ai.da.model.dto.QueryCouponsPageDTO; +import com.ai.da.model.vo.CheckCouponsVO; +import com.baomidou.mybatisplus.core.metadata.IPage; import com.stripe.exception.StripeException; import javax.servlet.http.HttpServletRequest; @@ -51,4 +56,16 @@ public interface StripeService { // Map getIp(HttpServletRequest request); String getStackTrace(Exception e, int maxLines); + + String createCoupon(CreateCouponDTO createCouponDTO); + + CheckCouponsVO checkProductCoupon(String promotionCode, Long price); + + ProductCoupons getProductCoupon(String promotionCode, String promotionCodeId); + + String retrieveCoupon(String couponId); + + String retrievePromotionCode(String promotionCode); + + IPage getAllCoupons(QueryCouponsPageDTO queryCouponsPageDTO); } diff --git a/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java b/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java index 509325a0..c88251ae 100644 --- a/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java @@ -10,6 +10,7 @@ import com.ai.da.common.utils.RedisUtil; import com.ai.da.common.utils.SendEmailUtil; import com.ai.da.mapper.primary.AffiliateIncomeMapper; import com.ai.da.mapper.primary.AffiliateMapper; +import com.ai.da.mapper.primary.ProductCouponsMapper; import com.ai.da.mapper.primary.SubscriptionInfoMapper; import com.ai.da.mapper.primary.entity.*; import com.ai.da.model.dto.AffiliateEmailParamsDTO; @@ -17,10 +18,7 @@ import com.ai.da.model.dto.AffiliateQueryDTO; import com.ai.da.model.vo.AffiliateInvitationDetailsVO; import com.ai.da.model.vo.AffiliateVO; import com.ai.da.model.vo.AuthPrincipalVo; -import com.ai.da.service.AccountService; -import com.ai.da.service.AffiliateService; -import com.ai.da.service.OrderInfoService; -import com.ai.da.service.PaymentInfoService; +import com.ai.da.service.*; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -34,9 +32,7 @@ import org.springframework.util.CollectionUtils; import javax.annotation.Resource; import java.math.BigDecimal; import java.time.LocalDateTime; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; import java.util.function.Function; @Service @@ -45,19 +41,18 @@ public class AffiliateServiceImpl extends ServiceImpl queryWrapper = new QueryWrapper<>(); + if (!StringUtil.isNullOrEmpty(lastTime)){ + queryWrapper.gt("create_time", lastTime) + .lt("create_time", currentTime) + .isNotNull("promotion_code"); + } + List paymentInfos = paymentInfoService.getBaseMapper().selectList(queryWrapper); + + // key:推广码, value:用户支付的金额 + HashMap codeAmount = new HashMap<>(); + if (!paymentInfos.isEmpty()){ + for (PaymentInfo paymentInfo : paymentInfos){ + String promotionCode = paymentInfo.getPromotionCode(); + Float sum = codeAmount.get(promotionCode); + if (sum == null || sum == 0.0f){ + codeAmount.put(promotionCode, paymentInfo.getPayerTotal()); + }else { + codeAmount.put(promotionCode, sum + paymentInfo.getPayerTotal()); + } + } + for (Map.Entry entry : codeAmount.entrySet()){ + String promotionCode = entry.getKey(); + ProductCoupons productCoupons = stripeService.getProductCoupon(promotionCode, null); + if (!Objects.isNull(productCoupons)){ + // 2、计算支付金额的总和,更新totalEarnings,commission,unpaidCommission + float sum = productCoupons.getTotalEarnings() + entry.getValue(); + productCoupons.setTotalEarnings(sum); + float commission = sum * productCoupons.getCommissionRate() / 100; + productCoupons.setCommission(commission); + productCoupons.setUnpaidCommission(commission - productCoupons.getPaidCommission()); + productCouponsMapper.updateById(productCoupons); + } + } + } + redisUtil.addToString(RedisUtil.PAYMENT_INFO_LAST_SCAN_TIME, currentTime); + } + } diff --git a/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java b/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java index b56ffbda..d85d3725 100644 --- a/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java @@ -6,6 +6,7 @@ import com.ai.da.common.response.PageBaseResponse; import com.ai.da.mapper.primary.PaymentInfoMapper; import com.ai.da.mapper.primary.entity.OrderInfo; import com.ai.da.mapper.primary.entity.PaymentInfo; +import com.ai.da.mapper.primary.entity.ProductCoupons; import com.ai.da.model.dto.AlipayHKCallbackDTO; import com.ai.da.model.dto.QueryPageByTimeDTO; import com.ai.da.model.vo.OrderListVO; @@ -232,20 +233,27 @@ public class PaymentInfoServiceImpl extends ServiceImpl getPaymentInfoByPromCode(Long accountId, String promCode){ + return baseMapper.selectPaidPaymentsByAccountAndPromotion(accountId, promCode); + } } diff --git a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java index b35b2ff6..d0446c0a 100644 --- a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java @@ -8,14 +8,20 @@ import com.ai.da.common.utils.DateUtil; import com.ai.da.common.utils.SendEmailUtil; import com.ai.da.mapper.primary.AccountMapper; import com.ai.da.mapper.primary.PaymentInfoMapper; +import com.ai.da.mapper.primary.ProductCouponsMapper; import com.ai.da.mapper.primary.SubscriptionInfoMapper; import com.ai.da.mapper.primary.entity.*; +import com.ai.da.model.dto.CreateCouponDTO; import com.ai.da.model.dto.ProductPurchaseDTO; +import com.ai.da.model.dto.QueryCouponsPageDTO; import com.ai.da.model.dto.SubscriptionEmailParamsDTO; +import com.ai.da.model.vo.CheckCouponsVO; import com.ai.da.service.*; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.google.gson.Gson; import com.stripe.Stripe; import com.stripe.exception.SignatureVerificationException; @@ -67,6 +73,8 @@ public class StripeServiceImpl implements StripeService { private SubscriptionInfoMapper subscriptionInfoMapper; @Resource private PaymentInfoMapper paymentInfoMapper; + @Resource + private ProductCouponsMapper productCouponsMapper; @Value("${stripe.private-key}") private String privateKey; @@ -85,6 +93,9 @@ public class StripeServiceImpl implements StripeService { public String pay(ProductPurchaseDTO productPurchaseDTO, HttpServletRequest request) { Stripe.apiKey = privateKey; + //创建支付信息得到url + // 一次性支付和周期扣款,需要区分mode: payment || subscription || setup + SessionCreateParams.Builder sessionBuilder = new SessionCreateParams.Builder(); ProductEnum productEnum; switch (productPurchaseDTO.getProductName()){ case "CreditsPurchase": @@ -105,6 +116,8 @@ public class StripeServiceImpl implements StripeService { default: throw new BusinessException("unknown subscription type"); } + // 只有订阅时才允许使用推广码优惠 +// sessionBuilder.setAllowPromotionCodes(true); break; default: throw new BusinessException("unknown product type"); @@ -131,12 +144,11 @@ public class StripeServiceImpl implements StripeService { String priceId = getPrice(productEnum.getPrice(), productId, payType, productPurchaseDTO.getSubscribeType()); // 获取或创建customer String customerId = getCustomer(account.getUserName(), account.getUserEmail()); + log.info("customerId:{}", customerId); // 获取自定义订单号 String orderId = orderInfo.getOrderNo(); - //创建支付信息得到url - // 一次性支付和周期扣款,需要区分mode: payment || subscription || setup - SessionCreateParams.Builder sessionBuilder = new SessionCreateParams.Builder(); + if (payType.equals("recurring")){ sessionBuilder.setMode(SessionCreateParams.Mode.SUBSCRIPTION); sessionBuilder.setSubscriptionData(SessionCreateParams.SubscriptionData.builder().setDescription("AiDA - " + orderId).build()); @@ -148,8 +160,6 @@ public class StripeServiceImpl implements StripeService { } sessionBuilder.setPaymentMethodConfiguration(paymentMethodConfigurationId); -// sessionBuilder.addPaymentMethodType(SessionCreateParams.PaymentMethodType.ALIPAY); -// sessionBuilder.addPaymentMethodType(SessionCreateParams.PaymentMethodType.CARD); sessionBuilder.setCustomer(customerId); sessionBuilder.setSuccessUrl(productPurchaseDTO.getReturnUrl());//可自定义成功页面 sessionBuilder.setLocale(account.getLanguage().equals("CHINESE_SIMPLIFIED") ? SessionCreateParams.Locale.ZH : SessionCreateParams.Locale.EN); @@ -160,6 +170,16 @@ public class StripeServiceImpl implements StripeService { .build()); sessionBuilder.putMetadata("orderId", orderId); //通过订单号关联用于检索支付信息(可选) + // 添加优惠券 + String promotionCode = productPurchaseDTO.getPromotionCode(); + if (!StringUtil.isNullOrEmpty(promotionCode)){ + ProductCoupons productCoupon = checkProductCoupon(promotionCode);; + if (productCoupon != null){ + sessionBuilder.addDiscount(SessionCreateParams.Discount.builder() + .setPromotionCode(productCoupon.getPromotionCodeId()).build()); + } + } + Session session = Session.create(sessionBuilder.build()); List paymentMethodTypes = session.getPaymentMethodTypes(); log.info("paymentMethodTypes: {}", paymentMethodTypes); @@ -171,6 +191,8 @@ public class StripeServiceImpl implements StripeService { // 更新order信息 orderInfoService.updateOrderNoById(orderInfo.getId(), orderId); return session.getUrl(); + } catch (BusinessException e) { + throw e; } catch (Exception e) { log.error("创建支付会话出现异常:", e); } @@ -1346,4 +1368,192 @@ public class StripeServiceImpl implements StripeService { } return sb.toString(); } + + + /* + * 优惠券实施: + * 1、由管理员创建优惠券,手动设置该优惠券对应的折扣 + * 2、用户在订阅时,手动输入优惠码 + * 3、使用stripe的字段 redeem_by 管理优惠券的有效期 + * 4、promotion code与 coupons需要绑定 + * 5、用户只能使用一次优惠券 + * + * 问题:对于一次付款和订阅,优惠码是否可以混用 + */ + public String createCoupon(CreateCouponDTO createCouponDTO){ + Stripe.apiKey = privateKey; + CouponCreateParams.Builder couponParams = CouponCreateParams.builder() + // 任何客户只能用一次这个优惠券 + .setDuration(CouponCreateParams.Duration.ONCE) + .setPercentOff(BigDecimal.valueOf(createCouponDTO.getPercentOff())); + if (Objects.nonNull(createCouponDTO.getTimestamp())){ + couponParams.setRedeemBy(createCouponDTO.getTimestamp()); + } + try { + // 1、创建优惠券 + Coupon coupon = Coupon.create(couponParams.build()); + // 2、创建一个推广码 + PromotionCode promotionCode = createPromotionCode(coupon.getId(), createCouponDTO.getMaxRedemptions()); + // 3、落库 + ProductCoupons productCoupons = new ProductCoupons(coupon.getId(), createCouponDTO.getTimestamp(), promotionCode.getId(), + promotionCode.getCode(), createCouponDTO.getMaxRedemptions(), createCouponDTO.getPercentOff(), createCouponDTO.getCommissionRate()); + productCoupons.setCreateTime(LocalDateTime.now()); + productCouponsMapper.insert(productCoupons); + + return promotionCode.getCode(); + } catch (StripeException e) { + throw new RuntimeException(e); + } + } + + public PromotionCode createPromotionCode(String couponId, Long maxRedemption){ + Stripe.apiKey = privateKey; + PromotionCodeCreateParams.Builder promotionCodeParams = PromotionCodeCreateParams.builder() + .setCoupon(couponId) + .setRestrictions(PromotionCodeCreateParams.Restrictions.builder().build()); + if (Objects.nonNull(maxRedemption)){ + promotionCodeParams.setMaxRedemptions(maxRedemption); + } + + try { + return PromotionCode.create(promotionCodeParams.build()); + } catch (StripeException e) { + throw new RuntimeException(e); + } + } + + public ProductCoupons checkProductCoupon(String promotionCode){ + Stripe.apiKey = privateKey; + Long accountId = UserContext.getUserHolder().getId(); + // 1、从数据库查找promotionCode对应的promotionCodeId + ProductCoupons productCoupons = productCouponsMapper.selectOne(new QueryWrapper().eq("promotion_code", promotionCode)); + if (Objects.nonNull(productCoupons)){ + // 2、查绑定的Coupons是否存在以及是否过期 + long epochSecondNow = Instant.now().getEpochSecond(); + Long redeemBy = productCoupons.getRedeemBy(); + if (redeemBy < epochSecondNow){ + throw new BusinessException("this.promotion.code.has.expired"); + } else { + // 判断该用户是否有成功使用过这个推广码 + List paymentInfoByPromCode = paymentInfoService.getPaymentInfoByPromCode(accountId, promotionCode); + if (!paymentInfoByPromCode.isEmpty()) { + // 已使用过推广码,状态无效 + if (paymentInfoByPromCode.size() > 1) { + log.error("用户[{}]多次成功使用优惠码[{}]", accountId, promotionCode); + } + log.info("用户[{}]已成功使用过优惠码[{}]", accountId, promotionCode); + throw new BusinessException("one.time.limit.per.customer"); + } + } + }else { + throw new BusinessException("this.promotion.code.is.invalid"); + } + return productCoupons; + } + + public CheckCouponsVO checkProductCoupon(String promotionCode, Long price){ + Stripe.apiKey = privateKey; + Long accountId = UserContext.getUserHolder().getId(); + CheckCouponsVO checkCouponsVO = new CheckCouponsVO(); + // 1、从数据库查找promotionCode对应的promotionCodeId + ProductCoupons productCoupons = productCouponsMapper.selectOne(new QueryWrapper().eq("promotion_code", promotionCode)); + if (Objects.nonNull(productCoupons)){ + // 2、查绑定的Coupons是否存在以及是否过期 + long epochSecondNow = Instant.now().getEpochSecond(); + Long redeemBy = productCoupons.getRedeemBy(); + if (redeemBy < epochSecondNow){ + String msg = BusinessException.getMessageFromResource("this.promotion.code.has.expired"); + checkCouponsVO.setMessage(msg); + checkCouponsVO.setStatus("expired"); + }else { + // 判断该用户是否有成功使用过这个推广码 + List paymentInfoByPromCode = paymentInfoService.getPaymentInfoByPromCode(accountId, promotionCode); + if (paymentInfoByPromCode.isEmpty()) { + // 未使用过推广码,状态有效 + checkCouponsVO.setStatus("valid"); + checkCouponsVO.setDiscountedPrice(price * (1 - productCoupons.getPercentOff() / 100)); + } else { + // 已使用过推广码,状态无效 + if (paymentInfoByPromCode.size() > 1) { + log.error("用户[{}]多次成功使用优惠码[{}]", accountId, promotionCode); + } + log.info("用户[{}]已成功使用过优惠码[{}]", accountId, promotionCode); + String msg = BusinessException.getMessageFromResource("one.time.limit.per.customer"); + checkCouponsVO.setMessage(msg); + checkCouponsVO.setStatus("invalid"); + } + } + }else { + String msg = BusinessException.getMessageFromResource("this.promotion.code.is.invalid"); + checkCouponsVO.setMessage(msg); + checkCouponsVO.setStatus("invalid"); + } + return checkCouponsVO; + } + + public ProductCoupons getProductCoupon(String promotionCode, String promotionCodeId){ + Stripe.apiKey = privateKey; + QueryWrapper qw = new QueryWrapper<>(); + // 1、从数据库查找promotionCode对应的promotionCodeId + if (!StringUtil.isNullOrEmpty(promotionCode)){ + qw.eq("promotion_code", promotionCode); + } + if (!StringUtil.isNullOrEmpty(promotionCodeId)){ + qw.eq("promotion_code_id", promotionCodeId); + } + return productCouponsMapper.selectOne(qw); + } + + public String retrieveCoupon(String couponId){ + Stripe.apiKey = privateKey; + try { + Coupon coupon = Coupon.retrieve(couponId); + log.info("retrieve的coupon: {}", coupon); + return JSON.toJSONString(coupon); + } catch (StripeException e) { + throw new RuntimeException(e); + } + } + + public String retrievePromotionCode(String promotionCode){ + Stripe.apiKey = privateKey; + try { + ProductCoupons productCoupon = getProductCoupon(promotionCode, null); + PromotionCode retrieve = PromotionCode.retrieve(productCoupon.getPromotionCodeId()); + log.info("retrieve的promotionCode: {}", retrieve); + return JSON.toJSONString(retrieve); + } catch (StripeException e) { + throw new RuntimeException(e); + } + } + + public IPage getAllCoupons(QueryCouponsPageDTO queryCouponsPageDTO){ + // 分页 + 按条件查询 + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (!StringUtil.isNullOrEmpty(queryCouponsPageDTO.getOrderById()) && queryCouponsPageDTO.getOrderById().equals("DESC")){ + queryWrapper.orderByDesc("id"); + } + if (!StringUtil.isNullOrEmpty(queryCouponsPageDTO.getPromotionCode())){ + queryWrapper.like("promotion_code", queryCouponsPageDTO.getPromotionCode()); + } + if (Objects.nonNull(queryCouponsPageDTO.getIsExpired())){ + long epochSecond = Instant.now().getEpochSecond(); + if (queryCouponsPageDTO.getIsExpired()){ + queryWrapper.lt("redeem_by", epochSecond); + }else { + queryWrapper.gt("redeem_by", epochSecond); + } + } + if (!StringUtil.isNullOrEmpty(queryCouponsPageDTO.getCooperator())){ + queryWrapper.like("cooperator", queryCouponsPageDTO.getCooperator()); + } + if (!StringUtil.isNullOrEmpty(queryCouponsPageDTO.getStartTime())){ + queryWrapper.gt("create_time", queryCouponsPageDTO.getStartTime()); + } + if (!StringUtil.isNullOrEmpty(queryCouponsPageDTO.getEndTime())){ + queryWrapper.lt("create_time", queryCouponsPageDTO.getEndTime()); + } + + return productCouponsMapper.selectPage(new Page<>(queryCouponsPageDTO.getPage(), queryCouponsPageDTO.getSize()), queryWrapper); + } } diff --git a/src/main/resources/mapper/primary/PaymentInfoMapper.xml b/src/main/resources/mapper/primary/PaymentInfoMapper.xml index ce03b6c4..c358a722 100644 --- a/src/main/resources/mapper/primary/PaymentInfoMapper.xml +++ b/src/main/resources/mapper/primary/PaymentInfoMapper.xml @@ -167,11 +167,21 @@ INSERT IGNORE INTO t_payment_info (order_no, transaction_id, payment_type, trade_state, payer_total, type, content, notified, payment_method, last4, hosted_invoice_url, - country, city, ip_address, create_time) + country, city, ip_address, promotion_code, create_time) VALUES (#{paymentInfo.orderNo}, #{paymentInfo.transactionId}, #{paymentInfo.paymentType}, #{paymentInfo.tradeState}, #{paymentInfo.payerTotal},#{paymentInfo.type}, #{paymentInfo.content}, #{paymentInfo.notified},#{paymentInfo.paymentMethod}, #{paymentInfo.last4},#{paymentInfo.hostedInvoiceUrl}, - #{paymentInfo.country},#{paymentInfo.city},#{paymentInfo.ipAddress},#{paymentInfo.createTime}); + #{paymentInfo.country},#{paymentInfo.city},#{paymentInfo.ipAddress},#{paymentInfo.promotionCode},#{paymentInfo.createTime}); + + + diff --git a/src/main/resources/messages_en.properties b/src/main/resources/messages_en.properties index a40e7125..e9f5174d 100644 --- a/src/main/resources/messages_en.properties +++ b/src/main/resources/messages_en.properties @@ -150,6 +150,12 @@ only.original.works.can.participate.in.the.event=Sorry, only original works can remaining.credits.insufficient=Your remaining credits are insufficient for this generation. Please recharge. you.haven't.subscribed.to.any.products.yet=You haven't subscribed to any products yet generate.result.below.standard=The quality of the generated images currently falls below standard. Please consider adjusting your prompt and trying again. +partial.design.failed=Partial design failed, Please try again later. +email.count.limit=Rate limit reached. Retry in 1 hour. +model.path.cannot.be.empty=Model path cannot be empty. +this.promotion.code.has.expired=This promotion code has expired. +this.promotion.code.is.invalid=This promotion code is invalid. +one.time.limit.per.customer=This code has already been redeemed. Promo codes are limited to one-time use per customer. # 可能会报异常 # Informative: diff --git a/src/main/resources/messages_zh.properties b/src/main/resources/messages_zh.properties index 803945e7..0ed76056 100644 --- a/src/main/resources/messages_zh.properties +++ b/src/main/resources/messages_zh.properties @@ -130,6 +130,7 @@ the.workspace.lastIndex.not.found=未找到工作区的lastIndex。 gender.cannot.be.empty=性别不能为空。 image.synthesis.failed=图像合成失败。 priority.cannot.be.repeated=优先级不能重复。 +image.modify.failed=图片修改失败,请稍后重试。 slogan.style.cannot.be.empty=标语风格文本不能为空。 slogan.image.cannot.be.empty=标语图片不能为空。 questionnaire.filled.out=您已填写过当前问卷。 @@ -145,6 +146,12 @@ only.original.works.can.participate.in.the.event=抱歉,只有原创作品能 remaining.credits.insufficient=您的剩余积分不够本次生成消耗,请充值 you.haven't.subscribed.to.any.products.yet=您还未订阅任何产品 generate.result.below.standard=当前生成的图像质量低于标准。请考虑调整您的提示词并再次尝试 +partial.design.failed=局部设计失败。请稍后重试。 +email.count.limit=您的账号触发邮件发送频率限制,请一小时后重试。 +model.path.cannot.be.empty=模特路径不能为空 +this.promotion.code.has.expired=该促销码已过期。 +this.promotion.code.is.invalid=该促销码无效。 +one.time.limit.per.customer=该码已兑换。每个促销码每位用户仅限使用一次。 # 可能会报异常 # Informative: From 1482bb6ab29e6e713cdf6000672237c7fe86433a Mon Sep 17 00:00:00 2001 From: xupei Date: Tue, 15 Apr 2025 15:58:22 +0800 Subject: [PATCH 14/32] =?UTF-8?q?Stripe=E6=8E=A8=E5=B9=BF=E7=A0=81=20?= =?UTF-8?q?=E9=83=A8=E5=88=86=E5=8A=9F=E8=83=BD=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 218d828e0d1b4967bf00aeb9ad5bc4df2fbae561) --- .../ai/da/controller/StripeController.java | 7 + .../mapper/primary/entity/ProductCoupons.java | 9 +- .../com/ai/da/model/dto/CreateCouponDTO.java | 4 + .../java/com/ai/da/service/StripeService.java | 2 + .../impl/CollectionElementServiceImpl.java | 2015 +++++++++-------- .../ai/da/service/impl/StripeServiceImpl.java | 28 +- 6 files changed, 1111 insertions(+), 954 deletions(-) diff --git a/src/main/java/com/ai/da/controller/StripeController.java b/src/main/java/com/ai/da/controller/StripeController.java index 416b3abe..261777ae 100644 --- a/src/main/java/com/ai/da/controller/StripeController.java +++ b/src/main/java/com/ai/da/controller/StripeController.java @@ -134,6 +134,13 @@ public class StripeController { public Response retrievePromotionCode(@RequestParam String retrievePromotionCode){ return Response.success(stripeService.retrievePromotionCode(retrievePromotionCode)); } + + @ApiOperation("更新推广码信息") + @GetMapping("/updatePromCodeInfo") + public Response updateCouponsInfo(@RequestParam Long id, @RequestParam(required = false) Long paidCommission, + @RequestParam(required = false) String cooperator, @RequestParam(required = false) String remark){ + return Response.success(stripeService.updateCouponsInfo(id, paidCommission, cooperator, remark)); + } /*@ApiOperation("临时 取消订阅") @GetMapping("/cancelSubscriptionTemp") public Response cancelSubscriptionTemp(@RequestParam String subscriptionId) { diff --git a/src/main/java/com/ai/da/mapper/primary/entity/ProductCoupons.java b/src/main/java/com/ai/da/mapper/primary/entity/ProductCoupons.java index 07ebb3bb..2ffe97fb 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/ProductCoupons.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/ProductCoupons.java @@ -3,10 +3,12 @@ package com.ai.da.mapper.primary.entity; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; @EqualsAndHashCode(callSuper = true) @Data @TableName("t_product_coupons") +@NoArgsConstructor public class ProductCoupons extends BaseEntity{ // 优惠券id private String couponId; @@ -35,16 +37,15 @@ public class ProductCoupons extends BaseEntity{ // 备注 private String remark; - public ProductCoupons() { - } - - public ProductCoupons(String couponId, Long redeemBy, String promotionCodeId, String promotionCode, Long maxRedemptions, float percentOff, float commissionRate) { + public ProductCoupons(String couponId, Long redeemBy, String promotionCodeId, String promotionCode, Long maxRedemptions, float percentOff, float commissionRate, String cooperator, String remark) { this.couponId = couponId; this.redeemBy = redeemBy; this.promotionCodeId = promotionCodeId; this.promotionCode = promotionCode; this.maxRedemptions = maxRedemptions; this.percentOff = percentOff; + this.cooperator = cooperator; + this.remark = remark; this.commissionRate = commissionRate; } } diff --git a/src/main/java/com/ai/da/model/dto/CreateCouponDTO.java b/src/main/java/com/ai/da/model/dto/CreateCouponDTO.java index 5985baba..311f7c67 100644 --- a/src/main/java/com/ai/da/model/dto/CreateCouponDTO.java +++ b/src/main/java/com/ai/da/model/dto/CreateCouponDTO.java @@ -17,4 +17,8 @@ public class CreateCouponDTO { private Long timestamp; @ApiModelProperty("推广码最大使用次数") private Long maxRedemptions; + @ApiModelProperty("合作者/机构名") + private String cooperator; + @ApiModelProperty("备注") + private String remark; } diff --git a/src/main/java/com/ai/da/service/StripeService.java b/src/main/java/com/ai/da/service/StripeService.java index 97f94b17..7769fa66 100644 --- a/src/main/java/com/ai/da/service/StripeService.java +++ b/src/main/java/com/ai/da/service/StripeService.java @@ -61,6 +61,8 @@ public interface StripeService { CheckCouponsVO checkProductCoupon(String promotionCode, Long price); + ProductCoupons updateCouponsInfo(Long id, Long paidCommission, String cooperator, String remark); + ProductCoupons getProductCoupon(String promotionCode, String promotionCodeId); String retrieveCoupon(String couponId); diff --git a/src/main/java/com/ai/da/service/impl/CollectionElementServiceImpl.java b/src/main/java/com/ai/da/service/impl/CollectionElementServiceImpl.java index 73f0ec99..8635bca0 100644 --- a/src/main/java/com/ai/da/service/impl/CollectionElementServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/CollectionElementServiceImpl.java @@ -1,949 +1,1066 @@ -package com.ai.da.service.impl; - -import cn.hutool.core.collection.CollectionUtil; -import com.ai.da.common.config.FileProperties; -import com.ai.da.common.config.exception.BusinessException; -import com.ai.da.common.context.UserContext; -import com.ai.da.common.enums.*; -import com.ai.da.common.response.ResultEnum; -import com.ai.da.common.utils.*; -import com.ai.da.mapper.primary.CollectionElementMapper; -import com.ai.da.mapper.primary.GenerateDetailMapper; -import com.ai.da.mapper.primary.entity.*; -import com.ai.da.model.dto.*; -import com.ai.da.model.enums.ModelType; -import com.ai.da.model.enums.Sex; -import com.ai.da.model.enums.StyleEnum; -import com.ai.da.model.vo.*; -import com.ai.da.python.PythonService; -import com.ai.da.python.vo.DesignPythonItem; -import com.ai.da.service.*; -import com.alibaba.fastjson.JSON; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.google.common.collect.Lists; -import io.netty.util.internal.StringUtil; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.CollectionUtils; -import org.springframework.util.StringUtils; - -import javax.annotation.Resource; -import java.io.File; -import java.math.BigDecimal; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.util.*; -import java.util.stream.Collectors; - -/** - * 服务实现类 - * - * @author yanglei - * @since 2022-09-30 - */ -@Slf4j -@Service -public class CollectionElementServiceImpl extends ServiceImpl implements CollectionElementService { - @Resource - private CollectionElementMapper collectionElementMapper; - @Resource - private FileProperties fileProperties; - @Resource - private PanToneService panToneService; - @Resource - private PythonService pythonService; - @Resource - private LibraryService libraryService; - @Resource - private SysFileService sysFileService; - @Resource - private GenerateService generateService; - @Resource - private GenerateDetailMapper generateDetailMapper; - @Resource - private LibraryModelPointService libraryModelPointService; - @Resource - private TCollectionElementRelationService tCollectionElementRelationService; - @Resource - private MinioUtil minioUtil; - - @Value("${minio.bucketName.collectionElement}") - private String collectionElement; - @Value("${minio.bucketName.gradient}") - private String gradientBucketName; - @Resource - private RedisUtil redisUtil; - -// @Resource -// private RedisUtil redisUtil; - - @Transactional(rollbackFor = Exception.class) - @Override - public CollectionElementVO upload(CollectionElementUploadDTO uploadDTO) { - long start = System.currentTimeMillis(); - //用户信息 - AuthPrincipalVo userInfo = UserContext.getUserHolder(); - CollectionLevel1TypeEnum level1TypeEnum = CollectionLevel1TypeEnum.uploadOf(uploadDTO.getLevel1Type()); - if (Objects.isNull(level1TypeEnum)) { - throw new BusinessException("unknown.parameter.level1Type"); - } - String objectName = userInfo.getId() + "/" + level1TypeEnum.getRealName(); - String path = minioUtil.upload(collectionElement, objectName, uploadDTO.getFile()); - - String level2Type = null; - if (uploadDTO.getLevel1Type().equals(CollectionLevel1TypeEnum.SKETCH_BOARD.getRealName())){ - if (StringUtil.isNullOrEmpty(uploadDTO.getGender())) { - throw new BusinessException("gender.cannot.be.empty"); - } - level2Type = pythonService.getClothCategory(path,uploadDTO.getGender()); - } - - //保存element元素 - CollectionElement collectionElement = resolveData(uploadDTO, userInfo, path, level2Type); - saveOne(collectionElement); -// if (!StringUtils.isEmpty(uploadDTO.getMoodboardPosition())) { -// redisUtil.saveMoodboardPosition(collectionElement.getId(), uploadDTO.getMoodboardPosition()); -// } - CollectionElementVO collectionElementVO = CopyUtil.copyObject(collectionElement, CollectionElementVO.class); - collectionElementVO.setMinIOPath(collectionElementVO.getUrl()); - collectionElementVO.setUrl(minioUtil.getPreSignedUrl(collectionElementVO.getUrl(), 24 * 60)); - collectionElementVO.setDesignType(DesignTypeEnum.COLLECTION.getRealName()); - - long end = System.currentTimeMillis(); - double floor = Math.floor((double) (end - start) / 1000); - log.info("本次图片上传耗时:{} 毫秒", end - start); - Long incrementCount = redisUtil.getIncrementCount(RedisUtil.UPLOAD_TIMEOUT_REMINDER_COUNTER); - if (floor > 5 && incrementCount < 3) { - // 邮件通知 一天最多通知3次 - log.info("上传超过5秒,发送邮件通知"); - SendEmailUtil.uploadTimeoutReminder(userInfo.getUsername(), String.valueOf(((end - start) / 1000))); - redisUtil.increaseCount(RedisUtil.UPLOAD_TIMEOUT_REMINDER_COUNTER); - } - return collectionElementVO; - } - - private String calculateFileUrl(CollectionLevel1TypeEnum level1TypeEnum, Long userId) { - String rootPath = fileProperties.getSys().getPath(); - String day = DateUtil.dateToStr(new Date(), DateUtil.YYYYMM); - return rootPath + day + "/" + "userFile" + "/collection" - + "/" + level1TypeEnum.getRealName() + "/" + userId + "/" + UUID.randomUUID().toString(); - } - - private CollectionElement resolveData(CollectionElementUploadDTO uploadDTO, AuthPrincipalVo userInfo, File file) { - CollectionElement element = CopyUtil.copyObject(uploadDTO, CollectionElement.class); - element.setAccountId(userInfo.getId()); - element.setCollectionId(0L); - element.setHasPin((byte) 0); - String pictureCollectonName = file.getName(); - //获取图片后缀 - String suffix = pictureCollectonName.substring(pictureCollectonName.lastIndexOf(".")); - //获取图片前缀 - String prefix = pictureCollectonName.substring(0, pictureCollectonName.lastIndexOf(".")); - element.setName(DateUtil.dateToStr(new Date(), DateUtil.YYYY_MM_DD)); - element.setUrl(file.getAbsolutePath()); - //按时区计算 - element.setCreateDate(DateUtil.getByTimeZone(uploadDTO.getTimeZone())); - String linuxDomain = fileProperties.getLinuxDomain(); - if (!StringUtils.isEmpty(linuxDomain)) { - //linux 系统 - String oldPath = fileProperties.getSys().getPath(); - element.setUrl(file.getAbsolutePath().replace(oldPath, linuxDomain)); - } - return element; - } - - private CollectionElement resolveData(CollectionElementUploadDTO uploadDTO, AuthPrincipalVo userInfo, String path, String level2Type) { - CollectionElement element = CopyUtil.copyObject(uploadDTO, CollectionElement.class); - element.setAccountId(userInfo.getId()); - element.setCollectionId(0L); - element.setHasPin((byte) 0); -// String pictureCollectonName = fileName; -// //获取图片后缀 -// String suffix = pictureCollectonName.substring(pictureCollectonName.lastIndexOf(".")); -// //获取图片前缀 -// String prefix = pictureCollectonName.substring(0,pictureCollectonName.lastIndexOf(".")); - String originalFilename = uploadDTO.getFile().getOriginalFilename(); - if (originalFilename != null && originalFilename.contains(".")) { - // 如果文件名包含点号,则去除最后一个点及其后面的内容 - int lastDotIndex = originalFilename.lastIndexOf("."); - if (lastDotIndex != -1) { - originalFilename = originalFilename.substring(0, lastDotIndex); - } - } - element.setName(originalFilename); - element.setUrl(path); - //按时区计算 - element.setCreateDate(DateUtil.getByTimeZone(uploadDTO.getTimeZone())); - element.setLevel2Type(level2Type); -// String linuxDomain = fileProperties.getLinuxDomain(); -// if (!StringUtils.isEmpty(linuxDomain)) { -// //linux 系统 -// String oldPath = fileProperties.getSys().getPath(); -// element.setUrl(file.getAbsolutePath().replace(oldPath, linuxDomain)); -// } - return element; - } - - @Override - public void delete(Long id) { - CollectionElement collectionElement = selectById(id); - if (Objects.isNull(collectionElement)) { - throw new BusinessException("collectionElement.not.found"); - } - minioUtil.deleteObject(collectionElement.getUrl()); - collectionElementMapper.deleteById(id); -// if (!FileUtil.delete(collectionElement.getUrl())) { -// throw new BusinessException("file deletion failed! "); -// } - } - - @Override - public void batchDelete(List ids) { - if (CollectionUtils.isEmpty(ids)) { - return; - } -// QueryWrapper queryWrapper = new QueryWrapper<>(); -// queryWrapper.in("id", ids); -// CollectionElement collectionElement = new CollectionElement(); -// collectionElement.setCollectionId(0L); - collectionElementMapper.deleteBatchIds(ids); - } - - /** 该方法已不再使用 */ - @Deprecated - @Override - public GenerateCollectionItemVO generatePrint(CollectionGeneratePrintDTO generatePrintDTO) { - Long userId = UserContext.getUserHolder().getId(); - String url1 = null; - String url2 = null; - CollectionElement element1 = selectById(generatePrintDTO.getSelect1Id()); - if (Objects.isNull(element1)) { - Library library1 = libraryService.getById(generatePrintDTO.getSelect1Id()); - if (Objects.isNull(library1)) { - throw new BusinessException("select1.file.does.not.exist"); - } - url1 = library1.getUrl(); - } else { - url1 = element1.getUrl(); - } - CollectionElement element2 = selectById(generatePrintDTO.getSelect2Id()); - if (Objects.isNull(element2)) { - Library library2 = libraryService.getById(generatePrintDTO.getSelect2Id()); - if (Objects.isNull(library2)) { - throw new BusinessException("select2.file.does.not.exist"); - } - url2 = library2.getUrl(); - } else { - url2 = element2.getUrl(); - } - List printPath = Arrays.asList(url1, url2); - //调取python 接口 - String generateUrl = pythonService.generatePrint(printPath,userId); - if (StringUtils.isEmpty(generateUrl)) { - throw new BusinessException("generate.interface.exception"); - } - - // 保存合成信息到generate表 - Generate generate = setGenerate(userId, generatePrintDTO.getTimeZone()); - generateService.save(generate); - - // 保存合成后的信息到generateDetail - GenerateDetail generateDetail = setGenerateDetail(generate.getId(), generateUrl, generatePrintDTO.getTimeZone()); - generateDetailMapper.insert(generateDetail); - -// CollectionElement element = resolveData(generateUrl, generatePrintDTO.getTimeZone(), userId); -// if (!this.save(element)) { -// throw new BusinessException("save.collectionElement.failed"); -// } -// CollectionGeneratePrintVO collectionGeneratePrint = CopyUtil.copyObject(element, CollectionGeneratePrintVO.class); -// collectionGeneratePrint.setUrl(minioUtil.getPresignedUrl(generateUrl, 24 * 60)); -// collectionGeneratePrint.setDesignType(DesignTypeEnum.COLLECTION.getRealName()); -// return collectionGeneratePrint; - return new GenerateCollectionItemVO(generateDetail.getId(), - minioUtil.getPreSignedUrl(generateUrl, 24 * 60), - generateDetail.getIsLike().equals((byte) 0) ? Boolean.FALSE : Boolean.TRUE); - } - - @Override - public Boolean savePrint(CollectionSavePrintDTO savePrintDTO) { - //用户信息 - List elements = listByIds(savePrintDTO.getPrintId()); - if (CollectionUtils.isEmpty(elements)) { - throw new BusinessException("collectionElements.not.found"); - } - return saveLibraryByCollectionElement(elements, savePrintDTO.getTimeZone()); - } - - @Override - public Boolean saveLibraryByCollectionElement(List elements, String timeZone) { - if (CollectionUtils.isEmpty(elements)) { - return Boolean.TRUE; - } - //获取已存在相同的library - List md5List = elements.stream().map(CollectionElement::getMd5).collect(Collectors.toList()); - List existsLibrarys = libraryService.getByMD5List(md5List); - if (!CollectionUtils.isEmpty(existsLibrarys)) { - //去重 - List existsMd5Lists = existsLibrarys.stream().map(Library::getMd5).collect(Collectors.toList()); - elements = elements.stream().filter(element -> !existsMd5Lists.contains(element.getMd5())).collect(Collectors.toList()); - } - if (CollectionUtils.isEmpty(elements)) { - //都是重复的 - return Boolean.TRUE; - } - String name = DateUtil.dateToStr(new Date(), DateUtil.YYYY_MM_DD); - List libraryList = CopyUtil.copyList(elements, Library.class, (o, d) -> { - d.setCreateDate(DateUtil.getByTimeZone(timeZone)); - d.setName(name); - d.setId(null); - }); - if (!libraryService.saveBatch(libraryList)) { - throw new BusinessException("batch.save.libraryList.failed"); - } - return Boolean.TRUE; - } - - @Override - public Boolean saveLibraryByCollectionElement(List elements, String timeZone, String modelSex) { - if (CollectionUtils.isEmpty(elements)) { - return Boolean.TRUE; - } - //获取已存在相同的library - List md5List = elements.stream().map(CollectionElement::getMd5).collect(Collectors.toList()); - List existsLibrarys = libraryService.getByMD5List(md5List); - if (!CollectionUtils.isEmpty(existsLibrarys)) { - //去重 - List existsMd5Lists = existsLibrarys.stream().map(Library::getMd5).collect(Collectors.toList()); - elements = elements.stream().filter(element -> !existsMd5Lists.contains(element.getMd5())).collect(Collectors.toList()); - } - if (CollectionUtils.isEmpty(elements)) { - //都是重复的 - return Boolean.TRUE; - } - String name = DateUtil.dateToStr(new Date(), DateUtil.YYYY_MM_DD); - List libraryList = CopyUtil.copyList(elements, Library.class, (o, d) -> { - if (d.getLevel1Type().equals(LibraryLevel1TypeEnum.SKETCH_BOARD.getRealName())) { - d.setLevel3Type(modelSex); -// try { -// libraryService.processSketchBoards(d.getUrl(), d.getLevel2Type()); -// }catch (Exception e) { -// // TODO:暂不处理 -// } - } - d.setCreateDate(DateUtil.getByTimeZone(timeZone)); - d.setName(name); - d.setId(null); - }); - if (!libraryService.saveBatch(libraryList)) { - throw new BusinessException("batch.save.libraryList.failed"); - } - return Boolean.TRUE; - } - - private CollectionElement resolveData(String path, String timeZone, Long userId){ -// File file = new File(path); - - String name = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf(".")); - CollectionElement element = new CollectionElement(); - element.setAccountId(userId); - element.setCollectionId(0L); - element.setName(name); - element.setLevel1Type(CollectionLevel1TypeEnum.PRINT_BOARD.getRealName()); - element.setUrl(path); - element.setHasPin((byte) 0); - try { - element.setMd5(MD5Utils.encryptFile(minioUtil.download(path))); - }catch (Exception e){ - throw new RuntimeException(e); - } - /* catch (MinioException | IOException e) { - throw new RuntimeException(e); - }*/ - - //按时区计算 - element.setCreateDate(DateUtil.getByTimeZone(timeZone)); - return element; - } - - @Override - public ValidateElementVO validateElement(DesignCollectionDTO designDTO) { - ValidateElementVO elementVO = CopyUtil.copyObject(designDTO, ValidateElementVO.class); - List colorBoards = elementVO.getColorBoards(); - for (CollectionColorDTO colorBoard : colorBoards) { - if (Objects.nonNull(colorBoard.getGradient())) { - String colorImg = colorBoard.getGradient().getColorImg(); - String[] parts = colorImg.split(","); - String imageType = parts[0].split("/")[1].split(";")[0]; - String base64Data = parts[1]; - String gradientMinioUrl = minioUtil.uploadImageFromBase64(gradientBucketName, base64Data, imageType); - colorBoard.setGradientMinioUrl(gradientMinioUrl); - colorBoard.getGradient().setColorImg(null); - colorBoard.setGradientString(JSON.toJSONString(colorBoard.getGradient())); - } - } - elementVO.setColorBoards(colorBoards); - List usedElementIds = elementVO.getUsedElementIds(); - List libraryCollectionElements = elementVO.getLibraryCollectionElements(); - List generateCollectionElements = elementVO.getGenerateCollectionElements(); - //校验moodboard - if (CollectionUtil.isNotEmpty(designDTO.getMoodBoards())) { - //校验designType - validateDesignType(designDTO.getMoodBoards(), "moodBoards"); - List moodBoardIds = designDTO.getMoodBoards().stream() - .filter(f -> f.getDesignType().equals(DesignTypeEnum.COLLECTION.getRealName())) - .map(DesignCollectionElementDTO::getId) - .collect(Collectors.toList()); - if (!CollectionUtils.isEmpty(moodBoardIds)) { - List MoodBoardElements = collectionElementMapper.selectBatchIds(moodBoardIds); - if (CollectionUtil.isEmpty(MoodBoardElements) || MoodBoardElements.size() != moodBoardIds.size()) { - throw new BusinessException("get.moodBoards.data.is.mismatch"); - } - elementVO.setMoodBoardElements(MoodBoardElements); - usedElementIds.addAll(moodBoardIds); - } - //library - List libraryIds = designDTO.getMoodBoards().stream() - .filter(f -> f.getDesignType().equals(DesignTypeEnum.LIBRARY.getRealName())) - .map(DesignCollectionElementDTO::getId) - .collect(Collectors.toList()); - if (!CollectionUtils.isEmpty(libraryIds)) { - List librarys = libraryService.getByIds(libraryIds); - //不校验了防止用户在library删除 对应不上 - if (CollectionUtil.isNotEmpty(librarys)) { - libraryCollectionElements.addAll(covertLibrarysToCollections(librarys, null)); - } - } - // generate - List generateIds = designDTO.getMoodBoards().stream() - .filter(o -> o.getDesignType().equals((DesignTypeEnum.GENERATE.getRealName()))) - .map(DesignCollectionElementDTO::getId) - .collect((Collectors.toList())); - if (CollectionUtil.isNotEmpty(generateIds)) { - List generateDetailList = generateDetailMapper.selectBatchIds(generateIds); - if (CollectionUtil.isNotEmpty(generateDetailList)) { - generateCollectionElements.addAll(covertGeneratesToCollections(generateDetailList, null)); - } - } - } - if (CollectionUtil.isNotEmpty(designDTO.getPrintBoards())) { - //校验designType - validateDesignType(CopyUtil.copyList(designDTO.getPrintBoards(), DesignCollectionElementDTO.class), "printBoards"); - List printBoardIds = designDTO.getPrintBoards().stream() - .filter(f -> f.getDesignType().equals(DesignTypeEnum.COLLECTION.getRealName())) - .map(DesignCollectionPrintElementDTO::getId) - .collect(Collectors.toList()); - if (!CollectionUtils.isEmpty(printBoardIds)) { - //校验printboard - List printBoardElements = collectionElementMapper.selectBatchIds(printBoardIds); - if (CollectionUtil.isEmpty(printBoardElements) || printBoardElements.size() != printBoardIds.size()) { - throw new BusinessException("get.printBoards.data.is.mismatch"); - } - elementVO.setPrintBoardElements(printBoardElements); - usedElementIds.addAll(printBoardIds); - } - //library - List libraryIds = designDTO.getPrintBoards().stream() - .filter(f -> f.getDesignType().equals(DesignTypeEnum.LIBRARY.getRealName())) - .map(DesignCollectionPrintElementDTO::getId) - .collect(Collectors.toList()); - if (!CollectionUtils.isEmpty(libraryIds)) { - List librarys = libraryService.getByIds(libraryIds); - //不校验了防止用户在library删除 对应不上 - if (CollectionUtil.isNotEmpty(librarys)) { - Map idToMap = designDTO.getPrintBoards() - .stream() - .collect(Collectors.toMap(DesignCollectionPrintElementDTO::getId, v -> v)); - libraryCollectionElements.addAll(covertLibrarysToPrintCollections(librarys, idToMap)); - } - } - // generate - List generateIds = designDTO.getPrintBoards().stream() - .filter(o -> o.getDesignType().equals((DesignTypeEnum.GENERATE.getRealName()))) - .map(DesignCollectionPrintElementDTO::getId) - .collect((Collectors.toList())); - if (CollectionUtil.isNotEmpty(generateIds)) { - List generateDetailList = generateDetailMapper.selectBatchIds(generateIds); - if (CollectionUtil.isNotEmpty(generateDetailList)) { - Map idToMap = designDTO.getPrintBoards() - .stream() - .collect(Collectors.toMap(DesignCollectionPrintElementDTO::getId, v -> v)); - generateCollectionElements.addAll(covertGeneratesToPrintCollections(generateDetailList, idToMap)); - } - } - } - if (CollectionUtil.isNotEmpty(designDTO.getSketchBoards())) { - //校验PIN是否满足 上衣或者下衣必须不超过8 - long topNum = 0; - long bottomNum = 0; - long outerwearNum = 0; - if (designDTO.getModelSex().equals(Sex.FEMALE.getValue())) { - topNum= designDTO.getSketchBoards().stream() - .filter(skecth -> skecth.getIsPin() == 1 - && DesignPythonItem.DRESS_BLOUSE.contains(skecth.getLevel2Type())).count(); - bottomNum = designDTO.getSketchBoards().stream() - .filter(skecth -> skecth.getIsPin() == 1 - && DesignPythonItem.SKIRT_TROUSERS.contains(skecth.getLevel2Type())).count(); - }else if (designDTO.getModelSex().equals(Sex.MALE.getValue())) { - topNum= designDTO.getSketchBoards().stream() - .filter(skecth -> skecth.getIsPin() == 1 - && DesignPythonItem.TOPS.contains(skecth.getLevel2Type())).count(); - bottomNum = designDTO.getSketchBoards().stream() - .filter(skecth -> skecth.getIsPin() == 1 - && DesignPythonItem.BOTTOMS.contains(skecth.getLevel2Type())).count(); - } - outerwearNum = designDTO.getSketchBoards().stream() - .filter(skecth -> skecth.getIsPin() == 1 - && DesignPythonItem.OUTWEAR.contains(skecth.getLevel2Type())).count(); - if (topNum > 8 || bottomNum > 8 || outerwearNum > 8) { - throw new BusinessException("the.number.of.PIN.top.or.bottom.or.outerwear.sketchBoard.cannot.be.more.than.8", ResultEnum.PROMPT.getCode()); - } - //校验designType - Boolean result = designDTO.getSketchBoards().stream() - .filter(mood -> StringUtils.isEmpty(mood.getDesignType())) - .findFirst().isPresent(); - if (result) { - throw new BusinessException("sketchBoards.designType.cannot.be.empty"); - } - - List sketchBoardIds = designDTO.getSketchBoards().stream() - .filter(f -> f.getDesignType().equals(DesignTypeEnum.COLLECTION.getRealName())) - .map(CollectionSketchDTO::getSketchBoardId) - .collect(Collectors.toList()); - if (!CollectionUtils.isEmpty(sketchBoardIds)) { - //校验sketchBoard - List sketchBoardElements = collectionElementMapper.selectBatchIds(sketchBoardIds); - if (CollectionUtil.isEmpty(sketchBoardElements) || sketchBoardElements.size() != sketchBoardIds.size()) { - throw new BusinessException("get.sketchBoards.data.is.mismatch"); - } - elementVO.setSketchBoardElements(sketchBoardElements); - usedElementIds.addAll(sketchBoardIds); - } - //library - List libraryIds = designDTO.getSketchBoards().stream() - .filter(f -> f.getDesignType().equals(DesignTypeEnum.LIBRARY.getRealName())) - .map(CollectionSketchDTO::getSketchBoardId) - .collect(Collectors.toList()); - if (!CollectionUtils.isEmpty(libraryIds)) { - List librarys = libraryService.getByIds(libraryIds); - //不校验了防止用户在library删除 对应不上 - if (CollectionUtil.isNotEmpty(librarys)) { - Map idToMap = designDTO.getSketchBoards() - .stream() - .collect(Collectors.toMap(CollectionSketchDTO::getSketchBoardId, v -> v)); - libraryCollectionElements.addAll(covertLibrarysToCollections(librarys, idToMap)); - } - } - // generate - List generateIds = designDTO.getSketchBoards().stream() - .filter(o -> o.getDesignType().equals((DesignTypeEnum.GENERATE.getRealName()))) - .map(CollectionSketchDTO::getSketchBoardId) - .collect((Collectors.toList())); - if (CollectionUtil.isNotEmpty(generateIds)) { - List generateDetailList = generateDetailMapper.selectBatchIds(generateIds); - if (CollectionUtil.isNotEmpty(generateDetailList)) { - Map idToMap = designDTO.getSketchBoards() - .stream() - .collect(Collectors.toMap(CollectionSketchDTO::getSketchBoardId, v -> v)); - generateCollectionElements.addAll(covertGeneratesToCollections(generateDetailList, idToMap)); - } - } - } - //校验marketingSketch - // 2023.12版本去掉了这个入参 -// if (CollectionUtil.isNotEmpty(designDTO.getMarketingSketchs())) { -// //校验designType -// validateDesignType(designDTO.getMarketingSketchs(),"marketingSketchs"); -// List printBoardIds = designDTO.getMarketingSketchs().stream() -// .filter(f ->f.getDesignType().equals(DesignTypeEnum.COLLECTION.getRealName())) -// .map(DesignCollectionElementDTO::getId) -// .collect(Collectors.toList()); -// if(!CollectionUtils.isEmpty(printBoardIds)){ -// List marketingSketchElements = collectionElementMapper.selectBatchIds(printBoardIds); -// Assert.isTrue(CollectionUtil.isNotEmpty(marketingSketchElements) -// && marketingSketchElements.size() == printBoardIds.size(), "get marketingSketch data is mismatch"); -// elementVO.setMarketingSketchElements(marketingSketchElements); -// usedElementIds.addAll(printBoardIds); -// } -// //library -// List libraryIds = designDTO.getMarketingSketchs().stream() -// .filter(f ->f.getDesignType().equals(DesignTypeEnum.LIBRARY.getRealName())) -// .map(DesignCollectionElementDTO::getId) -// .collect(Collectors.toList()); -// if(!CollectionUtils.isEmpty(libraryIds)){ -// List librarys = libraryService.getByIds(libraryIds); -// //不校验了防止用户在library删除 对应不上 -// if(CollectionUtil.isNotEmpty(librarys)){ -// libraryCollectionElements.addAll(covertLibrarysToCollections(librarys,null)); -// } -// } -// } - //校验控制生成类型 - SingleOverallEnum singleOverall = SingleOverallEnum.of(designDTO.getSingleOverall()); - if (Objects.isNull(singleOverall)) { - throw new BusinessException("unknown.parameter.singleOverall"); - } - if (SingleOverallEnum.SINGLE.equals(singleOverall)) { - SwitchCategoryEnum switchCategory = SwitchCategoryEnum.of(designDTO.getSwitchCategory()); - if (Objects.isNull(switchCategory)) { - throw new BusinessException("unknown.parameter.switchCategory"); - } - } - // 校验模特 - if (designDTO.getModelType().equals(ModelType.LIBRARY.getValue())) { - Library byId = libraryService.getById(designDTO.getTemplateId()); - LibraryModelPoint modelPoint = libraryModelPointService.getByRelationId(byId.getId(), designDTO.getModelType()); - elementVO.setDesignLibraryModelPoint(calculateTemplatePointTemplate(modelPoint, byId.getHigh(), byId.getWidth(), byId.getUrl())); - } else if (designDTO.getModelType().equals(ModelType.SYSTEM.getValue())) { - SysFileVO byId = sysFileService.getById(designDTO.getTemplateId()); - if (!StringUtils.isEmpty(byId.getLevel3Type()) && byId.getLevel2Type().equals("Female")) { - elementVO.setStyle(byId.getLevel3Type()); - } - LibraryModelPoint modelPoint = libraryModelPointService.getByRelationId(byId.getId(), designDTO.getModelType()); - elementVO.setDesignLibraryModelPoint(calculateTemplatePointTemplate(modelPoint, 700, 320, byId.getUrl())); - } - elementVO.setModelSex(designDTO.getModelSex()); - elementVO.setRequestIdList(designDTO.getRequestIdList()); - if (null != designDTO.getDesignNum()) { - elementVO.setDesignNum(designDTO.getDesignNum()); - }else { - elementVO.setDesignNum(8); - } - return elementVO; - } - - @Override - public DesignLibraryModelPointVO calculateTemplatePoint(LibraryModelPoint modelPoint, Integer high, Integer width, String templateUrl) { - DesignLibraryModelPointVO libraryModelPoint = new DesignLibraryModelPointVO(); - libraryModelPoint.setHandLeft(calculateTemplatePointOne(modelPoint.getHandLeft(), high, width)); - libraryModelPoint.setHandRight(calculateTemplatePointOne(modelPoint.getHandRight(), high, width)); - libraryModelPoint.setShoulderLeft(calculateTemplatePointOne(modelPoint.getShoulderLeft(), high, width)); - libraryModelPoint.setShoulderRight(calculateTemplatePointOne(modelPoint.getShoulderRight(), high, width)); - libraryModelPoint.setWaistbandLeft(calculateTemplatePointOne(modelPoint.getWaistbandLeft(), high, width)); - libraryModelPoint.setWaistbandRight(calculateTemplatePointOne(modelPoint.getWaistbandRight(), high, width)); - libraryModelPoint.setTemplateUrl(templateUrl); - return libraryModelPoint; - } - - @Override - public DesignLibraryModelPointVO calculateTemplatePointTemplate(LibraryModelPoint modelPoint, Integer high, Integer width, String templateUrl) { - DesignLibraryModelPointVO libraryModelPoint = new DesignLibraryModelPointVO(); -// LibraryModelPoint template = libraryModelPointService.getById(96L); -// libraryModelPoint.setHandLeft(calculateTemplatePointOne(template.getHandLeft(),752,564)); -// libraryModelPoint.setHandRight(calculateTemplatePointOne(template.getHandRight(),752,564)); -// libraryModelPoint.setShoulderLeft(calculateTemplatePointOne(template.getShoulderLeft(),752,564)); -// libraryModelPoint.setShoulderRight(calculateTemplatePointOne(template.getShoulderRight(),752,564)); -// libraryModelPoint.setWaistbandLeft(calculateTemplatePointOne(template.getWaistbandLeft(),752,564)); -// libraryModelPoint.setWaistbandRight(calculateTemplatePointOne(template.getWaistbandRight(),752,564)); -// libraryModelPoint.setTemplateUrl("aida-mannequins/model_1693218345.2714432.png"); - libraryModelPoint.setHandLeft(calculateTemplatePointOne(modelPoint.getHandLeft(), high, width)); - libraryModelPoint.setHandRight(calculateTemplatePointOne(modelPoint.getHandRight(), high, width)); - libraryModelPoint.setShoulderLeft(calculateTemplatePointOne(modelPoint.getShoulderLeft(), high, width)); - libraryModelPoint.setShoulderRight(calculateTemplatePointOne(modelPoint.getShoulderRight(), high, width)); - libraryModelPoint.setWaistbandLeft(calculateTemplatePointOne(modelPoint.getWaistbandLeft(), high, width)); - libraryModelPoint.setWaistbandRight(calculateTemplatePointOne(modelPoint.getWaistbandRight(), high, width)); - libraryModelPoint.setTemplateUrl(templateUrl); - return libraryModelPoint; - } - - private List calculateTemplatePointOne(String template, Integer high, Integer width) { - List originRatioList = JSON.parseObject(template, List.class); - originRatioList.set(0, originRatioList.get(0).multiply(BigDecimal.valueOf(width))); - originRatioList.set(1, originRatioList.get(1).multiply(BigDecimal.valueOf(high))); - return originRatioList; - } - - private List covertLibrarysToCollections(List libraries, Map idToMap) { - return CopyUtil.copyList(libraries, CollectionElement.class, (o, d) -> { - if (null != idToMap) { - CollectionSketchDTO sketchDTO = idToMap.get(o.getId()); - d.setLevel2Type(sketchDTO.getLevel2Type()); - d.setHasPin(sketchDTO.getIsPin()); - } - }); - } - - private List covertGeneratesToCollections(List generateDetailList, Map idToMap) { - return CopyUtil.copyList(generateDetailList, CollectionElement.class, (o, d) -> { - Generate byId = generateService.getById(o.getGenerateId()); - d.setAccountId(byId.getAccountId()); - d.setLevel1Type(byId.getLevel1Type()); - d.setCreateDate(Date.from(o.getCreateDate().atZone(ZoneId.systemDefault()).toInstant())); - if (null != idToMap) { - CollectionSketchDTO sketchDTO = idToMap.get(o.getId()); - d.setLevel2Type(sketchDTO.getLevel2Type()); - d.setHasPin(sketchDTO.getIsPin()); - } - }); - } - - private List covertLibrarysToPrintCollections(List libraries, Map idToMap) { - return CopyUtil.copyList(libraries, CollectionElement.class, (o, d) -> { - if (null != idToMap) { - DesignCollectionPrintElementDTO printDTO = idToMap.get(o.getId()); - d.setHasPin(printDTO.getIsPin()); - } - }); - } - - private List covertGeneratesToPrintCollections(List generateDetailList, Map idToMap) { - return CopyUtil.copyList(generateDetailList, CollectionElement.class, (o, d) -> { - Generate byId = generateService.getById(o.getGenerateId()); - d.setAccountId(byId.getAccountId()); - d.setLevel1Type(byId.getLevel1Type()); - if (!StringUtils.isEmpty(byId.getLevel2Type())) { - d.setLevel2Type(byId.getLevel2Type()); - } - d.setCreateDate(Date.from(o.getCreateDate().atZone(ZoneId.systemDefault()).toInstant())); - if (null != idToMap) { - DesignCollectionPrintElementDTO printDTO = idToMap.get(o.getId()); - d.setHasPin(printDTO.getIsPin()); - } - }); - } - - private void validateDesignType(List collectionElements, String msg) { - Boolean result = collectionElements.stream().filter(mood -> StringUtils.isEmpty(mood.getDesignType())).findFirst().isPresent(); - if (result) { - throw new BusinessException(msg + ".designType.cannot.be.empty"); - } - } - - @Override - public void editSketchBoardsElement(ValidateElementVO elementVO, List sketchBoards) { - if (CollectionUtil.isNotEmpty(sketchBoards)) { - List collect = sketchBoards.stream().filter(o -> o.getDesignType().equals(DesignTypeEnum.COLLECTION.getRealName())).collect(Collectors.toList()); - collect.forEach(sketchBoard -> { - CollectionElement collectionElement = CopyUtil.copyObject(sketchBoard, CollectionElement.class); - collectionElement.setHasPin(sketchBoard.getIsPin()); - collectionElement.setId(sketchBoard.getSketchBoardId()); - collectionElementMapper.updateById(collectionElement); - }); - List sketchBoardIds = collect.stream().map(CollectionSketchDTO::getSketchBoardId).collect(Collectors.toList()); - if (!CollectionUtils.isEmpty(sketchBoardIds)) { - List sketchBoardElements = collectionElementMapper.selectBatchIds(sketchBoardIds); - elementVO.setSketchBoardElements(sketchBoardElements); - }else { - elementVO.setSketchBoardElements(new ArrayList<>()); - } - } - } - - @Override - public void editPrintBoardsElement(ValidateElementVO elementVO, List printBoards) { - if (CollectionUtil.isNotEmpty(printBoards)) { - List collect = printBoards.stream().filter(o -> o.getDesignType().equals(DesignTypeEnum.COLLECTION.getRealName())).collect(Collectors.toList()); - collect.forEach(printBoard -> { - CollectionElement collectionElement = CopyUtil.copyObject(printBoard, CollectionElement.class); - collectionElement.setHasPin(Objects.isNull(printBoard.getIsPin()) ? 0 : printBoard.getIsPin()); - collectionElement.setId(printBoard.getId()); - collectionElementMapper.updateById(collectionElement); - }); - List printBoardIds = collect.stream().map(DesignCollectionPrintElementDTO::getId).collect(Collectors.toList()); - if (!CollectionUtils.isEmpty(printBoardIds)) { - List printBoardElements = collectionElementMapper.selectBatchIds(printBoardIds); - elementVO.setPrintBoardElements(printBoardElements); - }else { - elementVO.setPrintBoardElements(new ArrayList<>()); - } - } - } - - @Transactional(rollbackFor = Exception.class) - @Override - public void relationCollection(List elementIds, Long collectionId) { - if (CollectionUtils.isEmpty(elementIds) || null == collectionId) { - return; - } - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.lambda().in(CollectionElement::getId, elementIds); - CollectionElement element = new CollectionElement(); - element.setCollectionId(collectionId); - //批量关联 - collectionElementMapper.update(element, queryWrapper); - } - - @Transactional(rollbackFor = Exception.class) - @Override - public List saveColorBoard(List colorBoards, Long collectionId, String timeZone) { - //用户信息 - AuthPrincipalVo userInfo = UserContext.getUserHolder(); - List colorElements = resolveColorData(colorBoards, userInfo, collectionId, timeZone); - if (!this.saveBatch(colorElements)) { - throw new BusinessException("batch.save.colorElements.failed"); - } - return CopyUtil.copyList(colorElements, CollectionElementVO.class); - } - - @Override - public void refreshHistoryData() { - //幂等 - if (!CollectionUtils.isEmpty(tCollectionElementRelationService.getByCollectionId(1083L))) { - return; - } - // 分页数据 - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.orderByAsc("id"); - PageQueryBaseVo pageQuery = new PageQueryBaseVo(); - pageQuery.setPage(1); - pageQuery.setSize(200); - while (true) { - IPage page = getBaseMapper().selectPage( - new Page<>(pageQuery.getPage(), pageQuery.getSize()), queryWrapper); - List list = page.getRecords(); - if (CollectionUtils.isEmpty(list)) { - break; - } - - //保存 - List relations = list.stream().map(element -> - TCollectionElementRelation.builder().elementId(element.getId()) - .collectionId(element.getCollectionId()).createDate(new Date()).build()) - .collect(Collectors.toList()); - tCollectionElementRelationService.saveBatch(relations); - pageQuery.setPage(pageQuery.getPage() + 1); - log.info("refreshHistoryData###process###page###" + pageQuery.getPage()); - } - } - - private List resolveColorData(List colorBoards, AuthPrincipalVo userInfo, Long collectionId, String timeZone) { - List elements = Lists.newArrayList(); - colorBoards.forEach(color -> { - CollectionElement element = new CollectionElement(); - element.setAccountId(userInfo.getId()); - element.setCollectionId(collectionId); - if (StringUtils.isEmpty(color.getName())) { - element.setName(null); - } else { - element.setName(color.getId() + "_" + color.getName() + "_" + color.getTcx()); - } - element.setLevel1Type(CollectionLevel1TypeEnum.COLOR_BOARD.getRealName()); - element.setHasPin((byte) 0); - element.setMd5("0"); - element.setColorRgb(color.getRgbValue()); - //按时区计算 - element.setCreateDate(DateUtil.getByTimeZone(timeZone)); - if (Objects.nonNull(color.getGradient())) { - color.getGradient().setColorImg(null); - } - element.setGradientString(JSON.toJSONString(color.getGradient())); - elements.add(element); - }); - return elements; - } - - @Override - public List getByCollectionId(Long collectionId) { -// List elementIds = tCollectionElementRelationService.getByCollectionId(collectionId); -// if (CollectionUtils.isEmpty(elementIds)) { -// return null; -// } - QueryWrapper queryWrapper = new QueryWrapper<>(); -// queryWrapper.in("id", elementIds); - queryWrapper.lambda().eq(CollectionElement::getCollectionId, collectionId); - return collectionElementMapper.selectList(queryWrapper); - } - - @Override - public List getByOnlyCollectionId(Long collectionId) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("collection_id", collectionId); - return collectionElementMapper.selectList(queryWrapper); - } - - private CollectionElement selectById(Long id) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("id", id); - return collectionElementMapper.selectOne(queryWrapper); - } - - private Boolean exists(Long id) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("id", id); - return collectionElementMapper.exists(queryWrapper); - } - - private boolean saveOne(CollectionElement collectionElement) { - if (collectionElementMapper.insert(collectionElement) <= 0) { - throw new BusinessException("save.collectionElement.failed"); - } - return Boolean.TRUE; - } - - @Override - public CollectionElement editLevel2Type(Long elementId, String level2Type, String designType) { - CollectionElement collectionElement = new CollectionElement(); - - if (!Objects.isNull(elementId)) { - if (!StringUtil.isNullOrEmpty(designType)){ - switch (designType){ - case "collection": - collectionElement = collectionElementMapper.selectById(elementId); - if (StringUtil.isNullOrEmpty(collectionElement.getLevel2Type()) || !(collectionElement.getLevel2Type()).equals(level2Type)) { - collectionElement.setLevel2Type(level2Type); - updateById(collectionElement); - } - break; - case "library": - Library libraryElement = libraryService.getById(elementId); - if (!Objects.isNull(libraryElement)) { - if (StringUtil.isNullOrEmpty(libraryElement.getLevel2Type()) || !(libraryElement.getLevel2Type()).equals(level2Type)){ - libraryElement.setLevel2Type(level2Type); - libraryService.updateById(libraryElement); - } - BeanUtils.copyProperties(libraryElement,collectionElement); - } - break; - } - } else { - log.error("designType cannot be empty"); - throw new BusinessException("element source type cannot be empty!"); - } - }else { - return null; - } - return collectionElement; - } - - private Generate setGenerate(Long userId,String timeZone){ - Generate generate = new Generate(); - generate.setAccountId(userId); - generate.setLevel1Type(CollectionLevel1TypeEnum.PRINT_BOARD.getRealName()); - generate.setGenerateType("synthesis"); -// generate.setModelName("Image Synthesis Model"); - generate.setCreateDate(DateUtil.getByTimeZone(timeZone)); - return generate; - } - - private GenerateDetail setGenerateDetail(Long generateId, String url, String timeZone){ - GenerateDetail generateDetail = new GenerateDetail(); - generateDetail.setGenerateId(generateId); - generateDetail.setUrl(url); - String md5; - try { - md5 = MD5Utils.encryptFile(minioUtil.download(url)); - } catch (Exception e){ - throw new RuntimeException(e); - }/*catch (MinioException | IOException e) { - throw new RuntimeException(e); - }*/ - // 通过MD5来确认当前图片是否有被like过,避免重复like - List> libraryIds = generateDetailMapper.getLibraryIdThroughMD5(md5, CollectionLevel1TypeEnum.PRINT_BOARD.getRealName()); - if (libraryIds.isEmpty()){ - generateDetail.setIsLike((byte) 0); - }else { - generateDetail.setIsLike((byte) 1); - generateDetail.setLibraryId(libraryIds.get(0).get("library_id")); - } - generateDetail.setMd5(md5); - generateDetail.setCreateDate(LocalDateTime.now()); - - return generateDetail; - } -} +package com.ai.da.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import com.ai.da.common.config.FileProperties; +import com.ai.da.common.config.exception.BusinessException; +import com.ai.da.common.constant.CommonConstant; +import com.ai.da.common.context.UserContext; +import com.ai.da.common.enums.*; +import com.ai.da.common.response.ResultEnum; +import com.ai.da.common.utils.*; +import com.ai.da.mapper.primary.CollectionElementMapper; +import com.ai.da.mapper.primary.GenerateDetailMapper; +import com.ai.da.mapper.primary.entity.*; +import com.ai.da.model.dto.*; +import com.ai.da.model.enums.ModelType; +import com.ai.da.model.enums.Sex; +import com.ai.da.model.enums.StyleEnum; +import com.ai.da.model.vo.*; +import com.ai.da.python.PythonService; +import com.ai.da.python.vo.DesignPythonItem; +import com.ai.da.python.vo.ImageSegmentation; +import com.ai.da.service.*; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.common.collect.Lists; +import com.google.gson.Gson; +import io.netty.util.internal.StringUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import java.io.File; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 服务实现类 + * + * @author yanglei + * @since 2022-09-30 + */ +@Slf4j +@Service +public class CollectionElementServiceImpl extends ServiceImpl implements CollectionElementService { + @Resource + private CollectionElementMapper collectionElementMapper; + @Resource + private FileProperties fileProperties; + @Resource + private PanToneService panToneService; + @Resource + private PythonService pythonService; + @Resource + private LibraryService libraryService; + @Resource + private SysFileService sysFileService; + @Resource + private GenerateService generateService; + @Resource + private GenerateDetailMapper generateDetailMapper; + @Resource + private LibraryModelPointService libraryModelPointService; + @Resource + private TCollectionElementRelationService tCollectionElementRelationService; + @Resource + private MinioUtil minioUtil; + + @Value("${minio.bucketName.collectionElement}") + private String collectionElement; + @Value("${minio.bucketName.gradient}") + private String gradientBucketName; + @Value("${minio.bucketName.users}") + private String userBucketName; + @Resource + private RedisUtil redisUtil; + +// @Resource +// private RedisUtil redisUtil; + + @Transactional(rollbackFor = Exception.class) + @Override + public CollectionElementVO upload(CollectionElementUploadDTO uploadDTO) { + long start = System.currentTimeMillis(); + //用户信息 + AuthPrincipalVo userInfo = UserContext.getUserHolder(); + CollectionLevel1TypeEnum level1TypeEnum = CollectionLevel1TypeEnum.uploadOf(uploadDTO.getLevel1Type()); + if (Objects.isNull(level1TypeEnum)) { + throw new BusinessException("unknown.parameter.level1Type"); + } + String objectName = userInfo.getId() + "/" + level1TypeEnum.getRealName(); + String path = minioUtil.upload(collectionElement, objectName, uploadDTO.getFile()); + + String level2Type = null; + if (uploadDTO.getLevel1Type().equals(CollectionLevel1TypeEnum.SKETCH_BOARD.getRealName())){ + if (StringUtil.isNullOrEmpty(uploadDTO.getGender())) { + throw new BusinessException("gender.cannot.be.empty"); + } + level2Type = pythonService.getClothCategory(path,uploadDTO.getGender()); + } + + //保存element元素 + CollectionElement collectionElement = resolveData(uploadDTO, userInfo, path, level2Type); + saveOne(collectionElement); +// if (!StringUtils.isEmpty(uploadDTO.getMoodboardPosition())) { +// redisUtil.saveMoodboardPosition(collectionElement.getId(), uploadDTO.getMoodboardPosition()); +// } + CollectionElementVO collectionElementVO = CopyUtil.copyObject(collectionElement, CollectionElementVO.class); + collectionElementVO.setMinIOPath(collectionElementVO.getUrl()); + collectionElementVO.setUrl(minioUtil.getPreSignedUrl(collectionElementVO.getUrl(), 24 * 60)); + collectionElementVO.setDesignType(DesignTypeEnum.COLLECTION.getRealName()); + + long end = System.currentTimeMillis(); + double floor = Math.floor((double) (end - start) / 1000); + log.info("本次图片上传耗时:{} 毫秒", end - start); + Long incrementCount = redisUtil.getIncrementCount(RedisUtil.UPLOAD_TIMEOUT_REMINDER_COUNTER); + if (floor > 5 && incrementCount < 3) { + // 邮件通知 一天最多通知3次 + log.info("上传超过5秒,发送邮件通知"); + SendEmailUtil.uploadTimeoutReminder(userInfo.getUsername(), String.valueOf(((end - start) / 1000))); + redisUtil.increaseCount(RedisUtil.UPLOAD_TIMEOUT_REMINDER_COUNTER); + } + return collectionElementVO; + } + + private String calculateFileUrl(CollectionLevel1TypeEnum level1TypeEnum, Long userId) { + String rootPath = fileProperties.getSys().getPath(); + String day = DateUtil.dateToStr(new Date(), DateUtil.YYYYMM); + return rootPath + day + "/" + "userFile" + "/collection" + + "/" + level1TypeEnum.getRealName() + "/" + userId + "/" + UUID.randomUUID().toString(); + } + + private CollectionElement resolveData(CollectionElementUploadDTO uploadDTO, AuthPrincipalVo userInfo, File file) { + CollectionElement element = CopyUtil.copyObject(uploadDTO, CollectionElement.class); + element.setAccountId(userInfo.getId()); + element.setCollectionId(0L); + element.setHasPin((byte) 0); + String pictureCollectonName = file.getName(); + //获取图片后缀 + String suffix = pictureCollectonName.substring(pictureCollectonName.lastIndexOf(".")); + //获取图片前缀 + String prefix = pictureCollectonName.substring(0, pictureCollectonName.lastIndexOf(".")); + element.setName(DateUtil.dateToStr(new Date(), DateUtil.YYYY_MM_DD)); + element.setUrl(file.getAbsolutePath()); + //按时区计算 + element.setCreateDate(DateUtil.getByTimeZone(uploadDTO.getTimeZone())); + String linuxDomain = fileProperties.getLinuxDomain(); + if (!StringUtils.isEmpty(linuxDomain)) { + //linux 系统 + String oldPath = fileProperties.getSys().getPath(); + element.setUrl(file.getAbsolutePath().replace(oldPath, linuxDomain)); + } + return element; + } + + private CollectionElement resolveData(CollectionElementUploadDTO uploadDTO, AuthPrincipalVo userInfo, String path, String level2Type) { + CollectionElement element = CopyUtil.copyObject(uploadDTO, CollectionElement.class); + element.setAccountId(userInfo.getId()); + element.setCollectionId(0L); + element.setHasPin((byte) 0); +// String pictureCollectonName = fileName; +// //获取图片后缀 +// String suffix = pictureCollectonName.substring(pictureCollectonName.lastIndexOf(".")); +// //获取图片前缀 +// String prefix = pictureCollectonName.substring(0,pictureCollectonName.lastIndexOf(".")); + String originalFilename = uploadDTO.getFile().getOriginalFilename(); + if (originalFilename != null && originalFilename.contains(".")) { + // 如果文件名包含点号,则去除最后一个点及其后面的内容 + int lastDotIndex = originalFilename.lastIndexOf("."); + if (lastDotIndex != -1) { + originalFilename = originalFilename.substring(0, lastDotIndex); + } + } + element.setName(originalFilename); + element.setUrl(path); + //按时区计算 + element.setCreateDate(DateUtil.getByTimeZone(uploadDTO.getTimeZone())); + element.setLevel2Type(level2Type); +// String linuxDomain = fileProperties.getLinuxDomain(); +// if (!StringUtils.isEmpty(linuxDomain)) { +// //linux 系统 +// String oldPath = fileProperties.getSys().getPath(); +// element.setUrl(file.getAbsolutePath().replace(oldPath, linuxDomain)); +// } + return element; + } + + @Override + public void delete(Long id) { + CollectionElement collectionElement = selectById(id); + if (Objects.isNull(collectionElement)) { + throw new BusinessException("collectionElement.not.found"); + } + minioUtil.deleteObject(collectionElement.getUrl()); + collectionElementMapper.deleteById(id); +// if (!FileUtil.delete(collectionElement.getUrl())) { +// throw new BusinessException("file deletion failed! "); +// } + } + + @Override + public void batchDelete(List ids) { + if (CollectionUtils.isEmpty(ids)) { + return; + } +// QueryWrapper queryWrapper = new QueryWrapper<>(); +// queryWrapper.in("id", ids); +// CollectionElement collectionElement = new CollectionElement(); +// collectionElement.setCollectionId(0L); + collectionElementMapper.deleteBatchIds(ids); + } + + /** 该方法已不再使用 */ + @Deprecated + @Override + public GenerateCollectionItemVO generatePrint(CollectionGeneratePrintDTO generatePrintDTO) { + Long userId = UserContext.getUserHolder().getId(); + String url1 = null; + String url2 = null; + CollectionElement element1 = selectById(generatePrintDTO.getSelect1Id()); + if (Objects.isNull(element1)) { + Library library1 = libraryService.getById(generatePrintDTO.getSelect1Id()); + if (Objects.isNull(library1)) { + throw new BusinessException("select1.file.does.not.exist"); + } + url1 = library1.getUrl(); + } else { + url1 = element1.getUrl(); + } + CollectionElement element2 = selectById(generatePrintDTO.getSelect2Id()); + if (Objects.isNull(element2)) { + Library library2 = libraryService.getById(generatePrintDTO.getSelect2Id()); + if (Objects.isNull(library2)) { + throw new BusinessException("select2.file.does.not.exist"); + } + url2 = library2.getUrl(); + } else { + url2 = element2.getUrl(); + } + List printPath = Arrays.asList(url1, url2); + //调取python 接口 + String generateUrl = pythonService.generatePrint(printPath,userId); + if (StringUtils.isEmpty(generateUrl)) { + throw new BusinessException("generate.interface.exception"); + } + + // 保存合成信息到generate表 + Generate generate = setGenerate(userId, generatePrintDTO.getTimeZone()); + generateService.save(generate); + + // 保存合成后的信息到generateDetail + GenerateDetail generateDetail = setGenerateDetail(generate.getId(), generateUrl, generatePrintDTO.getTimeZone()); + generateDetailMapper.insert(generateDetail); + +// CollectionElement element = resolveData(generateUrl, generatePrintDTO.getTimeZone(), userId); +// if (!this.save(element)) { +// throw new BusinessException("save.collectionElement.failed"); +// } +// CollectionGeneratePrintVO collectionGeneratePrint = CopyUtil.copyObject(element, CollectionGeneratePrintVO.class); +// collectionGeneratePrint.setUrl(minioUtil.getPresignedUrl(generateUrl, 24 * 60)); +// collectionGeneratePrint.setDesignType(DesignTypeEnum.COLLECTION.getRealName()); +// return collectionGeneratePrint; + return new GenerateCollectionItemVO(generateDetail.getId(), + minioUtil.getPreSignedUrl(generateUrl, 24 * 60), + generateDetail.getIsLike().equals((byte) 0) ? Boolean.FALSE : Boolean.TRUE); + } + + @Override + public Boolean savePrint(CollectionSavePrintDTO savePrintDTO) { + //用户信息 + List elements = listByIds(savePrintDTO.getPrintId()); + if (CollectionUtils.isEmpty(elements)) { + throw new BusinessException("collectionElements.not.found"); + } + return saveLibraryByCollectionElement(elements, savePrintDTO.getTimeZone()); + } + + @Override + public Boolean saveLibraryByCollectionElement(List elements, String timeZone) { + if (CollectionUtils.isEmpty(elements)) { + return Boolean.TRUE; + } + //获取已存在相同的library + List md5List = elements.stream().map(CollectionElement::getMd5).collect(Collectors.toList()); + List existsLibrarys = libraryService.getByMD5List(md5List); + if (!CollectionUtils.isEmpty(existsLibrarys)) { + //去重 + List existsMd5Lists = existsLibrarys.stream().map(Library::getMd5).collect(Collectors.toList()); + elements = elements.stream().filter(element -> !existsMd5Lists.contains(element.getMd5())).collect(Collectors.toList()); + } + if (CollectionUtils.isEmpty(elements)) { + //都是重复的 + return Boolean.TRUE; + } + String name = DateUtil.dateToStr(new Date(), DateUtil.YYYY_MM_DD); + List libraryList = CopyUtil.copyList(elements, Library.class, (o, d) -> { + d.setCreateDate(DateUtil.getByTimeZone(timeZone)); + d.setName(name); + d.setId(null); + }); + if (!libraryService.saveBatch(libraryList)) { + throw new BusinessException("batch.save.libraryList.failed"); + } + return Boolean.TRUE; + } + + @Override + public Boolean saveLibraryByCollectionElement(List elements, String timeZone, String modelSex) { + if (CollectionUtils.isEmpty(elements)) { + return Boolean.TRUE; + } + //获取已存在相同的library + List md5List = elements.stream().map(CollectionElement::getMd5).collect(Collectors.toList()); + List existsLibrarys = libraryService.getByMD5List(md5List); + if (!CollectionUtils.isEmpty(existsLibrarys)) { + //去重 + List existsMd5Lists = existsLibrarys.stream().map(Library::getMd5).collect(Collectors.toList()); + elements = elements.stream().filter(element -> !existsMd5Lists.contains(element.getMd5())).collect(Collectors.toList()); + } + if (CollectionUtils.isEmpty(elements)) { + //都是重复的 + return Boolean.TRUE; + } + String name = DateUtil.dateToStr(new Date(), DateUtil.YYYY_MM_DD); + List libraryList = CopyUtil.copyList(elements, Library.class, (o, d) -> { + if (d.getLevel1Type().equals(LibraryLevel1TypeEnum.SKETCH_BOARD.getRealName())) { + d.setLevel3Type(modelSex); +// try { +// libraryService.processSketchBoards(d.getUrl(), d.getLevel2Type()); +// }catch (Exception e) { +// // TODO:暂不处理 +// } + } + d.setCreateDate(DateUtil.getByTimeZone(timeZone)); + d.setName(name); + d.setId(null); + }); + if (!libraryService.saveBatch(libraryList)) { + throw new BusinessException("batch.save.libraryList.failed"); + } + return Boolean.TRUE; + } + + private CollectionElement resolveData(String path, String timeZone, Long userId){ +// File file = new File(path); + + String name = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf(".")); + CollectionElement element = new CollectionElement(); + element.setAccountId(userId); + element.setCollectionId(0L); + element.setName(name); + element.setLevel1Type(CollectionLevel1TypeEnum.PRINT_BOARD.getRealName()); + element.setUrl(path); + element.setHasPin((byte) 0); + try { + element.setMd5(MD5Utils.encryptFile(minioUtil.download(path))); + }catch (Exception e){ + throw new RuntimeException(e); + } + /* catch (MinioException | IOException e) { + throw new RuntimeException(e); + }*/ + + //按时区计算 + element.setCreateDate(DateUtil.getByTimeZone(timeZone)); + return element; + } + + @Override + public ValidateElementVO validateElement(DesignCollectionDTO designDTO) { + ValidateElementVO elementVO = CopyUtil.copyObject(designDTO, ValidateElementVO.class); + List colorBoards = elementVO.getColorBoards(); + for (CollectionColorDTO colorBoard : colorBoards) { + if (Objects.nonNull(colorBoard.getGradient())) { + String colorImg = colorBoard.getGradient().getColorImg(); + String[] parts = colorImg.split(","); + String imageType = parts[0].split("/")[1].split(";")[0]; + String base64Data = parts[1]; + String gradientMinioUrl = minioUtil.uploadImageFromBase64(gradientBucketName, base64Data, imageType); + colorBoard.setGradientMinioUrl(gradientMinioUrl); + colorBoard.getGradient().setColorImg(null); + colorBoard.setGradientString(JSON.toJSONString(colorBoard.getGradient())); + } + } + elementVO.setColorBoards(colorBoards); + List usedElementIds = elementVO.getUsedElementIds(); + List libraryCollectionElements = elementVO.getLibraryCollectionElements(); + List generateCollectionElements = elementVO.getGenerateCollectionElements(); + //校验moodboard + if (CollectionUtil.isNotEmpty(designDTO.getMoodBoards())) { + //校验designType + validateDesignType(designDTO.getMoodBoards(), "moodBoards"); + List moodBoardIds = designDTO.getMoodBoards().stream() + .filter(f -> f.getDesignType().equals(DesignTypeEnum.COLLECTION.getRealName())) + .map(DesignCollectionElementDTO::getId) + .collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(moodBoardIds)) { + List MoodBoardElements = collectionElementMapper.selectBatchIds(moodBoardIds); + if (CollectionUtil.isEmpty(MoodBoardElements) || MoodBoardElements.size() != moodBoardIds.size()) { + throw new BusinessException("get.moodBoards.data.is.mismatch"); + } + elementVO.setMoodBoardElements(MoodBoardElements); + usedElementIds.addAll(moodBoardIds); + } + //library + List libraryIds = designDTO.getMoodBoards().stream() + .filter(f -> f.getDesignType().equals(DesignTypeEnum.LIBRARY.getRealName())) + .map(DesignCollectionElementDTO::getId) + .collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(libraryIds)) { + List librarys = libraryService.getByIds(libraryIds); + //不校验了防止用户在library删除 对应不上 + if (CollectionUtil.isNotEmpty(librarys)) { + libraryCollectionElements.addAll(covertLibrarysToCollections(librarys, null)); + } + } + // generate + List generateIds = designDTO.getMoodBoards().stream() + .filter(o -> o.getDesignType().equals((DesignTypeEnum.GENERATE.getRealName()))) + .map(DesignCollectionElementDTO::getId) + .collect((Collectors.toList())); + if (CollectionUtil.isNotEmpty(generateIds)) { + List generateDetailList = generateDetailMapper.selectBatchIds(generateIds); + if (CollectionUtil.isNotEmpty(generateDetailList)) { + generateCollectionElements.addAll(covertGeneratesToCollections(generateDetailList, null)); + } + } + } + if (CollectionUtil.isNotEmpty(designDTO.getPrintBoards())) { + //校验designType + validateDesignType(CopyUtil.copyList(designDTO.getPrintBoards(), DesignCollectionElementDTO.class), "printBoards"); + List printBoardIds = designDTO.getPrintBoards().stream() + .filter(f -> f.getDesignType().equals(DesignTypeEnum.COLLECTION.getRealName())) + .map(DesignCollectionPrintElementDTO::getId) + .collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(printBoardIds)) { + //校验printboard + List printBoardElements = collectionElementMapper.selectBatchIds(printBoardIds); + if (CollectionUtil.isEmpty(printBoardElements) || printBoardElements.size() != printBoardIds.size()) { + throw new BusinessException("get.printBoards.data.is.mismatch"); + } + elementVO.setPrintBoardElements(printBoardElements); + usedElementIds.addAll(printBoardIds); + } + //library + List libraryIds = designDTO.getPrintBoards().stream() + .filter(f -> f.getDesignType().equals(DesignTypeEnum.LIBRARY.getRealName())) + .map(DesignCollectionPrintElementDTO::getId) + .collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(libraryIds)) { + List librarys = libraryService.getByIds(libraryIds); + //不校验了防止用户在library删除 对应不上 + if (CollectionUtil.isNotEmpty(librarys)) { + Map idToMap = designDTO.getPrintBoards() + .stream() + .collect(Collectors.toMap(DesignCollectionPrintElementDTO::getId, v -> v)); + libraryCollectionElements.addAll(covertLibrarysToPrintCollections(librarys, idToMap)); + } + } + // generate + List generateIds = designDTO.getPrintBoards().stream() + .filter(o -> o.getDesignType().equals((DesignTypeEnum.GENERATE.getRealName()))) + .map(DesignCollectionPrintElementDTO::getId) + .collect((Collectors.toList())); + if (CollectionUtil.isNotEmpty(generateIds)) { + List generateDetailList = generateDetailMapper.selectBatchIds(generateIds); + if (CollectionUtil.isNotEmpty(generateDetailList)) { + Map idToMap = designDTO.getPrintBoards() + .stream() + .collect(Collectors.toMap(DesignCollectionPrintElementDTO::getId, v -> v)); + generateCollectionElements.addAll(covertGeneratesToPrintCollections(generateDetailList, idToMap)); + } + } + } + if (CollectionUtil.isNotEmpty(designDTO.getSketchBoards())) { + //校验PIN是否满足 上衣或者下衣必须不超过8 + long topNum = 0; + long bottomNum = 0; + long outerwearNum = 0; + if (designDTO.getModelSex().equals(Sex.FEMALE.getValue())) { + topNum= designDTO.getSketchBoards().stream() + .filter(skecth -> skecth.getIsPin() == 1 + && DesignPythonItem.DRESS_BLOUSE.contains(skecth.getLevel2Type())).count(); + bottomNum = designDTO.getSketchBoards().stream() + .filter(skecth -> skecth.getIsPin() == 1 + && DesignPythonItem.SKIRT_TROUSERS.contains(skecth.getLevel2Type())).count(); + }else if (designDTO.getModelSex().equals(Sex.MALE.getValue())) { + topNum= designDTO.getSketchBoards().stream() + .filter(skecth -> skecth.getIsPin() == 1 + && DesignPythonItem.TOPS.contains(skecth.getLevel2Type())).count(); + bottomNum = designDTO.getSketchBoards().stream() + .filter(skecth -> skecth.getIsPin() == 1 + && DesignPythonItem.BOTTOMS.contains(skecth.getLevel2Type())).count(); + } + outerwearNum = designDTO.getSketchBoards().stream() + .filter(skecth -> skecth.getIsPin() == 1 + && DesignPythonItem.OUTWEAR.contains(skecth.getLevel2Type())).count(); + if (topNum > 8 || bottomNum > 8 || outerwearNum > 8) { + throw new BusinessException("the.number.of.PIN.top.or.bottom.or.outerwear.sketchBoard.cannot.be.more.than.8", ResultEnum.PROMPT.getCode()); + } + //校验designType + Boolean result = designDTO.getSketchBoards().stream() + .filter(mood -> StringUtils.isEmpty(mood.getDesignType())) + .findFirst().isPresent(); + if (result) { + throw new BusinessException("sketchBoards.designType.cannot.be.empty"); + } + + List sketchBoardIds = designDTO.getSketchBoards().stream() + .filter(f -> f.getDesignType().equals(DesignTypeEnum.COLLECTION.getRealName())) + .map(CollectionSketchDTO::getSketchBoardId) + .collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(sketchBoardIds)) { + //校验sketchBoard + List sketchBoardElements = collectionElementMapper.selectBatchIds(sketchBoardIds); + if (CollectionUtil.isEmpty(sketchBoardElements) || sketchBoardElements.size() != sketchBoardIds.size()) { + throw new BusinessException("get.sketchBoards.data.is.mismatch"); + } + elementVO.setSketchBoardElements(sketchBoardElements); + usedElementIds.addAll(sketchBoardIds); + } + //library + List libraryIds = designDTO.getSketchBoards().stream() + .filter(f -> f.getDesignType().equals(DesignTypeEnum.LIBRARY.getRealName())) + .map(CollectionSketchDTO::getSketchBoardId) + .collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(libraryIds)) { + List librarys = libraryService.getByIds(libraryIds); + //不校验了防止用户在library删除 对应不上 + if (CollectionUtil.isNotEmpty(librarys)) { + Map idToMap = designDTO.getSketchBoards() + .stream() + .collect(Collectors.toMap(CollectionSketchDTO::getSketchBoardId, v -> v)); + libraryCollectionElements.addAll(covertLibrarysToCollections(librarys, idToMap)); + } + } + // generate + List generateIds = designDTO.getSketchBoards().stream() + .filter(o -> o.getDesignType().equals((DesignTypeEnum.GENERATE.getRealName()))) + .map(CollectionSketchDTO::getSketchBoardId) + .collect((Collectors.toList())); + if (CollectionUtil.isNotEmpty(generateIds)) { + List generateDetailList = generateDetailMapper.selectBatchIds(generateIds); + if (CollectionUtil.isNotEmpty(generateDetailList)) { + Map idToMap = designDTO.getSketchBoards() + .stream() + .collect(Collectors.toMap(CollectionSketchDTO::getSketchBoardId, v -> v)); + generateCollectionElements.addAll(covertGeneratesToCollections(generateDetailList, idToMap)); + } + } + } + //校验marketingSketch + // 2023.12版本去掉了这个入参 +// if (CollectionUtil.isNotEmpty(designDTO.getMarketingSketchs())) { +// //校验designType +// validateDesignType(designDTO.getMarketingSketchs(),"marketingSketchs"); +// List printBoardIds = designDTO.getMarketingSketchs().stream() +// .filter(f ->f.getDesignType().equals(DesignTypeEnum.COLLECTION.getRealName())) +// .map(DesignCollectionElementDTO::getId) +// .collect(Collectors.toList()); +// if(!CollectionUtils.isEmpty(printBoardIds)){ +// List marketingSketchElements = collectionElementMapper.selectBatchIds(printBoardIds); +// Assert.isTrue(CollectionUtil.isNotEmpty(marketingSketchElements) +// && marketingSketchElements.size() == printBoardIds.size(), "get marketingSketch data is mismatch"); +// elementVO.setMarketingSketchElements(marketingSketchElements); +// usedElementIds.addAll(printBoardIds); +// } +// //library +// List libraryIds = designDTO.getMarketingSketchs().stream() +// .filter(f ->f.getDesignType().equals(DesignTypeEnum.LIBRARY.getRealName())) +// .map(DesignCollectionElementDTO::getId) +// .collect(Collectors.toList()); +// if(!CollectionUtils.isEmpty(libraryIds)){ +// List librarys = libraryService.getByIds(libraryIds); +// //不校验了防止用户在library删除 对应不上 +// if(CollectionUtil.isNotEmpty(librarys)){ +// libraryCollectionElements.addAll(covertLibrarysToCollections(librarys,null)); +// } +// } +// } + //校验控制生成类型 + SingleOverallEnum singleOverall = SingleOverallEnum.of(designDTO.getSingleOverall()); + if (Objects.isNull(singleOverall)) { + throw new BusinessException("unknown.parameter.singleOverall"); + } + if (SingleOverallEnum.SINGLE.equals(singleOverall)) { + SwitchCategoryEnum switchCategory = SwitchCategoryEnum.of(designDTO.getSwitchCategory()); + if (Objects.isNull(switchCategory)) { + throw new BusinessException("unknown.parameter.switchCategory"); + } + } + // 校验模特 + if (designDTO.getModelType().equals(ModelType.LIBRARY.getValue())) { + Library byId = libraryService.getById(designDTO.getTemplateId()); + LibraryModelPoint modelPoint = libraryModelPointService.getByRelationId(byId.getId(), designDTO.getModelType()); + elementVO.setDesignLibraryModelPoint(calculateTemplatePointTemplate(modelPoint, byId.getHigh(), byId.getWidth(), byId.getUrl())); + } else if (designDTO.getModelType().equals(ModelType.SYSTEM.getValue())) { + SysFileVO byId = sysFileService.getById(designDTO.getTemplateId()); + if (!StringUtils.isEmpty(byId.getLevel3Type()) && byId.getLevel2Type().equals("Female")) { + elementVO.setStyle(byId.getLevel3Type()); + } + LibraryModelPoint modelPoint = libraryModelPointService.getByRelationId(byId.getId(), designDTO.getModelType()); + elementVO.setDesignLibraryModelPoint(calculateTemplatePointTemplate(modelPoint, 700, 320, byId.getUrl())); + } + // todo 开发分支代码,暂时以注释形式存在 + /* + if (!StringUtils.isEmpty(designDTO.getModelType())) { + if (designDTO.getModelType().equals(ModelType.LIBRARY.getValue())) { + Library byId = libraryService.getById(designDTO.getTemplateId()); + LibraryModelPoint modelPoint = libraryModelPointService.getByRelationId(byId.getId(), designDTO.getModelType()); + elementVO.setDesignLibraryModelPoint(calculateTemplatePointTemplate(modelPoint, byId.getHigh(), byId.getWidth(), byId.getUrl())); + } else if (designDTO.getModelType().equals(ModelType.SYSTEM.getValue())) { + SysFileVO byId = sysFileService.getById(designDTO.getTemplateId()); + if (!StringUtils.isEmpty(byId.getLevel3Type()) && byId.getLevel2Type().equals("Female")) { + elementVO.setStyle(byId.getLevel3Type()); + } + LibraryModelPoint modelPoint = libraryModelPointService.getByRelationId(byId.getId(), designDTO.getModelType()); + elementVO.setDesignLibraryModelPoint(calculateTemplatePointTemplate(modelPoint, 700, 320, byId.getUrl())); + } + }*/ + elementVO.setModelSex(designDTO.getModelSex()); + elementVO.setRequestIdList(designDTO.getRequestIdList()); + if (null != designDTO.getDesignNum()) { + elementVO.setDesignNum(designDTO.getDesignNum()); + }else { + elementVO.setDesignNum(8); + } + return elementVO; + } + + @Override + public DesignLibraryModelPointVO calculateTemplatePoint(LibraryModelPoint modelPoint, Integer high, Integer width, String templateUrl) { + DesignLibraryModelPointVO libraryModelPoint = new DesignLibraryModelPointVO(); + libraryModelPoint.setHandLeft(calculateTemplatePointOne(modelPoint.getHandLeft(), high, width)); + libraryModelPoint.setHandRight(calculateTemplatePointOne(modelPoint.getHandRight(), high, width)); + libraryModelPoint.setShoulderLeft(calculateTemplatePointOne(modelPoint.getShoulderLeft(), high, width)); + libraryModelPoint.setShoulderRight(calculateTemplatePointOne(modelPoint.getShoulderRight(), high, width)); + libraryModelPoint.setWaistbandLeft(calculateTemplatePointOne(modelPoint.getWaistbandLeft(), high, width)); + libraryModelPoint.setWaistbandRight(calculateTemplatePointOne(modelPoint.getWaistbandRight(), high, width)); + libraryModelPoint.setTemplateUrl(templateUrl); + return libraryModelPoint; + } + + @Override + public DesignLibraryModelPointVO calculateTemplatePointTemplate(LibraryModelPoint modelPoint, Integer high, Integer width, String templateUrl) { + DesignLibraryModelPointVO libraryModelPoint = new DesignLibraryModelPointVO(); +// LibraryModelPoint template = libraryModelPointService.getById(96L); +// libraryModelPoint.setHandLeft(calculateTemplatePointOne(template.getHandLeft(),752,564)); +// libraryModelPoint.setHandRight(calculateTemplatePointOne(template.getHandRight(),752,564)); +// libraryModelPoint.setShoulderLeft(calculateTemplatePointOne(template.getShoulderLeft(),752,564)); +// libraryModelPoint.setShoulderRight(calculateTemplatePointOne(template.getShoulderRight(),752,564)); +// libraryModelPoint.setWaistbandLeft(calculateTemplatePointOne(template.getWaistbandLeft(),752,564)); +// libraryModelPoint.setWaistbandRight(calculateTemplatePointOne(template.getWaistbandRight(),752,564)); +// libraryModelPoint.setTemplateUrl("aida-mannequins/model_1693218345.2714432.png"); + libraryModelPoint.setHandLeft(calculateTemplatePointOne(modelPoint.getHandLeft(), high, width)); + libraryModelPoint.setHandRight(calculateTemplatePointOne(modelPoint.getHandRight(), high, width)); + libraryModelPoint.setShoulderLeft(calculateTemplatePointOne(modelPoint.getShoulderLeft(), high, width)); + libraryModelPoint.setShoulderRight(calculateTemplatePointOne(modelPoint.getShoulderRight(), high, width)); + libraryModelPoint.setWaistbandLeft(calculateTemplatePointOne(modelPoint.getWaistbandLeft(), high, width)); + libraryModelPoint.setWaistbandRight(calculateTemplatePointOne(modelPoint.getWaistbandRight(), high, width)); + libraryModelPoint.setTemplateUrl(templateUrl); + return libraryModelPoint; + } + + private List calculateTemplatePointOne(String template, Integer high, Integer width) { + List originRatioList = JSON.parseObject(template, List.class); + originRatioList.set(0, originRatioList.get(0).multiply(BigDecimal.valueOf(width))); + originRatioList.set(1, originRatioList.get(1).multiply(BigDecimal.valueOf(high))); + return originRatioList; + } + + private List covertLibrarysToCollections(List libraries, Map idToMap) { + return CopyUtil.copyList(libraries, CollectionElement.class, (o, d) -> { + if (null != idToMap) { + CollectionSketchDTO sketchDTO = idToMap.get(o.getId()); + d.setLevel2Type(sketchDTO.getLevel2Type()); + d.setHasPin(sketchDTO.getIsPin()); + } + }); + } + + private List covertGeneratesToCollections(List generateDetailList, Map idToMap) { + return CopyUtil.copyList(generateDetailList, CollectionElement.class, (o, d) -> { + Generate byId = generateService.getById(o.getGenerateId()); + d.setAccountId(byId.getAccountId()); + d.setLevel1Type(byId.getLevel1Type()); + d.setCreateDate(Date.from(o.getCreateDate().atZone(ZoneId.systemDefault()).toInstant())); + if (null != idToMap) { + CollectionSketchDTO sketchDTO = idToMap.get(o.getId()); + d.setLevel2Type(sketchDTO.getLevel2Type()); + d.setHasPin(sketchDTO.getIsPin()); + } + }); + } + + private List covertLibrarysToPrintCollections(List libraries, Map idToMap) { + return CopyUtil.copyList(libraries, CollectionElement.class, (o, d) -> { + if (null != idToMap) { + DesignCollectionPrintElementDTO printDTO = idToMap.get(o.getId()); + d.setHasPin(printDTO.getIsPin()); + } + }); + } + + private List covertGeneratesToPrintCollections(List generateDetailList, Map idToMap) { + return CopyUtil.copyList(generateDetailList, CollectionElement.class, (o, d) -> { + Generate byId = generateService.getById(o.getGenerateId()); + d.setAccountId(byId.getAccountId()); + d.setLevel1Type(byId.getLevel1Type()); + if (!StringUtils.isEmpty(byId.getLevel2Type())) { + d.setLevel2Type(byId.getLevel2Type()); + } + d.setCreateDate(Date.from(o.getCreateDate().atZone(ZoneId.systemDefault()).toInstant())); + if (null != idToMap) { + DesignCollectionPrintElementDTO printDTO = idToMap.get(o.getId()); + d.setHasPin(printDTO.getIsPin()); + } + }); + } + + private void validateDesignType(List collectionElements, String msg) { + Boolean result = collectionElements.stream().filter(mood -> StringUtils.isEmpty(mood.getDesignType())).findFirst().isPresent(); + if (result) { + throw new BusinessException(msg + ".designType.cannot.be.empty"); + } + } + + @Override + public void editSketchBoardsElement(ValidateElementVO elementVO, List sketchBoards) { + if (CollectionUtil.isNotEmpty(sketchBoards)) { + List collect = sketchBoards.stream().filter(o -> o.getDesignType().equals(DesignTypeEnum.COLLECTION.getRealName())).collect(Collectors.toList()); + collect.forEach(sketchBoard -> { + CollectionElement collectionElement = CopyUtil.copyObject(sketchBoard, CollectionElement.class); + collectionElement.setHasPin(sketchBoard.getIsPin()); + collectionElement.setId(sketchBoard.getSketchBoardId()); + collectionElementMapper.updateById(collectionElement); + }); + List sketchBoardIds = collect.stream().map(CollectionSketchDTO::getSketchBoardId).collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(sketchBoardIds)) { + List sketchBoardElements = collectionElementMapper.selectBatchIds(sketchBoardIds); + elementVO.setSketchBoardElements(sketchBoardElements); + }else { + elementVO.setSketchBoardElements(new ArrayList<>()); + } + } + } + + @Override + public void editPrintBoardsElement(ValidateElementVO elementVO, List printBoards) { + if (CollectionUtil.isNotEmpty(printBoards)) { + List collect = printBoards.stream().filter(o -> o.getDesignType().equals(DesignTypeEnum.COLLECTION.getRealName())).collect(Collectors.toList()); + collect.forEach(printBoard -> { + CollectionElement collectionElement = CopyUtil.copyObject(printBoard, CollectionElement.class); + collectionElement.setHasPin(Objects.isNull(printBoard.getIsPin()) ? 0 : printBoard.getIsPin()); + collectionElement.setId(printBoard.getId()); + collectionElementMapper.updateById(collectionElement); + }); + List printBoardIds = collect.stream().map(DesignCollectionPrintElementDTO::getId).collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(printBoardIds)) { + List printBoardElements = collectionElementMapper.selectBatchIds(printBoardIds); + elementVO.setPrintBoardElements(printBoardElements); + }else { + elementVO.setPrintBoardElements(new ArrayList<>()); + } + } + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void relationCollection(List elementIds, Long collectionId) { + if (CollectionUtils.isEmpty(elementIds) || null == collectionId) { + return; + } + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.lambda().in(CollectionElement::getId, elementIds); + CollectionElement element = new CollectionElement(); + element.setCollectionId(collectionId); + //批量关联 + collectionElementMapper.update(element, queryWrapper); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public List saveColorBoard(List colorBoards, Long collectionId, String timeZone) { + //用户信息 + AuthPrincipalVo userInfo = UserContext.getUserHolder(); + List colorElements = resolveColorData(colorBoards, userInfo, collectionId, timeZone); + if (!this.saveBatch(colorElements)) { + throw new BusinessException("batch.save.colorElements.failed"); + } + return CopyUtil.copyList(colorElements, CollectionElementVO.class); + } + + @Override + public void refreshHistoryData() { + //幂等 + if (!CollectionUtils.isEmpty(tCollectionElementRelationService.getByCollectionId(1083L))) { + return; + } + // 分页数据 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.orderByAsc("id"); + PageQueryBaseVo pageQuery = new PageQueryBaseVo(); + pageQuery.setPage(1); + pageQuery.setSize(200); + while (true) { + IPage page = getBaseMapper().selectPage( + new Page<>(pageQuery.getPage(), pageQuery.getSize()), queryWrapper); + List list = page.getRecords(); + if (CollectionUtils.isEmpty(list)) { + break; + } + + //保存 + List relations = list.stream().map(element -> + TCollectionElementRelation.builder().elementId(element.getId()) + .collectionId(element.getCollectionId()).createDate(new Date()).build()) + .collect(Collectors.toList()); + tCollectionElementRelationService.saveBatch(relations); + pageQuery.setPage(pageQuery.getPage() + 1); + log.info("refreshHistoryData###process###page###" + pageQuery.getPage()); + } + } + + private List resolveColorData(List colorBoards, AuthPrincipalVo userInfo, Long collectionId, String timeZone) { + List elements = Lists.newArrayList(); + colorBoards.forEach(color -> { + CollectionElement element = new CollectionElement(); + element.setAccountId(userInfo.getId()); + element.setCollectionId(collectionId); + if (StringUtils.isEmpty(color.getName())) { + element.setName(null); + } else { + element.setName(color.getId() + "_" + color.getName() + "_" + color.getTcx()); + } + element.setLevel1Type(CollectionLevel1TypeEnum.COLOR_BOARD.getRealName()); + element.setHasPin((byte) 0); + element.setMd5("0"); + element.setColorRgb(color.getRgbValue()); + //按时区计算 + element.setCreateDate(DateUtil.getByTimeZone(timeZone)); + if (Objects.nonNull(color.getGradient())) { + color.getGradient().setColorImg(null); + } + element.setGradientString(JSON.toJSONString(color.getGradient())); + elements.add(element); + }); + return elements; + } + + @Override + public List getByCollectionId(Long collectionId) { +// List elementIds = tCollectionElementRelationService.getByCollectionId(collectionId); +// if (CollectionUtils.isEmpty(elementIds)) { +// return null; +// } + QueryWrapper queryWrapper = new QueryWrapper<>(); +// queryWrapper.in("id", elementIds); + queryWrapper.lambda().eq(CollectionElement::getCollectionId, collectionId); + return collectionElementMapper.selectList(queryWrapper); + } + + @Override + public List getByOnlyCollectionId(Long collectionId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("collection_id", collectionId); + return collectionElementMapper.selectList(queryWrapper); + } + + private CollectionElement selectById(Long id) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("id", id); + return collectionElementMapper.selectOne(queryWrapper); + } + + private Boolean exists(Long id) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("id", id); + return collectionElementMapper.exists(queryWrapper); + } + + private boolean saveOne(CollectionElement collectionElement) { + if (collectionElementMapper.insert(collectionElement) <= 0) { + throw new BusinessException("save.collectionElement.failed"); + } + return Boolean.TRUE; + } + + @Override + public CollectionElement editLevel2Type(Long elementId, String level2Type, String designType) { + CollectionElement collectionElement = new CollectionElement(); + + if (!Objects.isNull(elementId)) { + if (!StringUtil.isNullOrEmpty(designType)){ + switch (designType){ + case "collection": + collectionElement = collectionElementMapper.selectById(elementId); + if (StringUtil.isNullOrEmpty(collectionElement.getLevel2Type()) || !(collectionElement.getLevel2Type()).equals(level2Type)) { + collectionElement.setLevel2Type(level2Type); + updateById(collectionElement); + } + break; + case "library": + Library libraryElement = libraryService.getById(elementId); + if (!Objects.isNull(libraryElement)) { + if (StringUtil.isNullOrEmpty(libraryElement.getLevel2Type()) || !(libraryElement.getLevel2Type()).equals(level2Type)){ + libraryElement.setLevel2Type(level2Type); + libraryService.updateById(libraryElement); + } + BeanUtils.copyProperties(libraryElement,collectionElement); + } + break; + } + } else { + log.error("designType cannot be empty"); + throw new BusinessException("element source type cannot be empty!"); + } + }else { + return null; + } + return collectionElement; + } + + private Generate setGenerate(Long userId,String timeZone){ + Generate generate = new Generate(); + generate.setAccountId(userId); + generate.setLevel1Type(CollectionLevel1TypeEnum.PRINT_BOARD.getRealName()); + generate.setGenerateType("synthesis"); +// generate.setModelName("Image Synthesis Model"); + generate.setCreateDate(DateUtil.getByTimeZone(timeZone)); + return generate; + } + + private GenerateDetail setGenerateDetail(Long generateId, String url, String timeZone){ + GenerateDetail generateDetail = new GenerateDetail(); + generateDetail.setGenerateId(generateId); + generateDetail.setUrl(url); + String md5; + try { + md5 = MD5Utils.encryptFile(minioUtil.download(url)); + } catch (Exception e){ + throw new RuntimeException(e); + }/*catch (MinioException | IOException e) { + throw new RuntimeException(e); + }*/ + // 通过MD5来确认当前图片是否有被like过,避免重复like + List> libraryIds = generateDetailMapper.getLibraryIdThroughMD5(md5, CollectionLevel1TypeEnum.PRINT_BOARD.getRealName()); + if (libraryIds.isEmpty()){ + generateDetail.setIsLike((byte) 0); + }else { + generateDetail.setIsLike((byte) 1); + generateDetail.setLibraryId(libraryIds.get(0).get("library_id")); + } + generateDetail.setMd5(md5); + generateDetail.setCreateDate(LocalDateTime.now()); + + return generateDetail; + } + + // 对于上传图片或者从library选择的图片进行图片分割 + public List selectedImageSeg(List files, Long id, String type) { + Long accountId = UserContext.getUserHolder().getId(); + List resp = new ArrayList<>(); + List imageDates = new ArrayList<>(); + + boolean isUploadMode = !files.isEmpty(); + Library library = null; + + // 判断是否是上传的图片 + if (isUploadMode) { + String objectName = accountId + "/ImageSegment/input"; + for (MultipartFile file : files) { + String md5 = MD5Utils.encryptFile(file); + String segmentedResult = redisUtil.getFromString(RedisUtil.IMAGE_SEGMENTATION + md5); + // 判断上传的图片是否有已分割的数据 + if (StringUtil.isNullOrEmpty(segmentedResult)) { + String path = minioUtil.upload(userBucketName, objectName, file); + ImageSegmentation.ImageDate imageDate = new ImageSegmentation().new ImageDate(); + imageDate.setImage_url(path); + imageDate.setImage_type(type); + imageDates.add(imageDate); + } else { + ImageSegmentation.ImageDate imageData = JSONObject.parseObject(segmentedResult, ImageSegmentation.ImageDate.class); + resp.add(createCollectionElementVO(accountId, null, null, imageData.getImage_url(), imageData.getClothing_url())); + } + } + } else if (Objects.nonNull(id)) { + library = libraryService.getById(id); + // 判断从library中选择的图片是否有分割数据 + if (Objects.isNull(library)) { + throw new BusinessException("library.not.found"); + } + if (StringUtil.isNullOrEmpty(library.getSegmentedData())) { + ImageSegmentation.ImageDate imageDate = new ImageSegmentation().new ImageDate(); + imageDate.setImage_url(library.getUrl()); + imageDate.setImage_type(type); + imageDates.add(imageDate); + } else { + List restoredList = Arrays.asList(library.getSegmentedData().split(",")); + resp.add(createCollectionElementVO(accountId, id, library.getLevel1Type(), library.getUrl(), restoredList)); + } + } + + // 处理需要分割的图片 + if (!imageDates.isEmpty()) { + // 准备图片分割的参数 + ImageSegmentation imageSegmentation = new ImageSegmentation(); + imageSegmentation.setUser_id(accountId); + imageSegmentation.setImage_data(imageDates); + // 图片分割 + List segmented = pythonService.imageSegmentation(imageSegmentation); + // 处理图片分割结果 + for (ImageSegmentation.ImageDate imageData : segmented) { + if (isUploadMode) { + // 上传的图片需要添加到redis中存一天 + String key = RedisUtil.IMAGE_SEGMENTATION + + MD5Utils.encryptFile + (minioUtil.getPreSignedUrl + (imageData.getImage_url(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME), false); + redisUtil.addToString(key, new Gson().toJson(imageData), CommonConstant.GENERATE_RESULT_EXPIRE_TIME); + resp.add(createCollectionElementVO(accountId, null, null, imageData.getImage_url(), imageData.getClothing_url())); + } else { + // 从library中选择的图片需要更新数据库中对应图片的分割数据 + String segmentedData = String.join(",", imageData.getClothing_url()); + library.setSegmentedData(segmentedData); + library.setUpdateDate(new Date()); + libraryService.updateById(library); + resp.add(createCollectionElementVO(accountId, id, library.getLevel1Type(), library.getUrl(), imageData.getClothing_url())); + } + } + } + return resp; + } + + // 准备返回数据 + private CollectionElementVO createCollectionElementVO(Long accountId, Long id, String level1Type, + String imageUrl, List clothingUrls) { + CollectionElementVO vo = new CollectionElementVO(); + vo.setAccountId(accountId); + vo.setId(id); + vo.setLevel1Type(level1Type); + vo.setUrl(minioUtil.getPreSignedUrl(imageUrl, CommonConstant.MINIO_IMAGE_EXPIRE_TIME)); + vo.setMinIOPath(imageUrl); + + List segUrls = new ArrayList<>(); + for (String seg : clothingUrls) { + segUrls.add(minioUtil.getPreSignedUrl(seg, CommonConstant.MINIO_IMAGE_EXPIRE_TIME)); + } + vo.setSegmentedImages(segUrls); + return vo; + } + +} diff --git a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java index d0446c0a..c83907f0 100644 --- a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java @@ -1396,7 +1396,8 @@ public class StripeServiceImpl implements StripeService { PromotionCode promotionCode = createPromotionCode(coupon.getId(), createCouponDTO.getMaxRedemptions()); // 3、落库 ProductCoupons productCoupons = new ProductCoupons(coupon.getId(), createCouponDTO.getTimestamp(), promotionCode.getId(), - promotionCode.getCode(), createCouponDTO.getMaxRedemptions(), createCouponDTO.getPercentOff(), createCouponDTO.getCommissionRate()); + promotionCode.getCode(), createCouponDTO.getMaxRedemptions(), createCouponDTO.getPercentOff(), + createCouponDTO.getCommissionRate(), createCouponDTO.getCooperator(), createCouponDTO.getRemark()); productCoupons.setCreateTime(LocalDateTime.now()); productCouponsMapper.insert(productCoupons); @@ -1422,6 +1423,31 @@ public class StripeServiceImpl implements StripeService { } } + public ProductCoupons updateCouponsInfo(Long id, Long paidCommission, String cooperator, String remark){ + ProductCoupons productCoupons = productCouponsMapper.selectById(id); + if (Objects.isNull(productCoupons)){ + throw new BusinessException("Unknown Promotion Code"); + } + boolean flag = false; + if (!StringUtil.isNullOrEmpty(cooperator)){ + productCoupons.setCooperator(cooperator); + flag = true; + } + if (!StringUtil.isNullOrEmpty(remark)){ + productCoupons.setRemark(remark); + flag = true; + } + if (Objects.nonNull(paidCommission)){ + productCoupons.setPaidCommission(paidCommission); + flag = true; + } + if (flag){ + productCoupons.setUpdateTime(LocalDateTime.now()); + productCouponsMapper.updateById(productCoupons); + } + return productCoupons; + } + public ProductCoupons checkProductCoupon(String promotionCode){ Stripe.apiKey = privateKey; Long accountId = UserContext.getUserHolder().getId(); From c7b46229b5a37be7337ede8c2cd09fe96cc7d659 Mon Sep 17 00:00:00 2001 From: xupei Date: Mon, 28 Apr 2025 14:56:13 +0800 Subject: [PATCH 15/32] =?UTF-8?q?=E5=88=A0=E9=99=A4=E4=BC=98=E6=83=A0?= =?UTF-8?q?=E5=88=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 58af5c557059fbd95d7cfc1d589c2a8cf44f8c25) --- .../ai/da/service/impl/StripeServiceImpl.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java index c83907f0..033d0f58 100644 --- a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java @@ -24,6 +24,7 @@ import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.google.gson.Gson; import com.stripe.Stripe; +import com.stripe.exception.InvalidRequestException; import com.stripe.exception.SignatureVerificationException; import com.stripe.exception.StripeException; import com.stripe.model.*; @@ -1148,6 +1149,13 @@ public class StripeServiceImpl implements StripeService { emailParamsDTO.setFailMessage(orderByOrderNo.getNote()); emailParamsDTO.setSubscriptionType(subscriptionInfo.getType()); emailParamsDTO.setStartDate(DateUtil.changeTimeStampFormat(orderByOrderNo.getCreateTime())); + if (subscriptionInfo.getType().equals("month")){ + emailParamsDTO.setRenewalFee(String.valueOf(500)); + } else if (subscriptionInfo.getType().equals("year")){ + emailParamsDTO.setRenewalFee(String.valueOf(5000)); + } else { + emailParamsDTO.setRenewalFee(emailParamsDTO.getTotalFee()); + } if (subscriptionInfo.getStatus().equals("active")){ if (language.equals("ENGLISH")){ emailParamsDTO.setEndDate("When cancelled"); @@ -1385,6 +1393,7 @@ public class StripeServiceImpl implements StripeService { CouponCreateParams.Builder couponParams = CouponCreateParams.builder() // 任何客户只能用一次这个优惠券 .setDuration(CouponCreateParams.Duration.ONCE) + // percent_off 与 amount_off 不能同时设置 .setPercentOff(BigDecimal.valueOf(createCouponDTO.getPercentOff())); if (Objects.nonNull(createCouponDTO.getTimestamp())){ couponParams.setRedeemBy(createCouponDTO.getTimestamp()); @@ -1582,4 +1591,22 @@ public class StripeServiceImpl implements StripeService { return productCouponsMapper.selectPage(new Page<>(queryCouponsPageDTO.getPage(), queryCouponsPageDTO.getSize()), queryWrapper); } + + @Transactional + public void deleteCoupon(Long id){ + Stripe.apiKey = privateKey; + ProductCoupons productCoupons = productCouponsMapper.selectById(id); + if (Objects.isNull(productCoupons)){ + throw new BusinessException("unknown promotion code"); + } + try { + Coupon coupon = Coupon.retrieve(productCoupons.getCouponId()); + coupon.delete(); + log.info("coupon {} 删除成功", productCoupons.getCouponId()); + productCouponsMapper.deleteById(id); + } catch (StripeException e) { + log.error("未知coupons,无法通过couponId: {} 获得Coupons", productCoupons.getCouponId()); + } + } + } From 31bb29f2fdf3c98eab491d4ff45eafe482e02d81 Mon Sep 17 00:00:00 2001 From: xupei Date: Mon, 28 Apr 2025 14:40:42 +0800 Subject: [PATCH 16/32] =?UTF-8?q?Affiliate=20=E5=85=81=E8=AE=B8=E4=B8=BA?= =?UTF-8?q?=E4=B8=8D=E5=90=8C=E7=9A=84=E7=94=A8=E6=88=B7=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E4=B8=8D=E5=90=8C=E7=9A=84affiliate=20Stripe=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E4=BC=98=E6=83=A0=E5=88=B8=E5=88=A0=E9=99=A4=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=EF=BC=9B=E9=99=90=E5=88=B6=E4=BC=98=E6=83=A0=E5=88=B8?= =?UTF-8?q?=E5=8F=AA=E8=83=BD=E5=9C=A8=E8=AE=A2=E9=98=85=E6=97=B6=E4=BD=BF?= =?UTF-8?q?=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 200c0adfba26b83395686581e374e542a8b59b99) --- .../ai/da/controller/AffiliateController.java | 13 ++++++++-- .../ai/da/controller/StripeController.java | 8 ++++++ .../da/mapper/primary/entity/Affiliate.java | 2 ++ .../mapper/primary/entity/ProductCoupons.java | 5 ++++ .../model/dto/SubscriptionEmailParamsDTO.java | 2 ++ .../com/ai/da/service/AffiliateService.java | 4 ++- .../java/com/ai/da/service/StripeService.java | 2 ++ .../da/service/impl/AffiliateServiceImpl.java | 25 ++++++++++++++++--- .../ai/da/service/impl/StripeServiceImpl.java | 23 +++++++++-------- 9 files changed, 68 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/ai/da/controller/AffiliateController.java b/src/main/java/com/ai/da/controller/AffiliateController.java index 004bc6e7..7b1b63f3 100644 --- a/src/main/java/com/ai/da/controller/AffiliateController.java +++ b/src/main/java/com/ai/da/controller/AffiliateController.java @@ -51,8 +51,17 @@ public class AffiliateController { @ApiOperation(value = "审批affiliate申请") @GetMapping("/approval") - public Response applicationApproval(@RequestParam("id") Long id, @RequestParam("isApproved")Boolean isApproved) { - return Response.success(affiliateService.applicationApproval(id, isApproved)); + public Response applicationApproval(@RequestParam("id") Long id, + @RequestParam("isApproved")Boolean isApproved, + @RequestParam("commission") Float commission) { + return Response.success(affiliateService.applicationApproval(id, isApproved, commission)); + } + + @ApiOperation(value = "更新佣金比例") + @GetMapping("/updateCommission") + public Response updateCommissionPercentage(@RequestParam("id") Long id, @RequestParam("commission") Float commission) { + affiliateService.updateCommissionPercentage(id, commission); + return Response.success("success"); } /*@ApiOperation(value = "定时计算佣金") diff --git a/src/main/java/com/ai/da/controller/StripeController.java b/src/main/java/com/ai/da/controller/StripeController.java index 261777ae..e02a1765 100644 --- a/src/main/java/com/ai/da/controller/StripeController.java +++ b/src/main/java/com/ai/da/controller/StripeController.java @@ -141,6 +141,14 @@ public class StripeController { @RequestParam(required = false) String cooperator, @RequestParam(required = false) String remark){ return Response.success(stripeService.updateCouponsInfo(id, paidCommission, cooperator, remark)); } + + @ApiOperation("删除推广码") + @GetMapping("/deletePromCode") + public Response deleteCoupon(@RequestParam Long id){ + stripeService.deleteCoupon(id); + return Response.success("success"); + } + /*@ApiOperation("临时 取消订阅") @GetMapping("/cancelSubscriptionTemp") public Response cancelSubscriptionTemp(@RequestParam String subscriptionId) { diff --git a/src/main/java/com/ai/da/mapper/primary/entity/Affiliate.java b/src/main/java/com/ai/da/mapper/primary/entity/Affiliate.java index beb52662..5b9b42d4 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/Affiliate.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/Affiliate.java @@ -14,6 +14,8 @@ public class Affiliate extends BaseEntity{ // Active(活跃) || Inactive(过期) || Pending(待审批) || Refused(拒绝) private String status; + private Float commissionPercent; + private Float totalEarnings = 0.00F; private Float monthlyEarnings = 0.00F; diff --git a/src/main/java/com/ai/da/mapper/primary/entity/ProductCoupons.java b/src/main/java/com/ai/da/mapper/primary/entity/ProductCoupons.java index 2ffe97fb..88c9ed18 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/ProductCoupons.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/ProductCoupons.java @@ -1,5 +1,7 @@ package com.ai.da.mapper.primary.entity; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableLogic; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import lombok.EqualsAndHashCode; @@ -37,6 +39,9 @@ public class ProductCoupons extends BaseEntity{ // 备注 private String remark; + @TableLogic + private Integer isDeleted; + public ProductCoupons(String couponId, Long redeemBy, String promotionCodeId, String promotionCode, Long maxRedemptions, float percentOff, float commissionRate, String cooperator, String remark) { this.couponId = couponId; this.redeemBy = redeemBy; diff --git a/src/main/java/com/ai/da/model/dto/SubscriptionEmailParamsDTO.java b/src/main/java/com/ai/da/model/dto/SubscriptionEmailParamsDTO.java index 43a2d3af..0e8ef223 100644 --- a/src/main/java/com/ai/da/model/dto/SubscriptionEmailParamsDTO.java +++ b/src/main/java/com/ai/da/model/dto/SubscriptionEmailParamsDTO.java @@ -22,6 +22,8 @@ public class SubscriptionEmailParamsDTO { // 费用 private String totalFee; + private String renewalFee; + // 当前订阅开始时间 private String lastOrderDate; diff --git a/src/main/java/com/ai/da/service/AffiliateService.java b/src/main/java/com/ai/da/service/AffiliateService.java index a083e9d2..e34a172b 100644 --- a/src/main/java/com/ai/da/service/AffiliateService.java +++ b/src/main/java/com/ai/da/service/AffiliateService.java @@ -18,7 +18,9 @@ public interface AffiliateService extends IService { double[] getPersonalMonthlyIncome(int year); - Boolean applicationApproval(Long id, Boolean isApproved); + Boolean applicationApproval(Long id, Boolean isApproved, Float commission); + + void updateCommissionPercentage(Long id, Float commission); void updateAffiliateInfoWithPayment(); diff --git a/src/main/java/com/ai/da/service/StripeService.java b/src/main/java/com/ai/da/service/StripeService.java index 7769fa66..7087ca1a 100644 --- a/src/main/java/com/ai/da/service/StripeService.java +++ b/src/main/java/com/ai/da/service/StripeService.java @@ -70,4 +70,6 @@ public interface StripeService { String retrievePromotionCode(String promotionCode); IPage getAllCoupons(QueryCouponsPageDTO queryCouponsPageDTO); + + void deleteCoupon(Long id); } diff --git a/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java b/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java index c88251ae..ca3b87cc 100644 --- a/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java @@ -147,7 +147,7 @@ public class AffiliateServiceImpl extends ServiceImpl 0){ - // 分配新用户首次订阅所付费用的25%作为佣金 - BigDecimal commission = BigDecimal.valueOf(payerTotal).multiply(new BigDecimal("0.25")); + // 分配新用户首次订阅所付费用 预设的佣金比例 作为佣金 + BigDecimal commission = BigDecimal.valueOf(payerTotal).multiply(BigDecimal.valueOf(affiliate.getCommissionPercent() / 100)); BigDecimal monthlyEarning = BigDecimal.valueOf(affiliate.getMonthlyEarnings()).add(commission); BigDecimal unpaidEarnings = BigDecimal.valueOf(affiliate.getUnpaidEarnings()).add(commission); int visits = affiliate.getVisits() + 1; diff --git a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java index 033d0f58..af149f35 100644 --- a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java @@ -117,6 +117,16 @@ public class StripeServiceImpl implements StripeService { default: throw new BusinessException("unknown subscription type"); } + + // 添加优惠券(只允许在订阅时使用优惠券) + String promotionCode = productPurchaseDTO.getPromotionCode(); + if (!StringUtil.isNullOrEmpty(promotionCode)){ + ProductCoupons productCoupon = checkProductCoupon(promotionCode);; + if (productCoupon != null){ + sessionBuilder.addDiscount(SessionCreateParams.Discount.builder() + .setPromotionCode(productCoupon.getPromotionCodeId()).build()); + } + } // 只有订阅时才允许使用推广码优惠 // sessionBuilder.setAllowPromotionCodes(true); break; @@ -171,16 +181,6 @@ public class StripeServiceImpl implements StripeService { .build()); sessionBuilder.putMetadata("orderId", orderId); //通过订单号关联用于检索支付信息(可选) - // 添加优惠券 - String promotionCode = productPurchaseDTO.getPromotionCode(); - if (!StringUtil.isNullOrEmpty(promotionCode)){ - ProductCoupons productCoupon = checkProductCoupon(promotionCode);; - if (productCoupon != null){ - sessionBuilder.addDiscount(SessionCreateParams.Discount.builder() - .setPromotionCode(productCoupon.getPromotionCodeId()).build()); - } - } - Session session = Session.create(sessionBuilder.build()); List paymentMethodTypes = session.getPaymentMethodTypes(); log.info("paymentMethodTypes: {}", paymentMethodTypes); @@ -194,6 +194,9 @@ public class StripeServiceImpl implements StripeService { return session.getUrl(); } catch (BusinessException e) { throw e; + } catch (InvalidRequestException e) { + log.info("创建会话出现异常:", e); + throw new BusinessException(e.getMessage().substring(0, e.getMessage().indexOf(";"))); } catch (Exception e) { log.error("创建支付会话出现异常:", e); } From 9a81fb7ee4fc52e6838460bf3eb6f2523af93e8f Mon Sep 17 00:00:00 2001 From: xupei Date: Tue, 20 May 2025 16:53:48 +0800 Subject: [PATCH 17/32] =?UTF-8?q?TASK:=E5=B0=86PromotionCode=E5=90=88?= =?UTF-8?q?=E5=B9=B6=E5=88=B0=E7=94=9F=E4=BA=A7-test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/ai/da/common/enums/ProductEnum.java | 2 +- .../java/com/ai/da/common/utils/SendEmailUtil.java | 13 ++++++++----- .../service/impl/CollectionElementServiceImpl.java | 7 ++++--- .../com/ai/da/service/impl/StripeServiceImpl.java | 8 +++++--- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/ai/da/common/enums/ProductEnum.java b/src/main/java/com/ai/da/common/enums/ProductEnum.java index 11237ffe..ec01b9c9 100644 --- a/src/main/java/com/ai/da/common/enums/ProductEnum.java +++ b/src/main/java/com/ai/da/common/enums/ProductEnum.java @@ -13,7 +13,7 @@ public enum ProductEnum { // 月度订阅 MonthlySubscription("AiDA Monthly Subscription", 500L), // 测试 - DailySubscription("AiDA Daily Subscription", 5L), + DailySubscription("AiDA Daily Subscription", 10L), ; /** diff --git a/src/main/java/com/ai/da/common/utils/SendEmailUtil.java b/src/main/java/com/ai/da/common/utils/SendEmailUtil.java index 877f728c..461995a5 100644 --- a/src/main/java/com/ai/da/common/utils/SendEmailUtil.java +++ b/src/main/java/com/ai/da/common/utils/SendEmailUtil.java @@ -827,9 +827,12 @@ public class SendEmailUtil { // private final static Long NEW_MERCHANT_EN = 130721L; // private final static Long NEW_USER_EN = 130722L; // private final static Long NEW_USER_CN = 130723L; - private final static Long NEW_MERCHANT_EN = 135190L; - private final static Long NEW_USER_EN = 135189L; - private final static Long NEW_USER_CN = 135186L; + private final static Long NEW_MERCHANT_EN = 140335L; +// private final static Long NEW_MERCHANT_EN = 135190L; +// private final static Long NEW_USER_EN = 135189L; +// private final static Long NEW_USER_CN = 135186L; + private final static Long NEW_USER_EN = 140316L; + private final static Long NEW_USER_CN = 140317L; private final static Long RENEWAL_MERCHANT_EN = 130724L; private final static Long RENEWAL_USER_EN = 130725L; private final static Long RENEWAL_USER_CN = 130726L; @@ -844,7 +847,7 @@ public class SendEmailUtil { try { String merchantEmail = "kimwong@code-create.com.hk"; String developer = "xupei3360@163.com"; - String[] receiverEmail = {merchantEmail, developer}; + String[] receiverEmail = {/*merchantEmail, */developer}; Credential cred = new Credential(SECRET_ID, SECRET_KEy); // 实例化一个http选项,可选的,没有特殊需求可以跳过 HttpProfile httpProfile = new HttpProfile(); @@ -1014,7 +1017,7 @@ public class SendEmailUtil { 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(new String[]{/*merchantEmail, */developerEmail}); Template template = new Template(); req.setSubject("New Credit Purchase Order"); template.setTemplateID(CREDITS_PURCHASE_MERCHANT); diff --git a/src/main/java/com/ai/da/service/impl/CollectionElementServiceImpl.java b/src/main/java/com/ai/da/service/impl/CollectionElementServiceImpl.java index 8635bca0..cd508e42 100644 --- a/src/main/java/com/ai/da/service/impl/CollectionElementServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/CollectionElementServiceImpl.java @@ -18,7 +18,7 @@ import com.ai.da.model.enums.StyleEnum; import com.ai.da.model.vo.*; import com.ai.da.python.PythonService; import com.ai.da.python.vo.DesignPythonItem; -import com.ai.da.python.vo.ImageSegmentation; +//import com.ai.da.python.vo.ImageSegmentation; import com.ai.da.service.*; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; @@ -971,7 +971,8 @@ public class CollectionElementServiceImpl extends ServiceImpl selectedImageSeg(List files, Long id, String type) { + // todo 图像分割 开发分支代码 暂时以注释形式存在 + /*public List selectedImageSeg(List files, Long id, String type) { Long accountId = UserContext.getUserHolder().getId(); List resp = new ArrayList<>(); List imageDates = new ArrayList<>(); @@ -1061,6 +1062,6 @@ public class CollectionElementServiceImpl extends ServiceImpl Date: Thu, 22 May 2025 16:37:41 +0800 Subject: [PATCH 18/32] =?UTF-8?q?TASK:=20prom=20code=20=E5=BC=80=E5=90=AF?= =?UTF-8?q?=E4=BD=A3=E9=87=91=E8=AE=A1=E8=B4=B9=E5=AE=9A=E6=97=B6=E5=99=A8?= =?UTF-8?q?=E5=92=8C=E5=95=86=E5=AE=B6=E9=82=AE=E4=BB=B6=E9=80=9A=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ai/da/common/task/PaymentTask.java | 4 ++-- src/main/java/com/ai/da/common/utils/SendEmailUtil.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ai/da/common/task/PaymentTask.java b/src/main/java/com/ai/da/common/task/PaymentTask.java index 2fdf2e76..3bf23fad 100644 --- a/src/main/java/com/ai/da/common/task/PaymentTask.java +++ b/src/main/java/com/ai/da/common/task/PaymentTask.java @@ -113,9 +113,9 @@ public class PaymentTask { } } -// @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes + @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes public void calcCouponsCommission(){ - log.info("优惠券佣金计算定时器"); +// log.info("优惠券佣金计算定时器"); affiliateService.calcCouponsCommission(); } diff --git a/src/main/java/com/ai/da/common/utils/SendEmailUtil.java b/src/main/java/com/ai/da/common/utils/SendEmailUtil.java index 461995a5..c9d4ecc3 100644 --- a/src/main/java/com/ai/da/common/utils/SendEmailUtil.java +++ b/src/main/java/com/ai/da/common/utils/SendEmailUtil.java @@ -847,7 +847,7 @@ public class SendEmailUtil { try { String merchantEmail = "kimwong@code-create.com.hk"; String developer = "xupei3360@163.com"; - String[] receiverEmail = {/*merchantEmail, */developer}; + String[] receiverEmail = {merchantEmail, developer}; Credential cred = new Credential(SECRET_ID, SECRET_KEy); // 实例化一个http选项,可选的,没有特殊需求可以跳过 HttpProfile httpProfile = new HttpProfile(); @@ -1017,7 +1017,7 @@ public class SendEmailUtil { 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(new String[]{merchantEmail, developerEmail}); Template template = new Template(); req.setSubject("New Credit Purchase Order"); template.setTemplateID(CREDITS_PURCHASE_MERCHANT); From 5c66ece467b547f40c482c12c718f1eaf9ecede6 Mon Sep 17 00:00:00 2001 From: xupei Date: Fri, 23 May 2025 17:16:19 +0800 Subject: [PATCH 19/32] =?UTF-8?q?1.=E5=85=B3=E9=97=AD=E7=BB=AD=E8=AE=A2?= =?UTF-8?q?=E5=89=8D=E4=B8=83=E5=A4=A9=E9=82=AE=E4=BB=B6=E6=8F=90=E9=86=92?= =?UTF-8?q?=202.=E4=BC=98=E5=8C=96=E8=AE=A2=E9=98=85=E9=82=AE=E4=BB=B6?= =?UTF-8?q?=E6=8F=90=E9=86=92=EF=BC=8C=E5=90=91redis=E5=AD=98=E5=82=A8?= =?UTF-8?q?=E5=B7=B2=E5=8F=91=E9=80=81=E7=9A=84=E9=82=AE=E4=BB=B6=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ai/da/common/constant/CommonConstant.java | 2 + .../com/ai/da/common/task/PaymentTask.java | 5 +- .../com/ai/da/common/utils/RedisUtil.java | 5 +- .../da/service/impl/AffiliateServiceImpl.java | 10 ++-- .../da/service/impl/GenerateServiceImpl.java | 2 +- .../service/impl/PaymentInfoServiceImpl.java | 1 + .../ai/da/service/impl/StripeServiceImpl.java | 55 ++++++++++++------- 7 files changed, 51 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/ai/da/common/constant/CommonConstant.java b/src/main/java/com/ai/da/common/constant/CommonConstant.java index 35ff4504..43c2c99b 100644 --- a/src/main/java/com/ai/da/common/constant/CommonConstant.java +++ b/src/main/java/com/ai/da/common/constant/CommonConstant.java @@ -13,6 +13,8 @@ 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; public static class Numbers{ public static final Integer NUMBER_10 = 10; diff --git a/src/main/java/com/ai/da/common/task/PaymentTask.java b/src/main/java/com/ai/da/common/task/PaymentTask.java index 3bf23fad..975e039d 100644 --- a/src/main/java/com/ai/da/common/task/PaymentTask.java +++ b/src/main/java/com/ai/da/common/task/PaymentTask.java @@ -84,8 +84,9 @@ public class PaymentTask { }*/ } + // !!关闭此定时器,改为提前三天站内信提醒!! // 提前7天向用户发送提醒邮件,每天早上8点执行 - @Scheduled(cron = "0 0 8 * * ?") +// @Scheduled(cron = "0 0 8 * * ?") public void subscriptionReminder(){ stripeService.subscriptionReminder(); } @@ -113,7 +114,7 @@ public class PaymentTask { } } - @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes + @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes public void calcCouponsCommission(){ // log.info("优惠券佣金计算定时器"); affiliateService.calcCouponsCommission(); diff --git a/src/main/java/com/ai/da/common/utils/RedisUtil.java b/src/main/java/com/ai/da/common/utils/RedisUtil.java index f7b9ea1a..f8f1e6ec 100644 --- a/src/main/java/com/ai/da/common/utils/RedisUtil.java +++ b/src/main/java/com/ai/da/common/utils/RedisUtil.java @@ -84,8 +84,10 @@ public class RedisUtil { /** * 将数据放入set缓存 */ - public void addToSet(String key, String value) { + public void addToSet(String key, String value, Long expiresIn) { redisTemplate.opsForSet().add(key, value); + // 设置过期时间 + redisTemplate.expire(key, expiresIn, TimeUnit.SECONDS); } /** @@ -302,4 +304,5 @@ public class RedisUtil { } public final static String STRIPE_EXCEPTION_LOG = "StripeException:"; + public final static String SUBSCRIPTION_SENT_EMAIL_TYPE = "SubscriptionEmailSentType:"; } diff --git a/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java b/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java index ca3b87cc..141b3f54 100644 --- a/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java @@ -343,17 +343,19 @@ public class AffiliateServiceImpl extends ServiceImpl queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("trade_state","paid") + .lt("create_time", currentTime) + .isNotNull("promotion_code"); if (!StringUtil.isNullOrEmpty(lastTime)){ - queryWrapper.gt("create_time", lastTime) - .lt("create_time", currentTime) - .isNotNull("promotion_code"); + queryWrapper.gt("create_time", lastTime); } List paymentInfos = paymentInfoService.getBaseMapper().selectList(queryWrapper); + log.info("目前,新增使用优惠券的订单数:{}", paymentInfos.size()); // key:推广码, value:用户支付的金额 HashMap codeAmount = new HashMap<>(); diff --git a/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java b/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java index b96d04b0..65cab899 100644 --- a/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java @@ -701,7 +701,7 @@ public class GenerateServiceImpl extends ServiceImpl i // todo 取消待优化 uniqueIdList.forEach(uniqueId -> { // 1、将需要取消的唯一id加入redis,以便及时取消生成 - redisUtil.addToSet(cancelSetKey, uniqueId); + redisUtil.addToSet(cancelSetKey, uniqueId, CommonConstant.REDIS_SET_EXPIRE_TIME); /*// 1、确认当前消息是否还在排队中 Boolean exists = redisUtil.isElementExistsInZSet(consumptionOrderKey, uniqueId); diff --git a/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java b/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java index d85d3725..fcc7eba5 100644 --- a/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java @@ -310,6 +310,7 @@ public class PaymentInfoServiceImpl extends ServiceImpl qw = new QueryWrapper<>(); + // todo 首次支付失败,没有invoiceId,所以如果这个order之后成功支付后,会有多条paymentInfo 是否需要优化?? qw.eq("transaction_id", charge.getInvoice()); PaymentInfo paymentInfo = baseMapper.selectOne(qw); Charge.PaymentMethodDetails paymentMethodDetails = charge.getPaymentMethodDetails(); diff --git a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java index 2c26914b..e9611ca7 100644 --- a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java @@ -5,6 +5,7 @@ import com.ai.da.common.constant.CommonConstant; import com.ai.da.common.context.UserContext; import com.ai.da.common.enums.*; import com.ai.da.common.utils.DateUtil; +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.PaymentInfoMapper; @@ -67,7 +68,6 @@ public class StripeServiceImpl implements StripeService { private RefundInfoService refundInfoService; @Resource private AccountService accountService; - @Resource private AccountMapper accountMapper; @Resource @@ -76,6 +76,8 @@ public class StripeServiceImpl implements StripeService { private PaymentInfoMapper paymentInfoMapper; @Resource private ProductCouponsMapper productCouponsMapper; + @Resource + private RedisUtil redisUtil; @Value("${stripe.private-key}") private String privateKey; @@ -368,28 +370,31 @@ public class StripeServiceImpl implements StripeService { // 新增支付成功的信息,返回orderNo,表示,该回调第一次被记录 PaymentInfo paymentInfo = paymentInfoService.createOrUpdatePaymentInfoForStripe(invoice); + /* 在sendEmail方法中有做判断,这里的判断取消 // 当前支付没有被通知时才需要发送通知邮件 if (paymentInfo.getNotified().equals(0)) { - // 更新t_order_info中的total_fee,记录该订单的累计付款金额 - orderInfoService.updateTotalFeeByOrderNo(paymentInfo.getOrderNo()); - // 邮件通知商家和用户 - String billingReason = invoice.getBillingReason(); - switch (billingReason) { - case "subscription_create": - response = sendEmail(invoice.getSubscription(), "new", null); - break; - case "subscription_cycle": - response = sendEmail(invoice.getSubscription(), "renewal", null); - break; - case "manual": - boolean b = invoice.getLines().getData().get(0).getDescription().endsWith("Subscription"); - if (b) { - // 非自动续订式订阅,Stripe不会创建Subscription,所以invoice中不会有subscriptionId - response = sendEmail(null, "new", paymentInfo.getOrderNo()); - } - break; - } + + }*/ + // 更新t_order_info中的total_fee,记录该订单的累计付款金额 + orderInfoService.updateTotalFeeByOrderNo(paymentInfo.getOrderNo()); + // 邮件通知商家和用户 + String billingReason = invoice.getBillingReason(); + switch (billingReason) { + case "subscription_create": + response = sendEmail(invoice.getSubscription(), "new", null); + break; + case "subscription_cycle": + response = sendEmail(invoice.getSubscription(), "renewal", null); + break; + case "manual": + boolean b = invoice.getLines().getData().get(0).getDescription().endsWith("Subscription"); + if (b) { + // 非自动续订式订阅,Stripe不会创建Subscription,所以invoice中不会有subscriptionId + response = sendEmail(null, "new", paymentInfo.getOrderNo()); + } + break; } + } else if (event.getType().equals("invoice.payment_failed")) { // 更新支付信息 QueryWrapper queryWrapper = new QueryWrapper<>(); @@ -1011,7 +1016,12 @@ public class StripeServiceImpl implements StripeService { // (其实这里也可以通过invoiceId查询stripe,但是记录在自己的db中可以不用每次都查,且方便查看) type = StringUtil.isNullOrEmpty(paymentInfo.getType()) ? "new" : paymentInfo.getType(); } - if (!type.equals("reminder") && !type.equals("cancel") && paymentInfo.getNotified() == 1){ + + // todo 之后这种改成通过email-log来判断 + String key = RedisUtil.SUBSCRIPTION_SENT_EMAIL_TYPE + subscriptionInfo.getId(); + // 先判断当前订单 这个类型的邮件是否已发送过 + Boolean elementExistsInSet = redisUtil.isElementExistsInSet(key, type); + if (!type.equals("reminder") && !type.equals("cancel") && paymentInfo.getNotified() == 1 && elementExistsInSet){ // 已经邮件通知过,直接返回 log.info("不发送邮件,原因:【type为:{},order_no为:{},已经进行邮件通知】", type, orderNo); return true; @@ -1044,6 +1054,9 @@ public class StripeServiceImpl implements StripeService { payment.setUpdateTime(LocalDateTime.now()); paymentInfoMapper.updateById(payment); } + + // 将发成功的邮件类型存入redis 避免同一个订阅重复发送相同类型的邮件 subId:type + redisUtil.addToSet(key, type, CommonConstant.REDIS_SET_EXPIRE_TIME); return true; } From b445f1f11e9e1173e97cb12e315c0370c7ddfe4d Mon Sep 17 00:00:00 2001 From: xupei Date: Wed, 4 Jun 2025 15:49:55 +0800 Subject: [PATCH 20/32] =?UTF-8?q?BUGFIX:=20modifySketch=20=E5=9C=A8library?= =?UTF-8?q?=E4=B8=AD=E4=BF=AE=E6=94=B9=E5=90=8E=E9=9C=80=E8=A6=81=E4=BF=9D?= =?UTF-8?q?=E5=AD=98=E5=88=B0library?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ai/da/mapper/primary/entity/Library.java | 14 +++ .../ai/da/model/dto/GenerateModifyDTO.java | 5 +- .../da/service/impl/GenerateServiceImpl.java | 100 +++++++++++++----- 3 files changed, 94 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/ai/da/mapper/primary/entity/Library.java b/src/main/java/com/ai/da/mapper/primary/entity/Library.java index cc5250a4..3ccb4fab 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/Library.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/Library.java @@ -80,4 +80,18 @@ public class Library implements Serializable { private Date updateDate; // private Integer isCopy; + + + public Library() { + } + + public Library(Long accountId, String level1Type, String level2Type, String level3Type, String url, String md5, Date createDate) { + this.accountId = accountId; + this.level1Type = level1Type; + this.level2Type = level2Type; + this.level3Type = level3Type; + this.url = url; + this.md5 = md5; + this.createDate = createDate; + } } diff --git a/src/main/java/com/ai/da/model/dto/GenerateModifyDTO.java b/src/main/java/com/ai/da/model/dto/GenerateModifyDTO.java index da56be9c..1f97af3f 100644 --- a/src/main/java/com/ai/da/model/dto/GenerateModifyDTO.java +++ b/src/main/java/com/ai/da/model/dto/GenerateModifyDTO.java @@ -21,9 +21,12 @@ public class GenerateModifyDTO { @ApiModelProperty(value = "sketch所属分类", required = true) private String category; + @ApiModelProperty(value = "originalId的来源 Library || Generate(默认为空)", required = true) + private String originalIdSource; + @NotNull(message = "id cannot be empty") @ApiModelProperty(value = "原图id", required = true) - private String originalId; + private Long originalId; @ApiModelProperty("是否覆盖原图") private Boolean isOverride; diff --git a/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java b/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java index 65cab899..2ec0c181 100644 --- a/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java @@ -894,43 +894,95 @@ public class GenerateServiceImpl extends ServiceImpl i @Transactional(rollbackFor = Exception.class) public GenerateResultVO modifySketch(GenerateModifyDTO generateModifyDTO) { log.info("修改提取出的sketch,并加入到library"); + + // 提取常用参数 Long accountId = UserContext.getUserHolder().getId(); String base64 = generateModifyDTO.getBase64(); - String gender = generateModifyDTO.getGender(); + String gender = generateModifyDTO.getGender().toLowerCase(); String category = generateModifyDTO.getCategory(); + Long originalId = generateModifyDTO.getOriginalId(); + boolean isOverride = generateModifyDTO.getIsOverride(); + boolean isFromLibrary = generateModifyDTO.getOriginalIdSource().equals("Library"); - // 将base64上传到minio - String path; - GenerateDetail originalDetail = generateDetailMapper.selectById(generateModifyDTO.getOriginalId()); - Long generateDetailId = originalDetail.getId(); - if (generateModifyDTO.getIsOverride()){ - path = originalDetail.getUrl().replaceFirst("^[^/]+/", "").replaceFirst("\\.[^.]+$", ""); - }else { - path = accountId + "/sketchboard/" + gender.toLowerCase() + "/" + category + "/" + UUID.randomUUID(); + // 获取原始路径和可能的generateId + PathInfo pathInfo = getOriginalPathAndGenerateId(isFromLibrary, originalId); + + // 确定存储路径 + String storagePath = isOverride + ? pathInfo.originalPath.replaceFirst("^[^/]+/", "").replaceFirst("\\.[^.]+$", "") + : accountId + "/sketchboard/" + gender + "/" + category + "/" + UUID.randomUUID(); + + // 上传到MinIO + String minioPath = minioUtil.base64UploadToPath(base64, userBucket, storagePath); + log.info("修改后的图片:{}", minioPath); + + // 保存到数据库并返回结果 + return isFromLibrary + ? handleLibrarySave(accountId, originalId, minioPath, category, gender, isOverride) + : handleGenerateSave(originalId, pathInfo.generateId, minioPath, category, isOverride); + } + + private static class PathInfo { + String originalPath; + Long generateId; + + PathInfo(String originalPath, Long generateId) { + this.originalPath = originalPath; + this.generateId = generateId; } + } - String minioPath = minioUtil.base64UploadToPath(base64, userBucket, path); + private PathInfo getOriginalPathAndGenerateId(boolean isFromLibrary, Long originalId) { + if (isFromLibrary) { + return new PathInfo(libraryService.getById(originalId).getUrl(), null); + } else { + GenerateDetail detail = generateDetailMapper.selectById(originalId); + return new PathInfo(detail.getUrl(), detail.getGenerateId()); + } + } - log.info("修改后的图片 : {}", minioPath); + private GenerateResultVO handleLibrarySave(Long accountId, Long libraryId, String minioPath, + String category, String gender, boolean isOverride) { + Library library; + if (isOverride) { + library = new Library(); + library.setId(libraryId); + library.setUrl(minioPath); + library.setUpdateDate(new Date()); + libraryService.updateById(library); + } else { + library = new Library(accountId, "Sketchboard", category, gender, minioPath, + MD5Utils.encryptFile(minioUtil.getPreSignedUrl(minioPath, CommonConstant.MINIO_IMAGE_EXPIRE_TIME), false), + new Date()); + libraryService.save(library); + libraryId = library.getId(); + } + return buildResultVO(libraryId, minioPath, category); + } - // 存入db 保存到t_generate_detail - if (!generateModifyDTO.getIsOverride()){ - GenerateDetail generateDetail = new GenerateDetail(); - generateDetail.setGenerateId(originalDetail.getGenerateId()); + private GenerateResultVO handleGenerateSave(Long originalId, Long generateId, String minioPath, + String category, boolean isOverride) { + GenerateDetail generateDetail = new GenerateDetail(); + if (isOverride) { + generateDetail.setId(originalId); + generateDetail.setUrl(minioPath); + generateDetail.setUpdateDate(new Date()); + generateDetailMapper.updateById(generateDetail); + } else { + generateDetail.setGenerateId(generateId); generateDetail.setUrl(minioPath); generateDetail.setIsLike((byte)0); - generateDetail.setMd5(MD5Utils.encryptFile(minioUtil.getPreSignedUrl(minioPath, CommonConstant.MINIO_IMAGE_EXPIRE_TIME, true), Boolean.FALSE)); + generateDetail.setMd5(MD5Utils.encryptFile(minioUtil.getPreSignedUrl(minioPath, + CommonConstant.MINIO_IMAGE_EXPIRE_TIME, true), Boolean.FALSE)); generateDetail.setCreateDate(LocalDateTime.now()); generateDetailMapper.insert(generateDetail); - - generateDetailId = generateDetail.getId(); - }else { - GenerateDetail generateDetail = new GenerateDetail(); - generateDetail.setUrl(minioPath); - generateDetail.setId(generateDetailId); - generateDetailMapper.updateById(generateDetail); + originalId = generateDetail.getId(); } + return buildResultVO(originalId, minioPath, category); + } - return new GenerateResultVO(generateDetailId, minioUtil.getPreSignedUrl(minioPath, CommonConstant.MINIO_IMAGE_EXPIRE_TIME, true), "Success", category); + private GenerateResultVO buildResultVO(Long id, String minioPath, String category) { + String url = minioUtil.getPreSignedUrl(minioPath, CommonConstant.MINIO_IMAGE_EXPIRE_TIME, true); + return new GenerateResultVO(id, url, "Success", category); } } From 6249d53b7bc2c4ece7a82740fd5cd7381ff40b19 Mon Sep 17 00:00:00 2001 From: xupei Date: Wed, 4 Jun 2025 22:04:09 +0800 Subject: [PATCH 21/32] =?UTF-8?q?BUGFIX:=20modifySketch=20=E9=99=A4library?= =?UTF-8?q?=E4=BB=A5=E5=A4=96=E7=9A=84=E5=9C=B0=E6=96=B9=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=EF=BC=8CoriginalIdSource=E5=85=81=E8=AE=B8=E4=B8=8D=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java b/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java index 2ec0c181..34c6c9c8 100644 --- a/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java @@ -902,7 +902,8 @@ public class GenerateServiceImpl extends ServiceImpl i String category = generateModifyDTO.getCategory(); Long originalId = generateModifyDTO.getOriginalId(); boolean isOverride = generateModifyDTO.getIsOverride(); - boolean isFromLibrary = generateModifyDTO.getOriginalIdSource().equals("Library"); + boolean isFromLibrary = !StringUtil.isNullOrEmpty(generateModifyDTO.getOriginalIdSource()) + && generateModifyDTO.getOriginalIdSource().equals("Library"); // 获取原始路径和可能的generateId PathInfo pathInfo = getOriginalPathAndGenerateId(isFromLibrary, originalId); From 4b7fd649a3ad3c7865b4ecd6bce6d87f96717cf1 Mon Sep 17 00:00:00 2001 From: xupei Date: Fri, 6 Jun 2025 19:37:38 +0800 Subject: [PATCH 22/32] =?UTF-8?q?TASK:=20=E6=8E=A8=E5=B9=BF=E7=A0=81=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=BC=80=E5=A7=8B=E7=94=9F=E6=95=88=E6=97=B6?= =?UTF-8?q?=E9=97=B4;=E4=BC=98=E5=8C=96=E6=95=B0=E6=8D=AE=E8=AE=A1?= =?UTF-8?q?=E7=AE=97=E7=B1=BB=E5=9E=8B=EF=BC=8C=E4=BD=BF=E7=94=A8BigDecima?= =?UTF-8?q?l=E6=9B=BF=E6=8D=A2float;=E6=9B=B4=E6=96=B0paidCommission?= =?UTF-8?q?=E5=90=8E=E8=87=AA=E5=8A=A8=E8=AE=A1=E7=AE=97unpaidCommission?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ai/da/common/constant/CommonConstant.java | 2 + .../ai/da/controller/StripeController.java | 8 +- .../mapper/primary/entity/ProductCoupons.java | 12 ++- .../com/ai/da/model/dto/CreateCouponDTO.java | 4 +- .../com/ai/da/model/vo/CheckCouponsVO.java | 2 +- .../java/com/ai/da/service/StripeService.java | 2 +- .../da/service/impl/AffiliateServiceImpl.java | 83 ++++++++++++------- .../ai/da/service/impl/StripeServiceImpl.java | 41 +++++++-- 8 files changed, 106 insertions(+), 48 deletions(-) diff --git a/src/main/java/com/ai/da/common/constant/CommonConstant.java b/src/main/java/com/ai/da/common/constant/CommonConstant.java index 43c2c99b..85b67e36 100644 --- a/src/main/java/com/ai/da/common/constant/CommonConstant.java +++ b/src/main/java/com/ai/da/common/constant/CommonConstant.java @@ -81,5 +81,7 @@ public class CommonConstant { public static final String TIME_FORMAT_MMM_dd_yyyy = "MMM. dd, yyyy"; + public static final String TIME_FORMAT_yyyy_MM_dd_HH_mm_ss = "yyyy-MM-dd HH:mm:ss"; + public static final String AFFILIATE_LINK = "https://www.aida.com.hk?ref="; } diff --git a/src/main/java/com/ai/da/controller/StripeController.java b/src/main/java/com/ai/da/controller/StripeController.java index e02a1765..07ab7a5d 100644 --- a/src/main/java/com/ai/da/controller/StripeController.java +++ b/src/main/java/com/ai/da/controller/StripeController.java @@ -137,9 +137,11 @@ public class StripeController { @ApiOperation("更新推广码信息") @GetMapping("/updatePromCodeInfo") - public Response updateCouponsInfo(@RequestParam Long id, @RequestParam(required = false) Long paidCommission, - @RequestParam(required = false) String cooperator, @RequestParam(required = false) String remark){ - return Response.success(stripeService.updateCouponsInfo(id, paidCommission, cooperator, remark)); + public Response updateCouponsInfo(@RequestParam Long id, @RequestParam(required = false) String paidCommission, + @RequestParam(required = false) String cooperator, + @RequestParam(required = false) String remark, + @RequestParam(required = false) Long startTime){ + return Response.success(stripeService.updateCouponsInfo(id, paidCommission, cooperator, remark, startTime)); } @ApiOperation("删除推广码") diff --git a/src/main/java/com/ai/da/mapper/primary/entity/ProductCoupons.java b/src/main/java/com/ai/da/mapper/primary/entity/ProductCoupons.java index 88c9ed18..06a00810 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/ProductCoupons.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/ProductCoupons.java @@ -7,6 +7,8 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; +import java.math.BigDecimal; + @EqualsAndHashCode(callSuper = true) @Data @TableName("t_product_coupons") @@ -20,6 +22,8 @@ public class ProductCoupons extends BaseEntity{ private String promotionCodeId; // 对应的推广码 private String promotionCode; + // 优惠券有效期开始时间 + private Long startTime; // 最大兑换次数 private Long maxRedemptions; // 优惠券的折扣 @@ -29,13 +33,13 @@ public class ProductCoupons extends BaseEntity{ // 合作者 private String cooperator; // 使用了该优惠券支付的总金额 - private float totalEarnings; + private BigDecimal totalEarnings = BigDecimal.ZERO; // 佣金 - private float commission; + private BigDecimal commission = BigDecimal.ZERO; // 已付佣金 - private float paidCommission; + private BigDecimal paidCommission = BigDecimal.ZERO; // 未付佣金 - private float unpaidCommission; + private BigDecimal unpaidCommission = BigDecimal.ZERO; // 备注 private String remark; diff --git a/src/main/java/com/ai/da/model/dto/CreateCouponDTO.java b/src/main/java/com/ai/da/model/dto/CreateCouponDTO.java index 311f7c67..3e1c60b5 100644 --- a/src/main/java/com/ai/da/model/dto/CreateCouponDTO.java +++ b/src/main/java/com/ai/da/model/dto/CreateCouponDTO.java @@ -14,7 +14,9 @@ public class CreateCouponDTO { @NotNull(message = "Please set the commissionRate.") private Float commissionRate; @ApiModelProperty("推广码到期时间 秒级时间戳") - private Long timestamp; + private Long endTime; + @ApiModelProperty("推广码开始时间 秒级时间戳") + private Long startTime; @ApiModelProperty("推广码最大使用次数") private Long maxRedemptions; @ApiModelProperty("合作者/机构名") diff --git a/src/main/java/com/ai/da/model/vo/CheckCouponsVO.java b/src/main/java/com/ai/da/model/vo/CheckCouponsVO.java index 97b72d9c..dbbf2aeb 100644 --- a/src/main/java/com/ai/da/model/vo/CheckCouponsVO.java +++ b/src/main/java/com/ai/da/model/vo/CheckCouponsVO.java @@ -9,7 +9,7 @@ import lombok.NoArgsConstructor; @NoArgsConstructor public class CheckCouponsVO { - @ApiModelProperty("expired || invalid || valid") + @ApiModelProperty("expired 过期 || invalid 无效 || valid 有效 || pending 尚未生效") private String status; private String message; diff --git a/src/main/java/com/ai/da/service/StripeService.java b/src/main/java/com/ai/da/service/StripeService.java index 7087ca1a..4ab7b2b9 100644 --- a/src/main/java/com/ai/da/service/StripeService.java +++ b/src/main/java/com/ai/da/service/StripeService.java @@ -61,7 +61,7 @@ public interface StripeService { CheckCouponsVO checkProductCoupon(String promotionCode, Long price); - ProductCoupons updateCouponsInfo(Long id, Long paidCommission, String cooperator, String remark); + ProductCoupons updateCouponsInfo(Long id, String paidCommission, String cooperator, String remark, Long startTime); ProductCoupons getProductCoupon(String promotionCode, String promotionCodeId); diff --git a/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java b/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java index 141b3f54..61af2518 100644 --- a/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java @@ -31,9 +31,11 @@ import org.springframework.util.CollectionUtils; import javax.annotation.Resource; import java.math.BigDecimal; +import java.math.RoundingMode; import java.time.LocalDateTime; import java.util.*; import java.util.function.Function; +import java.util.stream.Collectors; @Service @Slf4j @@ -342,49 +344,66 @@ public class AffiliateServiceImpl extends ServiceImpl queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("trade_state","paid") + queryWrapper.eq("trade_state", "paid") .lt("create_time", currentTime) .isNotNull("promotion_code"); - if (!StringUtil.isNullOrEmpty(lastTime)){ - queryWrapper.gt("create_time", lastTime); - } - List paymentInfos = paymentInfoService.getBaseMapper().selectList(queryWrapper); + Optional.ofNullable(lastTime) + .filter(time -> !time.isEmpty()) + .ifPresent(time -> queryWrapper.gt("create_time", time)); + + List paymentInfos = paymentInfoService.list(queryWrapper); log.info("目前,新增使用优惠券的订单数:{}", paymentInfos.size()); - // key:推广码, value:用户支付的金额 - HashMap codeAmount = new HashMap<>(); - if (!paymentInfos.isEmpty()){ - for (PaymentInfo paymentInfo : paymentInfos){ - String promotionCode = paymentInfo.getPromotionCode(); - Float sum = codeAmount.get(promotionCode); - if (sum == null || sum == 0.0f){ - codeAmount.put(promotionCode, paymentInfo.getPayerTotal()); - }else { - codeAmount.put(promotionCode, sum + paymentInfo.getPayerTotal()); - } + // 2. 按推广码汇总支付金额 + Map codeAmount = paymentInfos.stream() + .collect(Collectors.toMap( + PaymentInfo::getPromotionCode, + payment -> new BigDecimal(payment.getPayerTotal()), + BigDecimal::add + )); + + // 3. 更新佣金数据 + codeAmount.forEach((promotionCode, amount) -> { + ProductCoupons coupon = stripeService.getProductCoupon(promotionCode, null); + if (coupon != null) { + updateCouponCommission(coupon, amount); + productCouponsMapper.updateById(coupon); } - for (Map.Entry entry : codeAmount.entrySet()){ - String promotionCode = entry.getKey(); - ProductCoupons productCoupons = stripeService.getProductCoupon(promotionCode, null); - if (!Objects.isNull(productCoupons)){ - // 2、计算支付金额的总和,更新totalEarnings,commission,unpaidCommission - float sum = productCoupons.getTotalEarnings() + entry.getValue(); - productCoupons.setTotalEarnings(sum); - float commission = sum * productCoupons.getCommissionRate() / 100; - productCoupons.setCommission(commission); - productCoupons.setUnpaidCommission(commission - productCoupons.getPaidCommission()); - productCouponsMapper.updateById(productCoupons); - } - } - } + }); + + // 4. 更新最后执行时间 redisUtil.addToString(RedisUtil.PAYMENT_INFO_LAST_SCAN_TIME, currentTime); } + /** + * 更新优惠券的佣金数据 + */ + private void updateCouponCommission(ProductCoupons coupon, BigDecimal newAmount) { + // 总收益 = 原收益(默认0) + 新增金额 + BigDecimal totalEarnings = Optional.ofNullable(coupon.getTotalEarnings()) + .orElse(BigDecimal.ZERO) + .add(newAmount); + coupon.setTotalEarnings(totalEarnings); + + // 佣金 = 总收益 × 佣金比例(需除以100) + BigDecimal commission = totalEarnings.multiply( + BigDecimal.valueOf(coupon.getCommissionRate()) + .divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP)); + coupon.setCommission(commission); + + // 未支付佣金 = 总佣金 - 已支付佣金(默认0) + BigDecimal unpaidCommission = commission.subtract( + Optional.ofNullable(coupon.getPaidCommission()) + .orElse(BigDecimal.ZERO)); + coupon.setUnpaidCommission(unpaidCommission); + } + } diff --git a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java index e9611ca7..32a80574 100644 --- a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java @@ -1413,8 +1413,8 @@ public class StripeServiceImpl implements StripeService { .setDuration(CouponCreateParams.Duration.ONCE) // percent_off 与 amount_off 不能同时设置 .setPercentOff(BigDecimal.valueOf(createCouponDTO.getPercentOff())); - if (Objects.nonNull(createCouponDTO.getTimestamp())){ - couponParams.setRedeemBy(createCouponDTO.getTimestamp()); + if (Objects.nonNull(createCouponDTO.getEndTime())){ + couponParams.setRedeemBy(createCouponDTO.getEndTime()); } try { // 1、创建优惠券 @@ -1422,9 +1422,10 @@ public class StripeServiceImpl implements StripeService { // 2、创建一个推广码 PromotionCode promotionCode = createPromotionCode(coupon.getId(), createCouponDTO.getMaxRedemptions()); // 3、落库 - ProductCoupons productCoupons = new ProductCoupons(coupon.getId(), createCouponDTO.getTimestamp(), promotionCode.getId(), + ProductCoupons productCoupons = new ProductCoupons(coupon.getId(), createCouponDTO.getEndTime(), promotionCode.getId(), promotionCode.getCode(), createCouponDTO.getMaxRedemptions(), createCouponDTO.getPercentOff(), createCouponDTO.getCommissionRate(), createCouponDTO.getCooperator(), createCouponDTO.getRemark()); + productCoupons.setStartTime(createCouponDTO.getStartTime()); productCoupons.setCreateTime(LocalDateTime.now()); productCouponsMapper.insert(productCoupons); @@ -1450,7 +1451,7 @@ public class StripeServiceImpl implements StripeService { } } - public ProductCoupons updateCouponsInfo(Long id, Long paidCommission, String cooperator, String remark){ + public ProductCoupons updateCouponsInfo(Long id, String paidCommission, String cooperator, String remark, Long startTime){ ProductCoupons productCoupons = productCouponsMapper.selectById(id); if (Objects.isNull(productCoupons)){ throw new BusinessException("Unknown Promotion Code"); @@ -1465,7 +1466,22 @@ public class StripeServiceImpl implements StripeService { flag = true; } if (Objects.nonNull(paidCommission)){ - productCoupons.setPaidCommission(paidCommission); + // 将 paidCommission 从 String 转换为 BigDecimal + if (!paidCommission.matches("-?\\d+(\\.\\d+)?")) { + throw new BusinessException("Invalid paidCommission value: " + paidCommission); + } + BigDecimal paidCommissionBigDecimal = new BigDecimal(paidCommission); + // 设置已支付佣金 + productCoupons.setPaidCommission(paidCommissionBigDecimal); + BigDecimal commission = Objects.isNull(productCoupons.getCommission()) ? new BigDecimal(0) : productCoupons.getCommission(); + // 计算未支付佣金 + BigDecimal unpaidCommission = commission.subtract(paidCommissionBigDecimal); + // 设置未支付佣金,确保其不为负数 + productCoupons.setUnpaidCommission(unpaidCommission.compareTo(BigDecimal.ZERO) > 0 ? unpaidCommission : BigDecimal.ZERO); + flag = true; + } + if (Objects.nonNull(startTime)){ + productCoupons.setStartTime(startTime); flag = true; } if (flag){ @@ -1478,6 +1494,7 @@ public class StripeServiceImpl implements StripeService { public ProductCoupons checkProductCoupon(String promotionCode){ Stripe.apiKey = privateKey; Long accountId = UserContext.getUserHolder().getId(); + String language = UserContext.getUserHolder().getLanguage(); // 1、从数据库查找promotionCode对应的promotionCodeId ProductCoupons productCoupons = productCouponsMapper.selectOne(new QueryWrapper().eq("promotion_code", promotionCode)); if (Objects.nonNull(productCoupons)){ @@ -1486,6 +1503,11 @@ public class StripeServiceImpl implements StripeService { Long redeemBy = productCoupons.getRedeemBy(); if (redeemBy < epochSecondNow){ throw new BusinessException("this.promotion.code.has.expired"); + } else if (Objects.nonNull(productCoupons.getStartTime()) && productCoupons.getStartTime() > epochSecondNow) { + String startTime = DateUtil.changeTimeStampFormat(productCoupons.getStartTime(), "seconds", CommonConstant.TIME_FORMAT_yyyy_MM_dd_HH_mm_ss); + String en = "This coupon will become active on " + startTime + ". Please try again then!"; + String cn = "该优惠券尚未到生效时间,请在 " + startTime + " 后使用。"; + throw new BusinessException(language.equals("ENGLISH") ? en : cn); } else { // 判断该用户是否有成功使用过这个推广码 List paymentInfoByPromCode = paymentInfoService.getPaymentInfoByPromCode(accountId, promotionCode); @@ -1507,6 +1529,7 @@ public class StripeServiceImpl implements StripeService { public CheckCouponsVO checkProductCoupon(String promotionCode, Long price){ Stripe.apiKey = privateKey; Long accountId = UserContext.getUserHolder().getId(); + String language = UserContext.getUserHolder().getLanguage(); CheckCouponsVO checkCouponsVO = new CheckCouponsVO(); // 1、从数据库查找promotionCode对应的promotionCodeId ProductCoupons productCoupons = productCouponsMapper.selectOne(new QueryWrapper().eq("promotion_code", promotionCode)); @@ -1518,7 +1541,13 @@ public class StripeServiceImpl implements StripeService { String msg = BusinessException.getMessageFromResource("this.promotion.code.has.expired"); checkCouponsVO.setMessage(msg); checkCouponsVO.setStatus("expired"); - }else { + }else if (Objects.nonNull(productCoupons.getStartTime()) && productCoupons.getStartTime() > epochSecondNow) { + String startTime = DateUtil.changeTimeStampFormat(productCoupons.getStartTime(), "seconds", CommonConstant.TIME_FORMAT_yyyy_MM_dd_HH_mm_ss); + String en = "This coupon will become active on " + startTime + ". Please try again then!"; + String cn = "该优惠券尚未到生效时间,请在 " + startTime + " 后使用。"; + checkCouponsVO.setMessage(language.equals("ENGLISH") ? en : cn); + checkCouponsVO.setStatus("pending"); + } else { // 判断该用户是否有成功使用过这个推广码 List paymentInfoByPromCode = paymentInfoService.getPaymentInfoByPromCode(accountId, promotionCode); if (paymentInfoByPromCode.isEmpty()) { From d5cf4e9d3f0da1f13222473df3994d7211d11046 Mon Sep 17 00:00:00 2001 From: xupei Date: Sun, 8 Jun 2025 09:19:36 +0800 Subject: [PATCH 23/32] =?UTF-8?q?TASK:=20=E6=B7=BB=E5=8A=A0=E2=80=9C?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=AF=95=E7=94=A8=E7=94=A8=E6=88=B7=E2=80=9D?= =?UTF-8?q?=E9=80=9A=E7=9F=A5=E5=AF=B9=E8=B1=A1chelseayu@code-create.com.h?= =?UTF-8?q?k?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ai/da/common/config/MyTaskScheduler.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/ai/da/common/config/MyTaskScheduler.java b/src/main/java/com/ai/da/common/config/MyTaskScheduler.java index 86d82fd4..babc1c11 100644 --- a/src/main/java/com/ai/da/common/config/MyTaskScheduler.java +++ b/src/main/java/com/ai/da/common/config/MyTaskScheduler.java @@ -148,6 +148,7 @@ public class MyTaskScheduler { SendEmailUtil.sendExcelEmail("ningning@code-create.com.hk", null, Files.readAllBytes(Paths.get(fileName)), fileName); SendEmailUtil.sendExcelEmail("johnnyho@code-create.com.hk", null, Files.readAllBytes(Paths.get(fileName)), fileName); SendEmailUtil.sendExcelEmail("ringolau@code-create.com.hk", null, Files.readAllBytes(Paths.get(fileName)), fileName); + SendEmailUtil.sendExcelEmail("chelseayu@code-create.com.hk", null, Files.readAllBytes(Paths.get(fileName)), fileName); } } catch (IOException e) { e.printStackTrace(); @@ -160,6 +161,7 @@ public class MyTaskScheduler { SendEmailUtil.sendNoExcelEmail("ningning@code-create.com.hk", null); SendEmailUtil.sendNoExcelEmail("johnnyho@code-create.com.hk", null); SendEmailUtil.sendNoExcelEmail("ringolau@code-create.com.hk", null); + SendEmailUtil.sendNoExcelEmail("chelseayu@code-create.com.hk", null); } } From 765d4048459a3863d8153b92912cae3b6ad4d535 Mon Sep 17 00:00:00 2001 From: xupei Date: Wed, 11 Jun 2025 15:34:00 +0800 Subject: [PATCH 24/32] =?UTF-8?q?TASK:=20=E5=B0=86generate=EF=BC=8C?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E8=BE=93=E5=85=A5=E4=B8=AD=E7=9A=84=E4=B8=AD?= =?UTF-8?q?=E6=96=87=E5=AD=97=E7=AC=A6=E8=BD=AC=E6=8D=A2=E4=B8=BA=E8=8B=B1?= =?UTF-8?q?=E6=96=87=E5=AD=97=E7=AC=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ComprehensivePunctuationConverter.java | 88 +++++++++++++++++++ .../da/service/impl/GenerateServiceImpl.java | 4 + 2 files changed, 92 insertions(+) create mode 100644 src/main/java/com/ai/da/common/utils/ComprehensivePunctuationConverter.java diff --git a/src/main/java/com/ai/da/common/utils/ComprehensivePunctuationConverter.java b/src/main/java/com/ai/da/common/utils/ComprehensivePunctuationConverter.java new file mode 100644 index 00000000..c4c4ce63 --- /dev/null +++ b/src/main/java/com/ai/da/common/utils/ComprehensivePunctuationConverter.java @@ -0,0 +1,88 @@ +package com.ai.da.common.utils; + +import java.util.HashMap; +import java.util.Map; + +public class ComprehensivePunctuationConverter { + private static final Map FULL_TO_HALF_MAP = new HashMap<>(); + + static { + // 中文标点到英文标点的映射(扩展版) + FULL_TO_HALF_MAP.put(',', ','); + FULL_TO_HALF_MAP.put('。', '.'); + FULL_TO_HALF_MAP.put(';', ';'); + FULL_TO_HALF_MAP.put(':', ':'); + FULL_TO_HALF_MAP.put('?', '?'); + FULL_TO_HALF_MAP.put('!', '!'); + FULL_TO_HALF_MAP.put('(', '('); + FULL_TO_HALF_MAP.put(')', ')'); + FULL_TO_HALF_MAP.put('【', '['); + FULL_TO_HALF_MAP.put('】', ']'); + FULL_TO_HALF_MAP.put('「', '\''); + FULL_TO_HALF_MAP.put('」', '\''); + FULL_TO_HALF_MAP.put('『', '"'); + FULL_TO_HALF_MAP.put('』', '"'); + FULL_TO_HALF_MAP.put('、', '\\'); + FULL_TO_HALF_MAP.put('~', '~'); + FULL_TO_HALF_MAP.put('—', '-'); + FULL_TO_HALF_MAP.put('.', '.'); + FULL_TO_HALF_MAP.put('〈', '<'); + FULL_TO_HALF_MAP.put('〉', '>'); + FULL_TO_HALF_MAP.put('《', '«'); + FULL_TO_HALF_MAP.put('》', '»'); + FULL_TO_HALF_MAP.put('〝', '"'); + FULL_TO_HALF_MAP.put('〞', '"'); + FULL_TO_HALF_MAP.put('﹁', '"'); + FULL_TO_HALF_MAP.put('﹂', '"'); + FULL_TO_HALF_MAP.put('…', '.'); + FULL_TO_HALF_MAP.put('﹏', '_'); + + // 全角字母和数字 + for (char c = 'A'; c <= 'Z'; c++) { + FULL_TO_HALF_MAP.put(c, (char)(c - 'A' + 'A')); + } + for (char c = 'a'; c <= 'z'; c++) { + FULL_TO_HALF_MAP.put(c, (char)(c - 'a' + 'a')); + } + for (char c = '0'; c <= '9'; c++) { + FULL_TO_HALF_MAP.put(c, (char)(c - '0' + '0')); + } + } + + /** + * 将字符串中的全角字符(包括标点、字母、数字)转换为半角字符 + */ + public static String convertToHalfWidth(String input) { + if (input == null || input.isEmpty()) { + return input; + } + + StringBuilder result = new StringBuilder(); + for (int i = 0; i < input.length(); i++) { + char c = input.charAt(i); + + // 检查映射表 + if (FULL_TO_HALF_MAP.containsKey(c)) { + result.append(FULL_TO_HALF_MAP.get(c)); + } + // 处理全角空格(Unicode 12288) + else if (c == ' ') { + result.append(' '); + } + // 其他字符保持不变 + else { + result.append(c); + } + } + + return result.toString(); + } + + public static void main(String[] args) { +// String text = "这是一个全角示例,包含:中文标点、全角字母(ABC)、全角数字(123) 还有全角空格!"; + String text = "birds,yellow"; + String converted = convertToHalfWidth(text); + System.out.println("原始文本: " + text); + System.out.println("转换后: " + converted); + } +} diff --git a/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java b/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java index 34c6c9c8..83426473 100644 --- a/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java @@ -334,6 +334,10 @@ public class GenerateServiceImpl extends ServiceImpl i prefix = userInput.substring(0, userInput.indexOf(",")) + ", "; userInput = userInput.substring(userInput.indexOf(",") + 1); } + // 替换用户输入中的中文字符 + log.info("用户输入,处理前:{}", userInput); + userInput = ComprehensivePunctuationConverter.convertToHalfWidth(userInput); + log.info("用户输入,处理后:{}", userInput); String translated = prefix + pythonService.promptTranslate(userInput); switch (level1Type) { case "Moodboard": From 22e5a97143a72f9c22a4b37b9898c99c5fe7ac1e Mon Sep 17 00:00:00 2001 From: xupei Date: Fri, 13 Jun 2025 11:18:55 +0800 Subject: [PATCH 25/32] =?UTF-8?q?BUGFIX:=20=E4=BC=98=E6=83=A0=E5=88=B8?= =?UTF-8?q?=E7=9A=84=E4=BD=A3=E9=87=91=E8=AE=A1=E7=AE=97=EF=BC=8C=E7=BB=9F?= =?UTF-8?q?=E8=AE=A1=E6=97=B6=E9=97=B4=E8=BE=B9=E7=95=8C=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../da/service/impl/AffiliateServiceImpl.java | 45 ++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java b/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java index 61af2518..270bd2bb 100644 --- a/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java @@ -33,6 +33,7 @@ import javax.annotation.Resource; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @@ -344,7 +345,7 @@ public class AffiliateServiceImpl extends ServiceImpl=和<) + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("trade_state", "paid") + .isNotNull("promotion_code"); + + if (!StringUtils.isNullOrEmpty(lastTime)) { + queryWrapper.ge("create_time", lastTime); // 关键修复:>=代替> + } + queryWrapper.lt("create_time", LocalDateTime.now().format(formatter)); + + List paymentInfos = paymentInfoService.list(queryWrapper); + log.info("扫描时间范围: {} - {}, 新增订单数: {}", + lastTime, LocalDateTime.now().format(formatter), paymentInfos.size()); + + // 3. 按推广码汇总支付金额 + Map codeAmount = paymentInfos.stream() + .collect(Collectors.toMap( + PaymentInfo::getPromotionCode, + payment -> new BigDecimal(payment.getPayerTotal()), + BigDecimal::add + )); + + // 4. 更新佣金数据 + codeAmount.forEach((promotionCode, amount) -> { + ProductCoupons coupon = stripeService.getProductCoupon(promotionCode, null); + if (coupon != null) { + updateCouponCommission(coupon, amount); + productCouponsMapper.updateById(coupon); + } + }); + + // 5. 结束时更新Redis时间 + String newLastTime = LocalDateTime.now().format(formatter); + redisUtil.addToString(RedisUtil.PAYMENT_INFO_LAST_SCAN_TIME, newLastTime); } /** From 301a62a563ec7ad0625d2b60fd98819a1aef28f8 Mon Sep 17 00:00:00 2001 From: xupei Date: Thu, 19 Jun 2025 17:39:18 +0800 Subject: [PATCH 26/32] =?UTF-8?q?TASK:=E6=B7=BB=E5=8A=A0=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E5=91=98=E8=AE=BF=E9=97=AE=E4=BA=BA=E5=91=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/ai/da/controller/ConvenientInquiryController.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/ai/da/controller/ConvenientInquiryController.java b/src/main/java/com/ai/da/controller/ConvenientInquiryController.java index 95014eec..fd1fe312 100644 --- a/src/main/java/com/ai/da/controller/ConvenientInquiryController.java +++ b/src/main/java/com/ai/da/controller/ConvenientInquiryController.java @@ -52,6 +52,7 @@ public class ConvenientInquiryController { if (accountId.equals(31L) || accountId.equals(87L) || accountId.equals(83L) || accountId.equals(6L) || accountId.equals(4L) || accountId.equals(73L) || userEmail.equals("joho8228@hotmail.com") || userEmail.equals("wanninghua160@gmail.com") + || userEmail.equals("chelseayu@code-create.com.hk") ) { return Response.success(convenientInquiryService.getTrial(queryUserConditionsVO)); } else { @@ -68,6 +69,7 @@ public class ConvenientInquiryController { if (accountId.equals(31L) || accountId.equals(87L) || accountId.equals(83L) || accountId.equals(6L) || accountId.equals(4L) || accountId.equals(73L) || userEmail.equals("joho8228@hotmail.com") || userEmail.equals("wanninghua160@gmail.com") + || userEmail.equals("chelseayu@code-create.com.hk") ) { if (StringUtil.isNullOrEmpty(startTime)) startTime = "2024-02-01 00:00:00"; if (StringUtil.isNullOrEmpty(endTime)) { @@ -185,6 +187,7 @@ public class ConvenientInquiryController { if (accountId.equals(31L) || accountId.equals(87L) || accountId.equals(83L) || accountId.equals(6L) || accountId.equals(4L) || accountId.equals(73L) || userEmail.equals("joho8228@hotmail.com") || userEmail.equals("wanninghua160@gmail.com") + || userEmail.equals("chelseayu@code-create.com.hk") ) { return Response.success(convenientInquiryService.getUserInfo(queryUserConditionsVO)); } else { From d6c5d0e95d62a195211aacaa91f28592659db567 Mon Sep 17 00:00:00 2001 From: xupei Date: Mon, 23 Jun 2025 10:53:30 +0800 Subject: [PATCH 27/32] =?UTF-8?q?TASK:=E6=9F=A5=E8=AF=A2=E4=BA=A4=E6=98=93?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=20=E6=B7=BB=E5=8A=A0=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E6=80=BB=E9=87=91=E9=A2=9D=E5=92=8C=E4=BB=98=E6=AC=BE=E8=80=85?= =?UTF-8?q?=E9=82=AE=E7=AE=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../response/TransactionPageResponse.java | 15 +++++++ .../da/mapper/primary/PaymentInfoMapper.java | 5 +++ .../com/ai/da/model/vo/PaymentInfoVO.java | 2 + .../impl/ConvenientInquiryServiceImpl.java | 10 ++++- .../mapper/primary/PaymentInfoMapper.xml | 39 +++++++++++++++++++ 5 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/ai/da/common/response/TransactionPageResponse.java diff --git a/src/main/java/com/ai/da/common/response/TransactionPageResponse.java b/src/main/java/com/ai/da/common/response/TransactionPageResponse.java new file mode 100644 index 00000000..25200d49 --- /dev/null +++ b/src/main/java/com/ai/da/common/response/TransactionPageResponse.java @@ -0,0 +1,15 @@ +package com.ai.da.common.response; + +import io.swagger.annotations.ApiModel; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@NoArgsConstructor +@ApiModel("交易记录分页响应结果") +public class TransactionPageResponse extends PageBaseResponse { + + private BigDecimal totalAmount; +} diff --git a/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java b/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java index 9384ad6b..0dc85cce 100644 --- a/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java +++ b/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java @@ -6,6 +6,7 @@ import com.ai.da.model.vo.PaymentInfoVO; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Param; +import java.math.BigDecimal; import java.util.List; import java.util.Map; @@ -24,6 +25,10 @@ public interface PaymentInfoMapper extends BaseMapper { String country, String city, String startTime, String endTime, String payer ); + BigDecimal queryTotalPaymentAmount(String paymentType,String payerTotal, String type, String status, + String country, String city, String startTime, String endTime, String payer + ); + List> getCities(); List> getCountries(); diff --git a/src/main/java/com/ai/da/model/vo/PaymentInfoVO.java b/src/main/java/com/ai/da/model/vo/PaymentInfoVO.java index caa1955c..98ac7f14 100644 --- a/src/main/java/com/ai/da/model/vo/PaymentInfoVO.java +++ b/src/main/java/com/ai/da/model/vo/PaymentInfoVO.java @@ -13,6 +13,8 @@ public class PaymentInfoVO { private Long id; @ApiModelProperty("付款用户名") private String payer; + @ApiModelProperty("付款者邮箱") + private String email; @ApiModelProperty("选择的支付平台 PayPal || Stripe || Alipay-HK") private String platform; @ApiModelProperty("支付的金额 单位:HKD") diff --git a/src/main/java/com/ai/da/service/impl/ConvenientInquiryServiceImpl.java b/src/main/java/com/ai/da/service/impl/ConvenientInquiryServiceImpl.java index 8e92d0a8..2f5804a4 100644 --- a/src/main/java/com/ai/da/service/impl/ConvenientInquiryServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/ConvenientInquiryServiceImpl.java @@ -5,6 +5,7 @@ import com.ai.da.common.constant.CommonConstant; import com.ai.da.common.context.UserContext; import com.ai.da.common.enums.CreditsEventsEnum; import com.ai.da.common.response.PageBaseResponse; +import com.ai.da.common.response.TransactionPageResponse; import com.ai.da.common.utils.CopyUtil; import com.ai.da.common.utils.DateUtil; import com.ai.da.mapper.primary.*; @@ -610,16 +611,21 @@ public class ConvenientInquiryServiceImpl extends ServiceImpl response = new PageBaseResponse<>(); + TransactionPageResponse response = new TransactionPageResponse<>(); response.setContent(paymentInfoVOS); response.setPage(queryPaymentInfoDTO.getPage()); response.setSize(size); response.setTotal(total); response.setPages((long) totalPage); + response.setTotalAmount(Objects.isNull(payerTotal) ? BigDecimal.ZERO : payerTotal); return response; } diff --git a/src/main/resources/mapper/primary/PaymentInfoMapper.xml b/src/main/resources/mapper/primary/PaymentInfoMapper.xml index c358a722..5a295797 100644 --- a/src/main/resources/mapper/primary/PaymentInfoMapper.xml +++ b/src/main/resources/mapper/primary/PaymentInfoMapper.xml @@ -48,6 +48,7 @@ SELECT p.id, a.user_name payer, + a.user_email email, p.payment_type platform, p.payer_total, p.type, @@ -149,6 +150,44 @@ AND p.transaction_id NOT LIKE 'cs_test%' + +