40 Commits

Author SHA1 Message Date
2e7004f9dc 取消监听所有消息队列 2026-02-05 15:16:04 +08:00
497421e7fe TO DEV 2026-01-27 10:15:36 +08:00
891527426c Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev/3.1_release_merge
# Conflicts:
#	src/main/java/com/ai/da/service/impl/DesignServiceImpl.java
2026-01-26 14:49:38 +08:00
litianxiang
8f0d0953b2 Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev/3.1_release_merge 2026-01-26 11:15:38 +08:00
f5c3621a5d bugfix: design like 2026-01-23 22:45:40 +08:00
litianxiang
9a1a0045e0 fix:like报错 2026-01-23 22:40:30 +08:00
6223c8e994 brandDNA 2026-01-23 22:25:01 +08:00
67bbee49fd Merge branch 'dev/3.1_release_merge' into release/3.1 2026-01-23 21:20:26 +08:00
ad62ceb32a Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2026-01-23 21:02:04 +08:00
082afe9e94 gradiant 置空 2026-01-23 20:57:48 +08:00
49288c3a31 TO Prod 2026-01-23 16:10:55 +08:00
81624e36db Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev/3.1_release_merge 2026-01-23 15:12:15 +08:00
a526b122d1 Merge branch 'release/3.1' into dev/3.1_release_merge 2026-01-23 15:11:45 +08:00
litianxiang
d882b2e817 Merge remote-tracking branch 'origin/dev-ltx' into dev/3.1_release_merge 2026-01-23 15:05:22 +08:00
litianxiang
ebf6427d42 fix:用户特征存入逻辑错误 2026-01-23 15:04:59 +08:00
77fe03d361 Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2026-01-23 11:46:31 +08:00
7a44d67dbf BUGFIX: 系统消息发布 广播时消息数量错误 2026-01-23 11:46:08 +08:00
55ce2c6c7e Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2026-01-23 10:54:35 +08:00
a426caaca3 BUGFIX: 系统消息发布 2026-01-23 10:54:03 +08:00
7cb7ce2836 Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2026-01-22 16:56:11 +08:00
8e075f1da4 BUGFIX: 通过hsv批量获取潘通信息,替换rgb 2026-01-22 16:55:00 +08:00
litianxiang
0f0fde2a3e Merge remote-tracking branch 'origin/dev-ltx' into dev/3.1_release_merge 2026-01-22 14:28:37 +08:00
litianxiang
8c6389a1f6 删除不用的字段 2026-01-22 14:28:10 +08:00
652f82b6a4 Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2026-01-22 13:56:44 +08:00
7ca2528dcf BUGFIX: design后未存储undivided layers 2026-01-22 13:56:07 +08:00
litianxiang
a7800913d2 Merge remote-tracking branch 'origin/dev-ltx' into dev/3.1_release_merge 2026-01-22 13:51:42 +08:00
litianxiang
1eaec64ff4 fix:GlobalAward读取配置错误 2026-01-22 13:51:13 +08:00
e603952332 Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2026-01-22 11:37:25 +08:00
2bc8b8ef96 BUGFIX: single design的渐变色未存储 2026-01-22 11:36:43 +08:00
0ce968b919 BUGFIX: 用户登录时的有效期验证异常抛出导致事务回滚,用户信息修改失败 2026-01-22 10:37:23 +08:00
litianxiang
dfc9ae4db2 GlobalAward站内信url修改 2026-01-21 16:50:01 +08:00
litianxiang
a3505c6d95 GlobalAward站内信url修改 2026-01-21 15:09:45 +08:00
litianxiang
6db0afd515 GlobalAward保存成功发送站内信,根据url可跳转且召回已填写资料 2026-01-21 14:59:41 +08:00
litianxiang
b1e6183dd1 GlobalAward接口token验证,id更换为uuid 2026-01-21 14:34:43 +08:00
30d08356c0 Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2026-01-21 14:14:17 +08:00
64cc29f456 TASK:Global Award邮箱验证 2026-01-21 14:13:33 +08:00
litianxiang
2b3e12a11c GlobalAward MINIO配置 2026-01-21 11:38:38 +08:00
litianxiang
d4a4724f61 GlobalAward拦截器配置 2026-01-21 10:35:22 +08:00
litianxiang
ba6e2bd24c GlobalAward拦截器配置 2026-01-21 10:21:17 +08:00
72ad977dcb BUGFIX: 获取近期新用户图表数据允许userType为null 2026-01-12 11:55:43 +08:00
26 changed files with 235 additions and 96 deletions

View File

@@ -559,7 +559,7 @@ public class GenerateConsumer {
log.info("============ProcessPoseTransformResult End listening==========");
}
@RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
/*@RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
@RabbitHandler
public void generateConsumer1(Message msg, Channel channel) {
generate(msg, channel, "consumer 1");
@@ -635,7 +635,7 @@ public class GenerateConsumer {
@RabbitHandler
public void getPoseTransformationResult(Message msg, Channel channel) {
processPoseTransformResult(msg, channel);
}
}*/
// @RabbitListener(queues = "#{rabbitMQProperties.queues.designBatch}")
// @RabbitHandler
// public void getDesignBatchResult(Message msg, Channel channel) {

View File

@@ -61,7 +61,9 @@ public class AuthenticationFilter extends OncePerRequestFilter {
, "/api/account/schoolLogin", "/api/account/enterpriseLogin", "/api/account/organizationNameSearch",
"/api/llm/stream",
//GlobalAwardController
"/api/global-award/"
"/api/global-award/uploads/pdf/init", "/api/global-award/uploads/pdf/chunk", "/api/global-award/uploads/pdf/complete", "/api/global-award/uploads/pdf/status",
"/api/global-award/uploads/video/init", "/api/global-award/uploads/video/chunk", "/api/global-award/uploads/video/complete", "/api/global-award/uploads/video/status",
"/api/global-award/contestants/save", "/api/global-award/contestants/by-email", "/api/global-award/checkEmail", "/api/global-award/checkCode"
);
@Override

View File

@@ -40,8 +40,8 @@ public class AccountTask {
accountService.extendValidityForCC();
}
// 每天凌晨0点执行一次
@Scheduled(cron = "0 0 0 * * ?")
// 每天凌晨0点执行一次 目前已没有角色类型为4的用户
/*@Scheduled(cron = "0 0 0 * * ?")
public void cancelActivityBenefits() {
// 1、查询当前所有参与了活动且过期的用户
List<Account> accountList = accountService.getExpiredUserBySystemUser(4);
@@ -51,7 +51,7 @@ public class AccountTask {
log.info("参与活动的用户{} : {} 于 {} 账号有效期到期,置为游客", account.getId(), account.getUserEmail(), account.getValidEndTime());
accountService.toVisitor(account);
}
}
}*/
// 每天检测正式用户到期情况每天凌晨0点执行
@Scheduled(cron = "0 0 0 * * ?")

View File

@@ -103,7 +103,7 @@ public class ConvenientInquiryController {
@GetMapping("/recentNewUserChart")
public Response<Map<String, Object>> recentNewUserChart(@Parameter(description = "startTime") @RequestParam @Nullable String startTime,
@Parameter(description = "endTime") @RequestParam @Nullable String endTime,
@Parameter(description = "userType") @RequestParam Integer userType) {
@Parameter(description = "userType") @RequestParam @Nullable Integer userType) {
return Response.success(convenientInquiryService.recentNewUserChart(startTime, endTime, userType));
}

View File

@@ -76,7 +76,9 @@ public class GlobalAwardController {
UploadCompleteResponse uploadCompleteResponse = uploadService.completePdfUpload(
request.getUploadId(),
request.getFileName(),
request.getTotalSize());
request.getTotalSize(),
request.getEmail(),
request.getSecureToken());
return Response.success(uploadCompleteResponse);
}
@@ -123,7 +125,9 @@ public class GlobalAwardController {
UploadCompleteResponse uploadCompleteResponse = uploadService.completeVideoUpload(
request.getUploadId(),
request.getFileName(),
request.getTotalSize());
request.getTotalSize(),
request.getEmail(),
request.getSecureToken());
return Response.success(uploadCompleteResponse);
}
@@ -141,10 +145,10 @@ public class GlobalAwardController {
return Response.success(globalAwardService.saveContestant(request));
}
@GetMapping("/contestants/by-email")
@ApiOperation(value = "根据邮箱查询参赛者", notes = "根据邮箱地址获取参赛者信息")
public Response<ContestantDTO> getContestantByEmail(@ApiParam(value = "参赛者邮箱地址", required = true) @RequestParam("email") String email) {
ContestantDTO dto = globalAwardService.getContestantByEmail(email);
@GetMapping("/contestants/{id}")
@ApiOperation(value = "根据id查询参赛者", notes = "根据id获取参赛者信息")
public Response<ContestantDTO> getContestantByID(@ApiParam(value = "参赛者id", required = true) @PathVariable("id") String id) {
ContestantDTO dto = globalAwardService.getContestantByID(id);
return Response.success(dto);
}
@@ -155,8 +159,8 @@ public class GlobalAwardController {
}
@GetMapping("/checkCode")
public Response<CheckOTPVO> checkOTP(@RequestParam("email") String email, @RequestParam("code") String code) {
return Response.success(globalAwardService.checkOTP(email, code));
public Response<CheckOTPVO> checkCode(@RequestParam("email") String email, @RequestParam("code") String code) {
return Response.success(globalAwardService.checkCode(email, code));
}
}

View File

@@ -18,11 +18,11 @@ import java.time.LocalDateTime;
@NoArgsConstructor
@AllArgsConstructor
@Builder
@TableName("submissions")
@TableName("contestants")
public class Contestant {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@TableId(value = "id", type = IdType.ASSIGN_UUID)
private String id;
private String email;
@@ -44,9 +44,6 @@ public class Contestant {
@TableField("phone_number")
private String phoneNumber;
@TableField("portfolio_url")
private String portfolioUrl;
@TableField("design_title")
private String designTitle;
@@ -65,8 +62,6 @@ public class Contestant {
@TableField("updated_at")
private LocalDateTime updatedAt;
@TableField("created_by")
private Long createdBy;
}

View File

@@ -50,11 +50,11 @@ public class ContestantDTO {
@ApiModelProperty(value = "视频文件路径", required = false, example = "contestants/user@example.com/2024/01/video_1234567890.mp4")
private String videoPath;
/**
* 是否确认覆盖已存在记录false 表示发现已有记录时仅返回 existingRecord不覆盖
*/
@ApiModelProperty(value = "是否确认覆盖已存在记录", required = false, example = "false")
private Boolean confirm = false;
// /**
// * 是否确认覆盖已存在记录false 表示发现已有记录时仅返回 existingRecord不覆盖
// */
// @ApiModelProperty(value = "是否确认覆盖已存在记录", required = false, example = "false")
// private Boolean confirm = false;
@NotBlank
private String secureToken;

View File

@@ -1,5 +1,6 @@
package com.ai.da.model.dto;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.media.Schema;
import com.ai.da.mapper.primary.entity.Gradient;
@@ -73,10 +74,12 @@ public class DesignSingleItemDTO implements Serializable {
@Schema(description = "45")
private double rotate;
/*@Schema(description = "带overall印花未分割图片")
@Hidden
@Schema(description = "带overall印花未分割图片")
private String undividedLayerBase64;
@Hidden
@Schema(description = "带overall/single印花未分割图片")
private String undividedLayerWithSinglePrintBase64;*/
private String undividedLayerWithSinglePrintBase64;
}

View File

@@ -36,4 +36,18 @@ public class UploadCompleteRequest {
@Positive(message = "文件大小必须大于0")
@ApiModelProperty(value = "文件总大小(字节)", required = true, example = "10485760")
private Long totalSize;
/**
* 用户邮箱
*/
@NotBlank(message = "用户邮箱不能为空")
@ApiModelProperty(value = "用户邮箱", required = true, example = "user@example.com")
private String email;
/**
* 安全令牌(邮箱验证令牌)
*/
@NotBlank(message = "安全令牌不能为空")
@ApiModelProperty(value = "安全令牌", required = true, example = "abc123def456")
private String secureToken;
}

View File

@@ -41,6 +41,13 @@ public class UploadInitRequest {
/**
* 用户邮箱
*/
@ApiModelProperty(value = "用户邮箱", required = false, example = "user@example.com")
@ApiModelProperty(value = "用户邮箱", required = true, example = "user@example.com")
private String email;
/**
* 安全令牌(邮箱验证令牌)
*/
@NotBlank(message = "安全令牌不能为空")
@ApiModelProperty(value = "安全令牌", required = true, example = "abc123def456")
private String secureToken;
}

View File

@@ -4309,7 +4309,7 @@ public class PythonService {
Map<String, Object> map = new HashMap<>();
map.put("prompt", prompt);
AuthPrincipalVo userHolder = UserContext.getUserHolder();
map.put("user_id", userHolder.getId());
map.put("user_id", userHolder.getId().toString());
log.info("brandDNAGenerate请求python 参数:####{}", map);
String param = JSON.toJSONString(map, SerializerFeature.WriteNullStringAsEmpty);
log.info(param);

View File

@@ -246,4 +246,6 @@ public interface AccountService extends IService<Account> {
void setEduAdminToExpire(Account adminAccount);
String getOrganizationTypeByRole(Integer roleNum);
void validateUserValidaExpire(Account account);
}

View File

@@ -53,7 +53,7 @@ public interface DesignItemService extends IService<DesignItem> {
DesignSingleVO designSingleIncludeLayers(DesignSingleIncludeLayersDTO designSingleIncludeLayersDTO);
// Map<String, List<String>> setPriorityAndUndividedLayer(JSONArray layers, DesignSingleIncludeLayersDTO designSingleIncludeLayersDTO);
Map<String, List<String>> setPriorityAndUndividedLayer(JSONArray layers, DesignSingleIncludeLayersDTO designSingleIncludeLayersDTO);
Map<String, String> setTypeAndUndividedLayer(JSONArray layers);

View File

@@ -13,11 +13,13 @@ public interface GlobalAwardService {
Map<String, Object> saveContestant(ContestantDTO request);
com.ai.da.model.dto.ContestantDTO getContestantByEmail(String email);
com.ai.da.model.dto.ContestantDTO getContestantByID(String email);
void checkEmail(String email);
CheckOTPVO checkOTP(String email, String otp);
CheckOTPVO checkCode(String email, String otp);
void checkSecurityToken(String email, String securityToken);
}

View File

@@ -39,9 +39,10 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
@@ -83,6 +84,9 @@ import java.util.stream.Collectors;
@Slf4j
@Service
public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> implements AccountService {
@Resource
private ApplicationContext applicationContext;
@Resource
private AccountMapper accountMapper;
@@ -279,7 +283,7 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
// 定义常量(临时)
private static final Integer SYSTEM_USER_TYPE_EDU_ADMIN = 7;
private void validateUserValidaExpire(Account account) {
public void validateUserValidaExpire(Account account) {
Long currentTime = new Date().getTime();
if (account.getSystemUser().equals(0)) {
return;
@@ -297,7 +301,9 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
if (isEduAdmin) {
setEduAdminToExpire(account);
} else {
toVisitor(account);
// 这里调用代理的 toVisitor 方法
AccountService proxy = applicationContext.getBean(AccountService.class);
proxy.toVisitor(account);
// return;
throw new BusinessException("account.expired", ResultEnum.PROMPT.getCode());
}
@@ -1949,6 +1955,7 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
return baseMapper.selectList(queryWrapper);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void toVisitor(Account account) {
accountMapper.toVisitor(account.getId());
}

View File

@@ -440,7 +440,18 @@ public class DesignItemServiceImpl extends ServiceImpl<DesignItemMapper, DesignI
// designItemDetail.setPrintJson(JSON.toJSONString(printObject));
designItemDetail.setPartialDesign(Objects.isNull(detail.getPrint()) ? null : detail.getPrint().getPartial());
designItemDetail.setGradientString(detail.getGradientString());
designItemDetails.add(designItemDetail);
// 处理gradientString为null的情况强制更新为null
if (Objects.isNull(detail.getGradientString()) && Objects.nonNull(designItemDetail.getId())) {
UpdateWrapper<DesignItemDetail> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("id", designItemDetail.getId());
updateWrapper.set("gradient_string", null);
updateWrapper.set("update_date", DateUtil.getByTimeZone(timeZone));
designItemDetailService.update(null, updateWrapper);
}
});
// 逻辑删除未复用的旧记录
@@ -987,8 +998,6 @@ public class DesignItemServiceImpl extends ServiceImpl<DesignItemMapper, DesignI
});
}
/*
取消存储UndividedLayer和UndividedLayerWithSinglePrint字段
private void undividedLayerBase64ToImage(List<DesignSingleItemDTO> designSingleItemDTOS) {
designSingleItemDTOS.forEach(item -> {
if (!StringUtil.isNullOrEmpty(item.getUndividedLayerBase64())) {
@@ -1023,10 +1032,9 @@ public class DesignItemServiceImpl extends ServiceImpl<DesignItemMapper, DesignI
}
}
});
}*/
}
/*@Override
取消存储UndividedLayer和UndividedLayerWithSinglePrint字段
@Override
public Map<String, List<String>> setPriorityAndUndividedLayer(JSONArray layers, DesignSingleIncludeLayersDTO designSingleIncludeLayersDTO) {
String designType = "default";
if (Objects.nonNull(designSingleIncludeLayersDTO)) {
@@ -1055,7 +1063,7 @@ public class DesignItemServiceImpl extends ServiceImpl<DesignItemMapper, DesignI
}
return priorityAndLayer;
}*/
}
// 由于在design过程中没有priority 优先级的概念并且在design时不会出现上下两件使用相同服装类型的情况所以这里依然保留这个方法。
@Override

View File

@@ -713,9 +713,9 @@ public class DesignServiceImpl extends ServiceImpl<DesignMapper, Design> impleme
Map<String, Integer> typePriority = list.stream().collect(Collectors.toMap(d -> d.getImageCategory().split("_")[0],
d -> Math.abs(d.getPriority()),
(existing, replacement) -> replacement));
// Map<String, String> typeAndUndividedLayer = designItemService.setTypeAndUndividedLayer(layers);
// log.info("all typeLayers Map:{}", typeAndUndividedLayer);
// Map<String, List<String>> priorityAndUndividedLayer = designItemService.setPriorityAndUndividedLayer(layers, null);
Map<String, String> typeAndUndividedLayer = designItemService.setTypeAndUndividedLayer(layers);
log.info("all typeLayers Map:{}", typeAndUndividedLayer);
Map<String, List<String>> priorityAndUndividedLayer = designItemService.setPriorityAndUndividedLayer(layers, null);
for (DesignPythonItem detail : item.getItems()) {
if (null == detail) {
continue;
@@ -727,10 +727,10 @@ public class DesignServiceImpl extends ServiceImpl<DesignMapper, Design> impleme
designItemDetail.setCollectionElementId(detail.getElementId());
designItemDetail.setCreateDate(DateUtil.getByTimeZone(timeZone));
log.info("detail.getType():{}", detail.getType());
/* if (!detail.getType().equals("Body")) {
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())) {
designItemDetail.setPath(detail.getBody_path());
//BODY不关联businessId
@@ -742,8 +742,8 @@ public class DesignServiceImpl extends ServiceImpl<DesignMapper, Design> impleme
DesignPythonItemPrint printObject = detail.getPrint().getOverall();
// designItemDetail.setPrintPath(Objects.isNull(printObject) ? "" : printObject.getPath());
designItemDetail.setPrintPath(CollectionUtils.isEmpty(printObject.getPrint_path_list()) ? "" : printObject.getPrint_path_list().get(0));
/*designItemDetail.setUndividedLayer(priorityAndUndividedLayer.get(designItemDetail.getPriority().toString()).get(0));
designItemDetail.setUndividedLayerWithSinglePrint(priorityAndUndividedLayer.get(designItemDetail.getPriority().toString()).get(1));*/
designItemDetail.setUndividedLayer(priorityAndUndividedLayer.get(designItemDetail.getPriority().toString()).get(0));
designItemDetail.setUndividedLayerWithSinglePrint(priorityAndUndividedLayer.get(designItemDetail.getPriority().toString()).get(1));
}
designItemDetailService.save(designItemDetail);
if (!SysFileLevel2TypeEnum.BODY.getRealName().equals(detail.getType()) && !StringUtil.isNullOrEmpty(designItemDetail.getPrintPath())) {
@@ -1154,7 +1154,7 @@ public class DesignServiceImpl extends ServiceImpl<DesignMapper, Design> impleme
.toLocalDateTime());
userPreference.setDesignItemId(designItem.getId());
userPreference.setProjectId(projectId);
if (workspaceRelStyles != null) {
if (workspaceRelStyles == null||workspaceRelStyles.isEmpty()) {
//查不到记录style应该是all
userPreference.setWorkspaceRelStyleId(0L);
} else {

View File

@@ -134,13 +134,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
throw new BusinessException("Email is required.");
}
String key = tokenCacheKey + request.getEmail();
String tokenCache = redisUtil.getFromString(key);
if (StringUtils.isBlank(tokenCache)) {
throw new BusinessException("请先完成邮箱认证");
} else if (!tokenCache.equals(request.getSecureToken())){
throw new BusinessException("身份认证失败,请先完成邮箱认证");
}
checkSecurityToken(request.getEmail(), request.getSecureToken());
QueryWrapper<Contestant> qw = new QueryWrapper<>();
qw.eq("email", request.getEmail());
@@ -157,7 +151,6 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
.age(request.getAge())
.countryRegionCity(request.getCountryRegionCity())
.phoneNumber(request.getPhoneNumber())
.portfolioUrl(request.getPortfolioUrl())
.designTitle(request.getDesignTitle())
.designDescription(request.getDesignDescription())
.pdfPath(request.getPdfPath())
@@ -167,6 +160,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
.build();
contestantMapper.insert(toInsert);
resp.put("success", true);
sendSiteMsg(toInsert.getId(), toInsert.getEmail());
return resp;
} else {
// update existing contestant
@@ -177,7 +171,6 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
existing.setAge(request.getAge());
existing.setCountryRegionCity(request.getCountryRegionCity());
existing.setPhoneNumber(request.getPhoneNumber());
existing.setPortfolioUrl(request.getPortfolioUrl());
existing.setDesignTitle(request.getDesignTitle());
existing.setDesignDescription(request.getDesignDescription());
existing.setPdfPath(request.getPdfPath());
@@ -190,18 +183,16 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
}
@Override
public ContestantDTO getContestantByEmail(String email) {
if (email == null) {
throw new BusinessException("Email is required.");
public ContestantDTO getContestantByID(String id) {
if (id == null) {
throw new BusinessException("id is required.");
}
QueryWrapper<Contestant> qw = new QueryWrapper<>();
qw.eq("email", email);
Contestant existing = contestantMapper.selectOne(qw);
Contestant existing = contestantMapper.selectById(id);
if (existing == null) {
return null;
}
ContestantDTO dto = new ContestantDTO();
dto.setEmail(existing.getEmail());
// dto.setEmail(existing.getEmail());
dto.setFirstName(existing.getFirstName());
dto.setLastName(existing.getLastName());
dto.setGender(existing.getGender());
@@ -209,7 +200,6 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
dto.setAge(existing.getAge());
dto.setCountryRegionCity(existing.getCountryRegionCity());
dto.setPhoneNumber(existing.getPhoneNumber());
dto.setPortfolioUrl(existing.getPortfolioUrl());
dto.setDesignTitle(existing.getDesignTitle());
dto.setDesignDescription(existing.getDesignDescription());
dto.setPdfPath(existing.getPdfPath());
@@ -217,6 +207,10 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
return dto;
}
/**
* 检查邮箱是否符合申请要求,发送验证码
* @param email AiDA邮箱
*/
public void checkEmail(String email) {
List<Integer> validRole = Arrays.asList(1, 2, 7, 8);
// 1. 验证邮箱在aida中有无账号
@@ -224,7 +218,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
queryWrapper.lambda().eq(Account::getUserEmail, email);
List<Account> accounts = accountMapper.selectList(queryWrapper);
if (accounts.isEmpty()) {
throw new BusinessException("请注册并订阅AiDA再重新提交申请");
throw new BusinessException("Please register and subscribe to AiDA, then resubmit your application.");
}
// 2. 验证账号是否是付费用户如果首次提交是但是修改的时候已经不是了how?不允许修改吗)
@@ -235,11 +229,17 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
SendEmailUtil.send(email, null,
SendEmailUtil.LOGIN_TEMPLATE_ID, randomVerifyCode);
} else {
throw new BusinessException("请订阅AiDA再重新提交申请");
throw new BusinessException("Please subscribe to AiDA, then resubmit your application.");
}
}
public CheckOTPVO checkOTP(String email, String otp) {
/**
* 验证验证码是否正确
* @param email 邮箱
* @param otp 一次性验证码
* @return 临时token和之前提交的表单内容
*/
public CheckOTPVO checkCode(String email, String otp) {
String otpCache = LocalCacheUtils.getVerifyCodeCache(AuthenticationOperationTypeEnum.GLOBAL_AWARD.name() + "_" + email);
assert otpCache != null;
if (otpCache.equals(otp)) {
@@ -247,14 +247,40 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
String secureToken = UUID.randomUUID().toString().replace("-", "");
redisUtil.addToString(tokenCacheKey + email, secureToken, 3 * 24 * 60 * 60L);
return new CheckOTPVO(secureToken, getContestantByEmail(email));
return new CheckOTPVO(secureToken, getContestantByID(email));
} else {
throw new BusinessException("验证码错误,请重试");
throw new BusinessException("Verification code is incorrect. Please try again.");
}
}
public void checkSecurityToken(String email, String securityToken) {
String key = tokenCacheKey + email;
if (StringUtils.isBlank(securityToken)) {
log.error("security token 缺失");
throw new BusinessException("Please complete email verification first.");
}
String tokenCache = redisUtil.getFromString(key);
if (StringUtils.isBlank(tokenCache)) {
log.error("security token 过期");
throw new BusinessException("Email verification has expired. Please verify again.");
} else if (!tokenCache.equals(securityToken)){
log.error("security token 与缓存不符");
throw new BusinessException("Identity verification failed. Please complete email verification first.");
}
}
// 发送站内信
public void sendSiteMsg(String applicationId, Long userId) {
public void sendSiteMsg(String applicationId, String email) {
Long userId;
QueryWrapper<Account> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(Account::getUserEmail, email);
List<Account> accounts = accountMapper.selectList(queryWrapper);
if (accounts.isEmpty()) {
throw new BusinessException("Please register and subscribe to AiDA, then resubmit your application.");
}else {
userId = accounts.get(0).getId();
}
PublishSysNotificationDTO sysNotificationDTO = new PublishSysNotificationDTO();
Notification notification = new Notification();
notification.setType("system");

View File

@@ -194,6 +194,8 @@ public class MessageCenterServiceImpl extends ServiceImpl<NotificationMapper, No
if (!type.equals("system")) {
// 个人未读消息
count = getUnreadCountByType(type, receiverId);
} else if (Objects.isNull(receiverId)) {
count = 1L;
} else {
// 系统未读消息
count = getUnreadSystemNotification(receiverId);
@@ -253,12 +255,14 @@ public class MessageCenterServiceImpl extends ServiceImpl<NotificationMapper, No
// 计算总的系统通知数量
QueryWrapper<Notification> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(Notification::getType, "system")
.gt(Notification::getCreateTime, account.getCreateDate())
.and(wrapper -> wrapper
.isNull(Notification::getReceiverId)
.or()
.eq(Notification::getReceiverId, receiverId)
);
if (Objects.nonNull(account)) {
queryWrapper.lambda().gt(Notification::getCreateTime, account.getCreateDate());
}
Long totalSysCount = baseMapper.selectCount(queryWrapper);
// 计算单个用户读了多少条系统数据

View File

@@ -258,6 +258,11 @@ public class PanToneServiceImpl extends ServiceImpl<PanToneMapper, PanTone> impl
d.setH(getRgbByHsvBatchDTO.getH());
d.setS(getRgbByHsvBatchDTO.getS());
d.setV(getRgbByHsvBatchDTO.getV());
// 不使用数据库中存储的RGB值使用通过hsv计算得到的RGB值
int[] rgb = PantoneUtils.hsvToRgb(d.getH(), d.getS(), d.getV());
d.setR(rgb[0]);
d.setG(rgb[1]);
d.setB(rgb[2]);
}
});
Map<Integer, PantoneVO> valueToPantoneVo = templateResposne.stream().collect(Collectors.toMap(

View File

@@ -3,6 +3,7 @@ package com.ai.da.service.upload;
import com.ai.da.model.dto.*;
import org.springframework.web.multipart.MultipartFile;
/**
* 分片上传服务接口
* 提供PDF和视频文件的分片上传、断点续传功能
@@ -36,7 +37,7 @@ public interface UploadService {
* @param totalSize 文件总大小
* @return 完成上传结果
*/
UploadCompleteResponse completePdfUpload(String uploadId, String fileName, long totalSize);
UploadCompleteResponse completePdfUpload(String uploadId, String fileName, long totalSize, String email, String secureToken);
/**
* 查询PDF上传状态
@@ -73,7 +74,7 @@ public interface UploadService {
* @param totalSize 文件总大小
* @return 完成上传结果
*/
UploadCompleteResponse completeVideoUpload(String uploadId, String fileName, long totalSize);
UploadCompleteResponse completeVideoUpload(String uploadId, String fileName, long totalSize, String email, String secureToken);
/**
* 查询视频上传状态

View File

@@ -88,6 +88,11 @@ public class UploadTask {
*/
UPLOADING,
/**
* 正在处理文件(合并分片、上传到存储)
*/
PROCESSING,
/**
* 上传完成
*/

View File

@@ -14,6 +14,7 @@ import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import java.io.FileInputStream;
import java.io.IOException;
@@ -59,20 +60,68 @@ public class UploadServiceImpl implements UploadService {
@Resource
private MinioUtil minioUtil;
@Value("${minio.bucket:contestants}")
@Value("${minio.bucketName.globalAward:global-award}")
private String minioBucket;
@Resource
private com.ai.da.service.GlobalAwardService globalAwardService;
// 内存存储上传任务状态
private final ConcurrentHashMap<String, UploadTask> uploadTasks = new ConcurrentHashMap<>();
// JSON序列化工具
private final ObjectMapper objectMapper = new ObjectMapper();
/**
* 应用启动时加载现有上传任务
*/
@PostConstruct
public void loadExistingTasks() {
try {
Path tempPath = Paths.get(tempDir);
if (!Files.exists(tempPath)) {
return;
}
Files.list(tempPath)
.filter(Files::isDirectory)
.forEach(uploadDir -> {
try {
String uploadId = uploadDir.getFileName().toString();
Path metadataPath = uploadDir.resolve("metadata.json");
if (Files.exists(metadataPath)) {
String json = Files.readString(metadataPath);
UploadTask task = objectMapper.readValue(json, UploadTask.class);
// 检查任务是否已过期
if (task.getExpiresAt().isAfter(LocalDateTime.now())) {
uploadTasks.put(uploadId, task);
log.info("加载现有上传任务: uploadId={}, status={}", uploadId, task.getStatus());
} else {
// 清理过期任务
cleanupTempFiles(uploadId);
log.info("清理过期上传任务: uploadId={}", uploadId);
}
}
} catch (Exception e) {
log.warn("加载上传任务失败: {}", uploadDir.getFileName(), e);
}
});
log.info("成功加载 {} 个现有上传任务", uploadTasks.size());
} catch (Exception e) {
log.error("加载现有上传任务时发生错误", e);
}
}
// ===== PDF上传实现 =====
@Override
public UploadTask initPdfUpload(UploadInitRequest request) {
// 验证安全令牌
globalAwardService.checkSecurityToken(request.getEmail(), request.getSecureToken());
// 验证PDF文件
validatePdfFile(request);
@@ -116,8 +165,10 @@ public class UploadServiceImpl implements UploadService {
}
@Override
@Async
public UploadCompleteResponse completePdfUpload(String uploadId, String fileName, long totalSize) {
public UploadCompleteResponse completePdfUpload(String uploadId, String fileName, long totalSize, String email, String secureToken) {
// 验证安全令牌
globalAwardService.checkSecurityToken(email, secureToken);
UploadTask task = validateAndGetTask(uploadId, "pdf");
log.info("开始PDF文件合并: uploadId={}, fileName={}", uploadId, fileName);
@@ -177,6 +228,9 @@ public class UploadServiceImpl implements UploadService {
@Override
public UploadTask initVideoUpload(UploadInitRequest request) {
// 验证安全令牌
globalAwardService.checkSecurityToken(request.getEmail(), request.getSecureToken());
// 验证视频文件
validateVideoFile(request);
@@ -220,8 +274,10 @@ public class UploadServiceImpl implements UploadService {
}
@Override
@Async
public UploadCompleteResponse completeVideoUpload(String uploadId, String fileName, long totalSize) {
public UploadCompleteResponse completeVideoUpload(String uploadId, String fileName, long totalSize, String email, String secureToken) {
// 验证安全令牌
globalAwardService.checkSecurityToken(email, secureToken);
UploadTask task = validateAndGetTask(uploadId, "video");
log.info("开始视频文件合并: uploadId={}, fileName={}", uploadId, fileName);

View File

@@ -22,7 +22,7 @@ spring.security.jwtExpiration=8640000000
spring.security.ignorePaths=/,/favicon.ico,/doc.html,/webjars/**,/swagger-resources,/v2/api-docs,\
/api/account/**,/api/element/**,/api/python/**,/api/design/**,/api/history/**,/api/library/**,/api/third/party/**,/api/generate/**,/api/workspace/**,/api/classification/**,\
/api/product/**,/api/ali-pay/**,/api/order-info/**,/api/paypal/**,/api/credits/**,/api/inquiry/**,/api/tasks/**,/api/python/prepareForSR,/api/alipay-hk/**,/api/portfolio/**,\
/api/stripe/**,/api/message/**,/api/tags/**,/notification/**,/api/affiliate/**,/api/project/**,/api/llm/**, /api/subscription_plan/**
/api/stripe/**,/api/message/**,/api/tags/**,/notification/**,/api/affiliate/**,/api/project/**,/api/llm/**, /api/subscription_plan/**,/api/global-award/**
spring.security.authApi=/auth/login
@@ -63,6 +63,7 @@ minio.bucketName.gradient=aida-gradient
minio.bucketName.modifiedSketch=aida-modified-sketch
minio.bucketName.slogan=aida-slogan
minio.bucketName.partialDesign=aida-partial-design
minio.bucketName.globalAward=global-award
redirect_url=http://18.167.251.121:7788
spring.rabbitmq.host=18.167.251.121
@@ -180,6 +181,4 @@ file.upload.max.size.video=104857600
# 上传任务过期时间(小时)
file.upload.task.expiry.hours=24
# MinIO配置
minio.bucket=contestants
global.award.link=https://develop.aida.com.hk/
global.award.link=https://develop.aida.com.hk/award/contestants?id=

View File

@@ -22,7 +22,7 @@ spring.security.jwtExpiration=604800000
spring.security.ignorePaths=/,/favicon.ico,/doc.html,/webjars/**,/swagger-resources,/v2/api-docs,\
/api/account/**,/api/element/**,/api/python/**,/api/design/**,/api/history/**,/api/library/**,/api/third/party/**,/api/generate/**,/api/workspace/**,/api/classification/**,\
/api/product/**,/api/ali-pay/**,/api/order-info/**,/api/paypal/**,/api/credits/**,/api/inquiry/**,/api/tasks/**,/api/python/prepareForSR,/api/alipay-hk/**,/api/portfolio/**,\
/api/stripe/**,/api/message/**,/api/tags/**,/notification/**,/api/affiliate/**,/api/project/**,/api/llm/**, /api/subscription_plan/**
/api/stripe/**,/api/message/**,/api/tags/**,/notification/**,/api/affiliate/**,/api/project/**,/api/llm/**, /api/subscription_plan/**,/api/global-award/**
spring.security.authApi=/auth/login
@@ -63,6 +63,7 @@ minio.bucketName.gradient=aida-gradient
minio.bucketName.modifiedSketch=aida-modified-sketch
minio.bucketName.slogan=aida-slogan
minio.bucketName.partialDesign=aida-partial-design
minio.bucketName.globalAward=global-award
redirect_url=http://18.167.251.121:7788
spring.rabbitmq.host=18.167.251.121
@@ -178,6 +179,4 @@ file.upload.max.size.video=104857600
# 上传任务过期时间(小时)
file.upload.task.expiry.hours=24
# MinIO配置
minio.bucket=contestants
global.award.link=https://www.aida.com.hk/
global.award.link=https://www.aida.com.hk/award/contestants?id=

View File

@@ -27,20 +27,20 @@ paypal.webhook_id=1D107312EX592781K
##### Stripe
# developer
#stripe.private-key=sk_test_51P4ZZL02n1TEydyN8qQHjOA9imsFU7Oxs2HMHGy2urHnnQgSHnZuu5vVP6pKhEACwUpsKNyrbZpdcg5TJWJLRHcY008dEO1fn2
stripe.private-key=sk_test_51P4ZZL02n1TEydyN8qQHjOA9imsFU7Oxs2HMHGy2urHnnQgSHnZuu5vVP6pKhEACwUpsKNyrbZpdcg5TJWJLRHcY008dEO1fn2
# dev 端点
#stripe.webhook-sign-secret=whsec_e0dBiJngx6qqgJj6yPyJ2A9ouh1Cjv5w
stripe.webhook-sign-secret=whsec_e0dBiJngx6qqgJj6yPyJ2A9ouh1Cjv5w
# local 端点
#stripe.webhook-sign-secret=whsec_TJcMSnAkh4uktrNY1M6Iy8XaVze4Rzqm
# kim - test
stripe.private-key=sk_test_51LwPrxH7nPZ8bkrNj67TFD7sxucaTANs1lf0KGSu1QSJfxYXcnigq2wTaZyZzST7y0fMbhhvaJZ4LjjFhr95M83a00eXrmOTL0
#stripe.private-key=sk_test_51LwPrxH7nPZ8bkrNj67TFD7sxucaTANs1lf0KGSu1QSJfxYXcnigq2wTaZyZzST7y0fMbhhvaJZ4LjjFhr95M83a00eXrmOTL0
# prod 端点
#stripe.webhook-sign-secret=whsec_GoyVEAaBtuGD5Rt55z83JnPnLDAZTN3u
# local 端点
#stripe.webhook-sign-secret=whsec_NvwM3hDQiN5GXclYOYekE9IKHLjmROF8
# dev 端点
stripe.webhook-sign-secret=whsec_pX0pPMQm85PaUSWnFMEzoccb3MGNkjoL
#stripe.webhook-sign-secret=whsec_pX0pPMQm85PaUSWnFMEzoccb3MGNkjoL
# kim - live
#stripe.private-key=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