Compare commits
5 Commits
4d3b22de82
...
dev/3.1_re
| Author | SHA1 | Date | |
|---|---|---|---|
| 11073690e5 | |||
|
|
921d2d956e | ||
|
|
d700f94f9d | ||
|
|
b277479e73 | ||
|
|
83cbd57dea |
6
pom.xml
6
pom.xml
@@ -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>
|
||||||
|
|||||||
@@ -1,89 +1,99 @@
|
|||||||
package com.ai.da.common.config.exception;
|
package com.ai.da.common.config.exception;
|
||||||
|
|
||||||
import com.ai.da.common.response.Response;
|
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.validation.BindException;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
import org.springframework.validation.BindException;
|
||||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
/**
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
* @author: dangweijian
|
|
||||||
* @description: 全局异常捕获
|
/**
|
||||||
* @create: 2019-12-03 10:24
|
* @author: dangweijian
|
||||||
**/
|
* @description: 全局异常捕获
|
||||||
@Slf4j
|
* @create: 2019-12-03 10:24
|
||||||
@ControllerAdvice
|
**/
|
||||||
public class ExceptionCatch {
|
@Slf4j
|
||||||
|
@ControllerAdvice
|
||||||
/**
|
public class ExceptionCatch {
|
||||||
* 线程安全,且构建后不可更改
|
|
||||||
*/
|
/**
|
||||||
private static ImmutableMap<Class<? extends Throwable>, ResultEnum> EXCEPTIONS;
|
* 线程安全,且构建后不可更改
|
||||||
|
*/
|
||||||
/**
|
private static ImmutableMap<Class<? extends Throwable>, ResultEnum> EXCEPTIONS;
|
||||||
* 用于构建ImmutableMap
|
|
||||||
*/
|
/**
|
||||||
private static ImmutableMap.Builder<Class<? extends Throwable>, ResultEnum> builder = ImmutableMap.builder();
|
* 用于构建ImmutableMap
|
||||||
|
*/
|
||||||
@ResponseBody
|
private static ImmutableMap.Builder<Class<? extends Throwable>, ResultEnum> builder = ImmutableMap.builder();
|
||||||
@ExceptionHandler(BusinessException.class)
|
|
||||||
public Response<String> businessExceptionCatch(BusinessException e) {
|
@ResponseBody
|
||||||
log.error("发生业务异常,code:[{}],msg:[{}]", e.getCode(), e.getMsg(), e);
|
@ExceptionHandler(BusinessException.class)
|
||||||
return Response.error(e.getCode(), e.getMsg());
|
public Response<String> businessExceptionCatch(BusinessException e) {
|
||||||
}
|
log.error("发生业务异常,code:[{}],msg:[{}]", e.getCode(), e.getMsg(), e);
|
||||||
|
return Response.error(e.getCode(), e.getMsg());
|
||||||
@ResponseBody
|
}
|
||||||
@ExceptionHandler(Exception.class)
|
|
||||||
public Response<String> exceptionCatch(Exception e) {
|
@ResponseBody
|
||||||
log.error("发生系统异常,message:[{}]", e.getMessage(), e);
|
@ResponseStatus(HttpStatus.UNAUTHORIZED)
|
||||||
//如果ImmutableMap集合为空,构建ImmutableMap
|
@ExceptionHandler(UnauthorizedException.class)
|
||||||
if (EXCEPTIONS == null || EXCEPTIONS.size() == 0) {
|
public Response<String> unauthorizedExceptionCatch(UnauthorizedException e) {
|
||||||
EXCEPTIONS = builder.build();
|
log.error("Unauthorized: {}", e.getMessage());
|
||||||
}
|
return Response.error(401, e.getMessage());
|
||||||
//获取不可预知异常自定义错误码
|
}
|
||||||
if (EXCEPTIONS != null) {
|
|
||||||
ResultEnum resultEnum = EXCEPTIONS.get(e.getClass());
|
@ResponseBody
|
||||||
if (resultEnum != null) {
|
@ExceptionHandler(Exception.class)
|
||||||
return Response.error(resultEnum.getCode(), resultEnum.getMsg());
|
public Response<String> exceptionCatch(Exception e) {
|
||||||
}
|
log.error("发生系统异常,message:[{}]", e.getMessage(), e);
|
||||||
}
|
//如果ImmutableMap集合为空,构建ImmutableMap
|
||||||
return Response.error(ResultEnum.ERROR.getCode(), e.getMessage() == null ? ResultEnum.ERROR.getMsg() : e.getMessage());
|
if (EXCEPTIONS == null || EXCEPTIONS.size() == 0) {
|
||||||
}
|
EXCEPTIONS = builder.build();
|
||||||
|
}
|
||||||
/**
|
//获取不可预知异常自定义错误码
|
||||||
* 处理参数校验异常
|
if (EXCEPTIONS != null) {
|
||||||
*
|
ResultEnum resultEnum = EXCEPTIONS.get(e.getClass());
|
||||||
* @param e
|
if (resultEnum != null) {
|
||||||
* @return ResponseData
|
return Response.error(resultEnum.getCode(), resultEnum.getMsg());
|
||||||
*/
|
}
|
||||||
@ResponseBody
|
}
|
||||||
@ExceptionHandler(BindException.class)
|
return Response.error(ResultEnum.ERROR.getCode(), e.getMessage() == null ? ResultEnum.ERROR.getMsg() : e.getMessage());
|
||||||
public Response<String> bindExceptionHandler(BindException e) {
|
}
|
||||||
log.error("参数错误bind:{}", e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
|
|
||||||
BusinessException businessException = new BusinessException(e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
|
/**
|
||||||
return Response.error(businessException.getCode(), businessException.getMsg());
|
* 处理参数校验异常
|
||||||
}
|
*
|
||||||
|
* @param e
|
||||||
/**
|
* @return ResponseData
|
||||||
* 处理参数校验异常
|
*/
|
||||||
*
|
@ResponseBody
|
||||||
* @param e
|
@ExceptionHandler(BindException.class)
|
||||||
* @return ResponseData
|
public Response<String> bindExceptionHandler(BindException e) {
|
||||||
*/
|
log.error("参数错误bind:{}", e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
|
||||||
@ResponseBody
|
BusinessException businessException = new BusinessException(e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
|
||||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
return Response.error(businessException.getCode(), businessException.getMsg());
|
||||||
public Response<String> handleValidationException(MethodArgumentNotValidException e) {
|
}
|
||||||
log.error("参数错误bind:{}", e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
|
|
||||||
BusinessException businessException = new BusinessException(e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
|
/**
|
||||||
return Response.error(businessException.getCode(), businessException.getMsg());
|
* 处理参数校验异常
|
||||||
}
|
*
|
||||||
|
* @param e
|
||||||
//初始化,不可预知异常自定义错误编码
|
* @return ResponseData
|
||||||
static {
|
*/
|
||||||
// builder.put(FileNotFoundException.class, ResultEnum.FILE_NOT_EXIST);
|
@ResponseBody
|
||||||
}
|
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||||
}
|
public Response<String> handleValidationException(MethodArgumentNotValidException e) {
|
||||||
|
log.error("参数错误bind:{}", e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
|
||||||
|
BusinessException businessException = new BusinessException(e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
|
||||||
|
return Response.error(businessException.getCode(), businessException.getMsg());
|
||||||
|
}
|
||||||
|
|
||||||
|
//初始化,不可预知异常自定义错误编码
|
||||||
|
static {
|
||||||
|
// builder.put(FileNotFoundException.class, ResultEnum.FILE_NOT_EXIST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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";
|
||||||
|
|||||||
@@ -1,19 +1,41 @@
|
|||||||
package com.ai.da.common.context;
|
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 AuthPrincipalVo getUserHolder() {
|
public static void setUserHolder(AuthPrincipalVo authPrincipalVo) {
|
||||||
return userHolder.get();
|
userHolder.set(authPrincipalVo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void delete() {
|
public static AuthPrincipalVo getUserHolder() {
|
||||||
userHolder.remove();
|
AuthPrincipalVo holder = userHolder.get();
|
||||||
}
|
if (holder == null) {
|
||||||
|
throw new RuntimeException("User not authenticated");
|
||||||
public static void setUserHolder(AuthPrincipalVo authPrincipalVo) {
|
}
|
||||||
userHolder.set(authPrincipalVo);
|
if (!"AIDA".equals(holder.getSource())) {
|
||||||
}
|
throw new RuntimeException("Access denied: source must be AIDA");
|
||||||
}
|
}
|
||||||
|
return holder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void delete() {
|
||||||
|
userHolder.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Long getUserId() {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -358,6 +358,8 @@ 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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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=设置的积分上限不能低于已使用的积分量
|
||||||
|
|||||||
Reference in New Issue
Block a user