14 Commits

Author SHA1 Message Date
litianxiang
9c68ce74ac Merge remote-tracking branch 'origin/dev/3.1_release_merge_MS' into dev/3.1_release_merge_MS 2026-06-10 17:54:54 +08:00
litianxiang
5745c334df rabbit监听queues修改 2026-06-10 17:54:46 +08:00
d9c0e67c07 task:开启消息监听 2026-06-10 17:38:26 +08:00
fe9cc99701 TASK:站内信格式调整 2026-06-03 18:32:12 +08:00
73c366d827 TASK:卖家审核通知 2026-06-03 17:55:15 +08:00
litianxiang
85e02a895c 去掉视频给卖家端fix 2026-06-02 17:07:35 +08:00
litianxiang
148bb84f3c 去掉视频给卖家 2026-06-02 15:02:45 +08:00
litianxiang
931eef6f53 登录黑名单清除失效问题 2026-05-29 16:02:03 +08:00
litianxiang
3d9a6aa9e9 适配无token接口的报错拦截器 2026-05-29 15:42:47 +08:00
11073690e5 TASK:允许修改订阅结束时间到今天之后的日期 2026-05-22 10:35:57 +08:00
litianxiang
921d2d956e minio缓存 2026-05-20 15:09:26 +08:00
litianxiang
d700f94f9d flux test 2026-05-14 16:36:55 +08:00
litianxiang
b277479e73 豆包模型更换 2026-05-13 20:52:28 +08:00
litianxiang
83cbd57dea 登录鉴权按照Source判断id来自于何处 2026-05-13 09:40:30 +08:00
20 changed files with 421 additions and 225 deletions

View File

@@ -263,6 +263,12 @@
<version>2.15.1</version> <version>2.15.1</version>
</dependency> </dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.13.0</version>
</dependency>
<dependency> <dependency>
<groupId>com.stripe</groupId> <groupId>com.stripe</groupId>
<artifactId>stripe-java</artifactId> <artifactId>stripe-java</artifactId>

View File

@@ -559,83 +559,83 @@ public class GenerateConsumer {
log.info("============ProcessPoseTransformResult End listening=========="); log.info("============ProcessPoseTransformResult End listening==========");
} }
// @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}") @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
// @RabbitHandler @RabbitHandler
// public void generateConsumer1(Message msg, Channel channel) { public void generateConsumer1(Message msg, Channel channel) {
// generate(msg, channel, "consumer 1"); generate(msg, channel, "consumer 1");
// } }
//
// @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}") @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
// @RabbitHandler @RabbitHandler
// public void generateConsumer2(Message msg, Channel channel) { public void generateConsumer2(Message msg, Channel channel) {
// generate(msg, channel, "consumer 2"); generate(msg, channel, "consumer 2");
// } }
//
// @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}") @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
// @RabbitHandler @RabbitHandler
// public void generateConsumer3(Message msg, Channel channel) { public void generateConsumer3(Message msg, Channel channel) {
// generate(msg, channel, "consumer 3"); generate(msg, channel, "consumer 3");
// } }
//
// @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}") @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
// @RabbitHandler @RabbitHandler
// public void generateConsumer4(Message msg, Channel channel) { public void generateConsumer4(Message msg, Channel channel) {
// generate(msg, channel, "consumer 4"); generate(msg, channel, "consumer 4");
// } }
//
// @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}") @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
// @RabbitHandler @RabbitHandler
// public void generateConsumer5(Message msg, Channel channel) { public void generateConsumer5(Message msg, Channel channel) {
// generate(msg, channel, "consumer 5"); generate(msg, channel, "consumer 5");
// } }
//
// @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}") @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
// @RabbitHandler @RabbitHandler
// public void generateConsumer6(Message msg, Channel channel) { public void generateConsumer6(Message msg, Channel channel) {
// generate(msg, channel, "consumer 6"); generate(msg, channel, "consumer 6");
// } }
//
// @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}") @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
// @RabbitHandler @RabbitHandler
// public void generateConsumer7(Message msg, Channel channel) { public void generateConsumer7(Message msg, Channel channel) {
// generate(msg, channel, "consumer 7"); generate(msg, channel, "consumer 7");
// } }
//
// @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}") @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
// @RabbitHandler @RabbitHandler
// public void generateConsumer8(Message msg, Channel channel) { public void generateConsumer8(Message msg, Channel channel) {
// generate(msg, channel, "consumer 8"); generate(msg, channel, "consumer 8");
// } }
//
// @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}") @RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
// @RabbitHandler @RabbitHandler
// public void generateConsumer9(Message msg, Channel channel) { public void generateConsumer9(Message msg, Channel channel) {
// generate(msg, channel, "consumer 9"); generate(msg, channel, "consumer 9");
// } }
//
// @RabbitListener(queues = "#{rabbitMQProperties.queues.generateResult}") @RabbitListener(queues = "#{rabbitMQProperties.queues.generateResult}")
// @RabbitHandler @RabbitHandler
// public void getGenerateResult(Message msg, Channel channel) { public void getGenerateResult(Message msg, Channel channel) {
// processGenerateResult(msg, channel); processGenerateResult(msg, channel);
// } }
//
// @RabbitListener(queues = "#{rabbitMQProperties.queues.toProductImageResult}") @RabbitListener(queues = "#{rabbitMQProperties.queues.toProductImageResult}")
// @RabbitHandler @RabbitHandler
// public void getToProductImageResult(Message msg, Channel channel) { public void getToProductImageResult(Message msg, Channel channel) {
// processToProductImageResult(msg, channel); processToProductImageResult(msg, channel);
// } }
//
// @RabbitListener(queues = "#{rabbitMQProperties.queues.relightResult}") @RabbitListener(queues = "#{rabbitMQProperties.queues.relightResult}")
// @RabbitHandler @RabbitHandler
// public void getRelightResult(Message msg, Channel channel) { public void getRelightResult(Message msg, Channel channel) {
// processRelightResult(msg, channel); processRelightResult(msg, channel);
// } }
//
// @RabbitListener(queues = "#{rabbitMQProperties.queues.poseTransform}") @RabbitListener(queues = "#{rabbitMQProperties.queues.poseTransform}")
// @RabbitHandler @RabbitHandler
// public void getPoseTransformationResult(Message msg, Channel channel) { public void getPoseTransformationResult(Message msg, Channel channel) {
// processPoseTransformResult(msg, channel); processPoseTransformResult(msg, channel);
// } }
// @RabbitListener(queues = "#{rabbitMQProperties.queues.designBatch}") // @RabbitListener(queues = "#{rabbitMQProperties.queues.designBatch}")
// @RabbitHandler // @RabbitHandler
// public void getDesignBatchResult(Message msg, Channel channel) { // public void getDesignBatchResult(Message msg, Channel channel) {

View File

@@ -44,9 +44,11 @@ public class ControllerLoggingAspect {
// 获取当前用户ID // 获取当前用户ID
Long userId = null; Long userId = null;
try {
AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder(); AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder();
if (authPrincipalVo != null) {
userId = authPrincipalVo.getId(); userId = authPrincipalVo.getId();
} catch (RuntimeException e) {
// 匿名接口,无认证上下文,忽略
} }
// 获取请求参数 // 获取请求参数
@@ -121,9 +123,11 @@ public class ControllerLoggingAspect {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
Long userId = null; Long userId = null;
try {
AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder(); AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder();
if (authPrincipalVo != null) {
userId = authPrincipalVo.getId(); userId = authPrincipalVo.getId();
} catch (RuntimeException e) {
// 匿名接口,无认证上下文,忽略
} }
// 获取请求参数 // 获取请求参数

View File

@@ -4,11 +4,13 @@ import com.ai.da.common.response.Response;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.ai.da.common.response.ResultEnum; import com.ai.da.common.response.ResultEnum;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException; import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
/** /**
* @author: dangweijian * @author: dangweijian
@@ -36,6 +38,14 @@ public class ExceptionCatch {
return Response.error(e.getCode(), e.getMsg()); return Response.error(e.getCode(), e.getMsg());
} }
@ResponseBody
@ResponseStatus(HttpStatus.UNAUTHORIZED)
@ExceptionHandler(UnauthorizedException.class)
public Response<String> unauthorizedExceptionCatch(UnauthorizedException e) {
log.error("Unauthorized: {}", e.getMessage());
return Response.error(401, e.getMessage());
}
@ResponseBody @ResponseBody
@ExceptionHandler(Exception.class) @ExceptionHandler(Exception.class)
public Response<String> exceptionCatch(Exception e) { public Response<String> exceptionCatch(Exception e) {

View File

@@ -0,0 +1,12 @@
package com.ai.da.common.config.exception;
public class UnauthorizedException extends RuntimeException {
public UnauthorizedException(String message) {
super(message);
}
public UnauthorizedException() {
super("Gateway token verification failed");
}
}

View File

@@ -18,8 +18,8 @@ public class ModelConstants {
// 模型名称常量 // 模型名称常量
public static final String PRINTBOARD_ADVANCED_T2I = "qwen-image"; public static final String PRINTBOARD_ADVANCED_T2I = "qwen-image";
public static final String MOODBOARD_ADVANCED = "doubao-seedream-3-0-t2i-250415"; public static final String MOODBOARD_ADVANCED = "doubao-seedream-4-5-251128";
public static final String PRINTBOARD_HIGH_T2I = "doubao-seedream-3-0-t2i-250415"; public static final String PRINTBOARD_HIGH_T2I = "doubao-seedream-4-0-250828-high";
public static final String PRINTBOARD_HIGH_I2I = "doubao-seedream-4-0-250828-fast"; public static final String PRINTBOARD_HIGH_I2I = "doubao-seedream-4-0-250828-fast";
public static final String PRINTBOARD_ADVANCED_I2I = "doubao-seedream-4-0-250828"; public static final String PRINTBOARD_ADVANCED_I2I = "doubao-seedream-4-0-250828";
public static final String IMAGEN_MODEL = "imagen-4.0-generate-001"; public static final String IMAGEN_MODEL = "imagen-4.0-generate-001";

View File

@@ -3,17 +3,39 @@ package com.ai.da.common.context;
import com.ai.da.model.vo.AuthPrincipalVo; import com.ai.da.model.vo.AuthPrincipalVo;
public class UserContext { public class UserContext {
private static ThreadLocal<AuthPrincipalVo> userHolder = new ThreadLocal<AuthPrincipalVo>(); private static final ThreadLocal<AuthPrincipalVo> userHolder = new ThreadLocal<>();
public static void setUserHolder(AuthPrincipalVo authPrincipalVo) {
userHolder.set(authPrincipalVo);
}
public static AuthPrincipalVo getUserHolder() { public static AuthPrincipalVo getUserHolder() {
return userHolder.get(); AuthPrincipalVo holder = userHolder.get();
if (holder == null) {
throw new RuntimeException("User not authenticated");
}
if (!"AIDA".equals(holder.getSource())) {
throw new RuntimeException("Access denied: source must be AIDA");
}
return holder;
} }
public static void delete() { public static void delete() {
userHolder.remove(); userHolder.remove();
} }
public static void setUserHolder(AuthPrincipalVo authPrincipalVo) { public static Long getUserId() {
userHolder.set(authPrincipalVo); return getUserHolder().getId();
}
public static Long getBuyerId() {
AuthPrincipalVo holder = userHolder.get();
if (holder == null) {
throw new RuntimeException("User not authenticated");
}
if (!"BUYER".equals(holder.getSource())) {
throw new RuntimeException("Access denied: source must be BUYER");
}
return holder.getId();
} }
} }

View File

@@ -52,6 +52,18 @@ public class MinioUtil {
return minioClient; return minioClient;
} }
@Autowired
private RedisUtil redisUtil;
/**
* Redis缓存key前缀用于Minio签名URL缓存
*/
private static final String REDIS_MINIO_URL_PREFIX = "minio:url:";
/**
* 签名URL缓存过期时间默认1天
*/
private static final long URL_CACHE_EXPIRE_SECONDS = 24 * 60 * 60;
/** /**
* description: 判断bucket是否存在不存在则创建 * description: 判断bucket是否存在不存在则创建
* *
@@ -392,6 +404,11 @@ public class MinioUtil {
* @return 文件的临时URL如果出现异常则返回null * @return 文件的临时URL如果出现异常则返回null
*/ */
public String getPreSignedUrl(String bucketName, String fileName, int expiry) { public String getPreSignedUrl(String bucketName, String fileName, int expiry) {
String cacheKey = REDIS_MINIO_URL_PREFIX + bucketName + "/" + fileName;
Object cachedUrl = redisUtil.getFromString(cacheKey);
if (cachedUrl != null) {
return cachedUrl.toString();
}
try { try {
String lowerName = fileName.toLowerCase(); String lowerName = fileName.toLowerCase();
@@ -419,8 +436,9 @@ public class MinioUtil {
builder.extraQueryParams(queryParams); builder.extraQueryParams(queryParams);
} }
String presignedObjectUrl = minioClient.getPresignedObjectUrl(builder.build());
return minioClient.getPresignedObjectUrl(builder.build()); redisUtil.addToString(cacheKey, presignedObjectUrl, URL_CACHE_EXPIRE_SECONDS);
return presignedObjectUrl;
} catch (MinioException | InvalidKeyException } catch (MinioException | InvalidKeyException
| IOException | NoSuchAlgorithmException | IllegalArgumentException e) { | IOException | NoSuchAlgorithmException | IllegalArgumentException e) {
e.printStackTrace(); e.printStackTrace();

View File

@@ -1076,4 +1076,45 @@ public class SendEmailUtil {
} }
private final static Long SELLER_APPROVED = 184414L;
private final static Long SELLER_REJECTED = 184415L;
public static void sellerApproval(String receiver, boolean isApproved) {
try {
// 实例化一个认证对象
Credential cred = new Credential(SECRET_ID, SECRET_KEy);
HttpProfile httpProfile = new HttpProfile();
httpProfile.setEndpoint("ses.tencentcloudapi.com");
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
SesClient client = new SesClient(cred, "ap-hongkong", clientProfile);
SendEmailRequest req = new SendEmailRequest();
req.setFromEmailAddress(CODE_CREATE_SEND_ADDRESS);
req.setDestination(new String[]{receiver});
// 根据邮件类型设置不同的主题和模板
String subject;
Template template = new Template();
if (isApproved) {
subject = "AiDA卖家权限已开通 AiDA Seller Access Enabled";
template.setTemplateID(SELLER_APPROVED);
}else {
subject = "AiDA卖家权限审批不通过 Seller Access Not Approved";
template.setTemplateID(SELLER_REJECTED);
}
req.setSubject(subject);
req.setTemplate(template);
// 发送邮件
SendEmailResponse resp = client.SendEmail(req);
log.info("邮件发送成功,收件人地址:{}", receiver);
log.info("短信发送结果res###{}", SendEmailResponse.toJsonString(resp));
} catch (TencentCloudSDKException e) {
log.info(receiver);
log.error("邮件发送失败###{},收件人地址:{}", e.toString(), receiver);
}
}
} }

View File

@@ -6,6 +6,7 @@ import com.ai.da.model.dto.GetNotificationDTO;
import com.ai.da.model.vo.NotificationVO; import com.ai.da.model.vo.NotificationVO;
import com.ai.da.model.dto.PublishSysNotificationDTO; import com.ai.da.model.dto.PublishSysNotificationDTO;
import com.ai.da.service.MessageCenterService; import com.ai.da.service.MessageCenterService;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -60,4 +61,12 @@ public class MessageCenterController {
messageCenterService.setReadAll(type); messageCenterService.setReadAll(type);
return Response.success("success"); return Response.success("success");
} }
@Hidden
@Operation(summary = "卖家审批结果站内信通知")
@PostMapping("/sellerApprovalNotice")
public Response<String> sellerApprovalNotice(@RequestParam("userId") Long userId, @RequestParam("isApproved") boolean isApproved) {
messageCenterService.sellerApprovalNotice(userId, isApproved);
return Response.success("success");
}
} }

View File

@@ -18,4 +18,10 @@ public interface GatewayFeignClient {
*/ */
@PostMapping("/logout") @PostMapping("/logout")
Response<Void> logout(@RequestParam("userId") Long userId); Response<Void> logout(@RequestParam("userId") Long userId);
/**
* 清除用户黑名单,允许该用户重新登录(登录时会自动调用)。
*/
@PostMapping("/clear-blacklist")
Response<Void> clearBlacklist(@RequestParam("userId") Long userId);
} }

View File

@@ -29,4 +29,6 @@ public interface MessageCenterService extends IService<Notification> {
void publishSystemNotification(PublishSysNotificationDTO message); void publishSystemNotification(PublishSysNotificationDTO message);
void videoFinishedMsg(Long userId, String projectName, boolean isSuccess); void videoFinishedMsg(Long userId, String projectName, boolean isSuccess);
void sellerApprovalNotice(Long userId, boolean isApproved);
} }

View File

@@ -358,12 +358,20 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
principal.setUsername(account.getUserName()); principal.setUsername(account.getUserName());
principal.setLanguage(account.getLanguage()); principal.setLanguage(account.getLanguage());
principal.setCountry(account.getCountry()); principal.setCountry(account.getCountry());
//区分买家端登录
principal.setSource("AIDA");
String token2 = tokenGenerateUtils.createToken(principal); String token2 = tokenGenerateUtils.createToken(principal);
// 本地 JVM 缓存(适配旧逻辑) // 本地 JVM 缓存(适配旧逻辑)
LocalCacheUtils.setTokenCache(String.valueOf(account.getId()), token2); LocalCacheUtils.setTokenCache(String.valueOf(account.getId()), token2);
// 同步写入 Redis重启后仍然可用 // 同步写入 Redis重启后仍然可用
long jwtExpiration = tokenGenerateUtils.getJwtExpiration(); long jwtExpiration = tokenGenerateUtils.getJwtExpiration();
redisUtil.setLoginToken(account.getId(), token2, jwtExpiration); redisUtil.setLoginToken(account.getId(), token2, jwtExpiration);
// 清除黑名单,允许用户重新登录(仅当黑名单功能开启时)
try {
gatewayFeignClient.clearBlacklist(account.getId());
} catch (Exception e) {
log.warn("登录时清除黑名单失败userId={}, error={}", account.getId(), e.getMessage());
}
return token2; return token2;
} }

View File

@@ -1553,11 +1553,11 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
if (imagePath != null) { if (imagePath != null) {
requestBuilder.image(finalImagePath1); requestBuilder.image(finalImagePath1);
} }
if (useModel.equals(ModelConstants.PRINTBOARD_HIGH_I2I)) { if (useModel.equals(ModelConstants.PRINTBOARD_HIGH_I2I)|| useModel.equals(ModelConstants.PRINTBOARD_HIGH_T2I)) {
GenerateImagesRequest.OptimizePromptOptions optimizePromptOptions = new GenerateImagesRequest.OptimizePromptOptions(); GenerateImagesRequest.OptimizePromptOptions optimizePromptOptions = new GenerateImagesRequest.OptimizePromptOptions();
optimizePromptOptions.setMode("fast"); optimizePromptOptions.setMode("fast");
requestBuilder.optimizePromptOptions(optimizePromptOptions); requestBuilder.optimizePromptOptions(optimizePromptOptions);
//由于PRINTBOARD_HIGH_I2I与PRINTBOARD_ADVANCED_I2I使用模型一致为了区别积分扣除PRINTBOARD_HIGH_I2I加入了-fast但传入模型时需要去掉-fast用PRINTBOARD_ADVANCED_I2I的常量做替代 //由于PRINTBOARD_HIGH_T2I,PRINTBOARD_HIGH_I2I与PRINTBOARD_ADVANCED_I2I使用模型一致为了区别积分扣除PRINTBOARD_HIGH_I2I加入了-fast或者-high,但传入模型时需要去掉-fast或者-high用PRINTBOARD_ADVANCED_I2I的常量做替代
requestBuilder.model(ModelConstants.PRINTBOARD_ADVANCED_I2I); requestBuilder.model(ModelConstants.PRINTBOARD_ADVANCED_I2I);
} }
@@ -4225,8 +4225,11 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
} }
// 发送POST请求到Flux API // 发送POST请求到Flux API
long start = System.currentTimeMillis();
String resp = sendRequestUtil.sendFluxPost(fluxRequestUrl, requestBody.toString()); String resp = sendRequestUtil.sendFluxPost(fluxRequestUrl, requestBody.toString());
JSONObject respObj = JSONUtil.parseObj(resp); JSONObject respObj = JSONUtil.parseObj(resp);
long end = System.currentTimeMillis();
log.info("flux 耗时:{}ms", end - start);
log.info("flux 发起生成请求返回结果: {}", respObj); log.info("flux 发起生成请求返回结果: {}", respObj);
// 从响应中提取任务ID // 从响应中提取任务ID

View File

@@ -7,6 +7,7 @@ import com.ai.da.common.response.PageBaseResponse;
import com.ai.da.common.utils.CopyUtil; import com.ai.da.common.utils.CopyUtil;
import com.ai.da.common.utils.MinioUtil; import com.ai.da.common.utils.MinioUtil;
import com.ai.da.common.utils.RedisUtil; import com.ai.da.common.utils.RedisUtil;
import com.ai.da.common.utils.SendEmailUtil;
import com.ai.da.common.websocket.NotificationConnection; import com.ai.da.common.websocket.NotificationConnection;
import com.ai.da.mapper.primary.*; import com.ai.da.mapper.primary.*;
import com.ai.da.mapper.primary.entity.*; import com.ai.da.mapper.primary.entity.*;
@@ -441,4 +442,50 @@ public class MessageCenterServiceImpl extends ServiceImpl<NotificationMapper, No
pushMessage("system", userId); pushMessage("system", userId);
} }
private final static String APPROVED_MESSAGE = "尊敬的用户,您的卖家权限已开通。" +
"现在可通过\"成为卖家\"的同一入口进入卖家中心。\n在卖家中心中您可以" +
"\n·从设计项目中批量选择服装设计并创建上架内容 " +
"\n·将设计及高级工具媒体转为可售卖的数字商品 " +
"\n·编辑、保存、发布并管理商品状态" +
"\n\nDear User, your seller access has been enabled. " +
"You can now enter the Seller Dashboard from the same entry point used to become a seller.\nIn the Seller Dashboard, you can:" +
"\n·Batch select apparel designs from a design project and create listings" +
"\n·Turn designs and Advanced Tools media into sellable digital items " +
"\n·Edit, save, publish, and manage item status";
private final static String REJECTED_MESSAGE = "尊敬的用户,您的卖家权限申请审批未通过。 请检查您提交的信息,并确保您的卖家资料符合平台要求。您可以更新相关信息后重新提交申请。\n\n" +
"Dear User, your seller access request was not approved. Please review the information you submitted and make sure your seller profile meets the platform requirements. You may update the relevant information and resubmit your application.";
public void sellerApprovalNotice(Long userId, boolean isApproved) {
if (userId != null && userId != 0) {
PublishSysNotificationDTO sysNotificationDTO = new PublishSysNotificationDTO();
Notification notification = new Notification();
notification.setType("system");
notification.setReceiverId(userId);
if (isApproved) {
sysNotificationDTO.setTitle("卖家权限审批通过 Seller Access Enabled");
sysNotificationDTO.setContent(APPROVED_MESSAGE);
} else {
sysNotificationDTO.setTitle("卖家权限审批不通过 Seller Access Not Approved");
sysNotificationDTO.setContent(REJECTED_MESSAGE);
}
notification.setContent(JSON.toJSONString(sysNotificationDTO));
notification.setIsRead(0);
notification.setCreateTime(LocalDateTime.now());
// 保存消息内容
save(notification);
// 推送系统消息
pushMessage("system", userId);
Account account = accountService.getById(userId);
if (account != null) {
// 发送邮件
SendEmailUtil.sellerApproval(account.getUserEmail(), isApproved);
}
}
}
} }

View File

@@ -169,7 +169,7 @@ public class SubscriptionPlanServiceImpl extends ServiceImpl<SubscriptionPlanMap
} }
/** /**
* 处理结束时间(只能延长) * 处理结束时间,不允许订阅结束时间早于当前时间和订阅开始时间
*/ */
private void handlePeriodEnd(UpdateSubscriptionPlanDTO dto, SubscriptionPlan plan) { private void handlePeriodEnd(UpdateSubscriptionPlanDTO dto, SubscriptionPlan plan) {
Long newEnd = dto.getCurrentPeriodEnd(); Long newEnd = dto.getCurrentPeriodEnd();
@@ -177,9 +177,20 @@ public class SubscriptionPlanServiceImpl extends ServiceImpl<SubscriptionPlanMap
return; return;
} }
if (newEnd < plan.getCurrentPeriodEnd()) { long currentTimeSec = System.currentTimeMillis() / 1000;
long startTime = plan.getCurrentPeriodStart();
// 检查是否早于开始时间不能等于否则周期长度为0
if (newEnd <= startTime) {
throw new BusinessException( throw new BusinessException(
"the.subscription.end.date.can.be.extended.only.not.reduced" "end.time.cannot.be.earlier.than.or.equal.to.start.time"
);
}
// 检查是否早于当前时间(不能等于,否则立即过期)
if (newEnd <= currentTimeSec) {
throw new BusinessException(
"end.time.cannot.be.earlier.than.or.equal.to.the.current.time"
); );
} }

View File

@@ -92,14 +92,15 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
for (CollectionSort userLikeSort : childSortList) { for (CollectionSort userLikeSort : childSortList) {
if (userLikeSort.getRelationType().equals(CollectionType.POSE_TRANSFORM.getValue())){ if (userLikeSort.getRelationType().equals(CollectionType.POSE_TRANSFORM.getValue())){
PoseTransformation poseTransformation = poseTransformationMapper.selectById(userLikeSort.getRelationId()); //2026.6.2 不显示视频到卖家端
if (poseTransformation != null) { // PoseTransformation poseTransformation = poseTransformationMapper.selectById(userLikeSort.getRelationId());
PoseTransformationVideoDTO videoDTO = new PoseTransformationVideoDTO(); // if (poseTransformation != null) {
videoDTO.setFirstFrameUrl(minioUtil.processMinioResource(poseTransformation.getFirstFrameUrl(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME)); // PoseTransformationVideoDTO videoDTO = new PoseTransformationVideoDTO();
videoDTO.setGifUrl(minioUtil.processMinioResource(poseTransformation.getGifUrl(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME)); // videoDTO.setFirstFrameUrl(minioUtil.processMinioResource(poseTransformation.getFirstFrameUrl(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME));
videoDTO.setVideoUrl(minioUtil.processMinioResource(poseTransformation.getVideoUrl(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME)); // videoDTO.setGifUrl(minioUtil.processMinioResource(poseTransformation.getGifUrl(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME));
designUrlsDTO.getVideos().add(videoDTO); // videoDTO.setVideoUrl(minioUtil.processMinioResource(poseTransformation.getVideoUrl(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME));
} // designUrlsDTO.getVideos().add(videoDTO);
// }
}else { }else {
ToProductImageResult toProductImageResult = toProductImageResultMapper.selectById(userLikeSort.getRelationId()); ToProductImageResult toProductImageResult = toProductImageResultMapper.selectById(userLikeSort.getRelationId());
if (toProductImageResult != null && !isGenerateTaskFailed(toProductImageResult.getStatus(), toProductImageResult.getCreateTime())) { if (toProductImageResult != null && !isGenerateTaskFailed(toProductImageResult.getStatus(), toProductImageResult.getCreateTime())) {

View File

@@ -11,14 +11,6 @@ spring:
application: application:
name: aida-back name: aida-back
# ---------- 副数据源back 私有,由 Nacos 统一管理) ----------
# ---------- Token 生成参数(由 TokenGenerateUtils 使用) ----------
security:
jwtSecret: JWTSECRET
jwtTokenHeader: Authorization
jwtTokenPrefix: Bearer-
jwtExpiration: 8640000000
# ---------- MinIO Buckets ---------- # ---------- MinIO Buckets ----------
minio: minio:
@@ -57,17 +49,17 @@ redis:
# ---------- RabbitMQ 队列 ---------- # ---------- RabbitMQ 队列 ----------
rabbitmq: rabbitmq:
queues: queues:
generate: generate-queue generate: generate-queue-dev
sr: SR-queue sr: SR-queue-dev
srResult: SuperResolution srResult: SuperResolution-dev
generateResult: GenerateImage generateResult: GenerateImage-dev
toProductImageResult: ToProductImage toProductImageResult: ToProductImage-dev
relightResult: Relight relightResult: Relight-dev
poseTransform: PoseTransform poseTransform: PoseTransform-dev
designBatch: DesignBatch designBatch: DesignBatch-dev
relightBatch: BatchRelight relightBatch: BatchRelight-dev
toProductImageBatch: BatchToProductImage toProductImageBatch: BatchToProductImage-dev
poseTransformBatch: BatchPoseTransform poseTransformBatch: BatchPoseTransform-dev
emailRetry: emailRetry-business emailRetry: emailRetry-business
exchange: exchange:
generate: generate-exchange generate: generate-exchange

View File

@@ -211,6 +211,8 @@ please.specify.the.organizationId=Please specify the organizationId.
switch.failed.sub-account.not.under.your.active.subscription=Switch failed. Sub-account not under your active subscription. switch.failed.sub-account.not.under.your.active.subscription=Switch failed. Sub-account not under your active subscription.
Sub-accounts.cannot.be.admins=Sub-accounts in a subscription cannot be designated as admins. Sub-accounts.cannot.be.admins=Sub-accounts in a subscription cannot be designated as admins.
only.subscription.plans.with.a.PENDING.status.can.have.their.start.time.modified=Only subscription plans with a PENDING status can have their start time modified. only.subscription.plans.with.a.PENDING.status.can.have.their.start.time.modified=Only subscription plans with a PENDING status can have their start time modified.
end.time.cannot.be.earlier.than.or.equal.to.start.time=End time cannot be earlier than or equal to start time.
end.time.cannot.be.earlier.than.or.equal.to.the.current.time=End time cannot be earlier than or equal to the current time.
the.subscription.end.date.can.be.extended.only.not.reduced=The subscription end date can be extended only, not reduced. the.subscription.end.date.can.be.extended.only.not.reduced=The subscription end date can be extended only, not reduced.
total.sub-account.quota.cannot.be.lower.than.existing.sub-accounts=Total sub-account quota cannot be lower than existing sub-accounts. total.sub-account.quota.cannot.be.lower.than.existing.sub-accounts=Total sub-account quota cannot be lower than existing sub-accounts.
the.credit.limit.set.cannot.be.lower.than.the.amount.of.credits.already.used=The credit limit set cannot be lower than the amount of credits already used. the.credit.limit.set.cannot.be.lower.than.the.amount.of.credits.already.used=The credit limit set cannot be lower than the amount of credits already used.

View File

@@ -207,6 +207,8 @@ please.specify.the.organizationId=请指定organizationId
switch.failed.sub-account.not.under.your.active.subscription=切换失败,该子账号不属于您当前管理的订阅计划 switch.failed.sub-account.not.under.your.active.subscription=切换失败,该子账号不属于您当前管理的订阅计划
Sub-accounts.cannot.be.admins=在订阅中的子账号不能被指定为管理员 Sub-accounts.cannot.be.admins=在订阅中的子账号不能被指定为管理员
only.subscription.plans.with.a.PENDING.status.can.have.their.start.time.modified=只有PENDING状态的订阅计划可以修改订阅开始时间 only.subscription.plans.with.a.PENDING.status.can.have.their.start.time.modified=只有PENDING状态的订阅计划可以修改订阅开始时间
end.time.cannot.be.earlier.than.or.equal.to.start.time=订阅结束时间不能早于或等于开始时间
end.time.cannot.be.earlier.than.or.equal.to.the.current.time=订阅结束时间不能早于或等于当前时间
the.subscription.end.date.can.be.extended.only.not.reduced=订阅的到期时间不能缩短,只能延长 the.subscription.end.date.can.be.extended.only.not.reduced=订阅的到期时间不能缩短,只能延长
total.sub-account.quota.cannot.be.lower.than.existing.sub-accounts=设置的子账号总数量不能低于现存已添加的子账号数量 total.sub-account.quota.cannot.be.lower.than.existing.sub-accounts=设置的子账号总数量不能低于现存已添加的子账号数量
the.credit.limit.set.cannot.be.lower.than.the.amount.of.credits.already.used=设置的积分上限不能低于已使用的积分量 the.credit.limit.set.cannot.be.lower.than.the.amount.of.credits.already.used=设置的积分上限不能低于已使用的积分量