1016 Commits

Author SHA1 Message Date
14dfe2806c merge dev 2026-04-10 23:27:37 +08:00
798c7b0592 Merge branch 'release/3.1' into dev/3.1_release_merge 2026-04-10 23:09:33 +08:00
9bd10581f4 BUGFIX:获取relight结果时删除了排序记录 2026-04-10 23:03:15 +08:00
1f288fe5e3 BUGFIX 2026-04-10 22:55:44 +08:00
72602eb245 BUGFIX 2026-04-10 22:51:00 +08:00
983d53268d DEBUG 2026-04-10 22:32:55 +08:00
f3aeeb3584 DEBUG 2026-04-10 22:21:56 +08:00
5d3692a204 BUGFIX:支付失败后的邮件通知类型错误(临时处理) 2026-04-08 13:52:38 +08:00
f2a074b2f6 Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2026-03-31 15:19:56 +08:00
6a7a37dcec BUGFIX:只有Printboard时,首次design没有使用元素 2026-03-31 14:12:43 +08:00
litianxiang
c4d2780f0e TO DEV 2026-03-31 13:55:32 +08:00
litianxiang
1da6b7728c Merge remote-tracking branch 'origin/dev/3.1_release_merge' into release/3.1 2026-03-30 17:05:43 +08:00
litianxiang
0faf77899b fix:PRINTBOARD_HIGH_I2I与PRINTBOARD_ADVANCED_I2I使用模型一致导致积分扣除错误 2026-03-27 16:49:10 +08:00
litianxiang
e4940019bf 框选适配py 2026-03-27 15:19:38 +08:00
litianxiang
0da66ff210 print t2i模型替换 2026-03-27 15:16:33 +08:00
litianxiang
5dd862ff79 MOOD_BOARD high 去掉翻译 2026-03-26 16:13:43 +08:00
litianxiang
edaec9884d TO PROD 2026-03-25 22:28:44 +08:00
litianxiang
76eeb2be53 moodboard基础模型修改 2026-03-25 10:39:22 +08:00
litianxiang
cb6f94d2d4 py api fix 2026-03-25 10:19:06 +08:00
litianxiang
28656c44c8 FIX FLUX2 2026-03-24 16:24:43 +08:00
litianxiang
6757a89d04 Pattern模式参数fix 2026-03-24 15:54:53 +08:00
litianxiang
9be1a1e307 加锁解决不同线程读取前还未保存的问题 2026-03-24 15:49:16 +08:00
litianxiang
2168978f61 print pattern也改为flux2 2026-03-24 15:32:06 +08:00
litianxiang
54466b935d debug 2026-03-24 15:23:33 +08:00
litianxiang
c970ebe691 debug 2026-03-24 15:15:59 +08:00
litianxiang
1c5a3a12b9 debug 2026-03-24 15:04:40 +08:00
litianxiang
6e06000083 debug 2026-03-24 14:46:01 +08:00
litianxiang
dea2b3be42 debug 2026-03-24 14:29:08 +08:00
litianxiang
bcf51aea23 debug 2026-03-24 14:20:39 +08:00
litianxiang
0c9d5404c6 flux2失败状态判断 2026-03-24 14:05:27 +08:00
litianxiang
93429839c0 本地flux改为flux2 2026-03-24 13:39:38 +08:00
litianxiang
27859c3e28 Merge remote-tracking branch 'origin/release/3.1' into dev/3.1_release_merge 2026-03-23 14:11:33 +08:00
litianxiang
f02c0930a6 日志切面(controller层报错打印) 2026-03-23 13:56:47 +08:00
litianxiang
d57bb83b25 Merge remote-tracking branch 'origin/release/3.1' into release/3.1 2026-03-23 13:50:44 +08:00
731e34f133 TO DEV 2026-03-23 13:38:10 +08:00
75eca8d6ba Merge branch 'release/3.1' into dev/3.1_release_merge
# Conflicts:
#	src/main/java/com/ai/da/python/PythonService.java
2026-03-23 13:22:18 +08:00
3e53401f76 TASK:返回符合查询条件的金额总计 2026-03-23 11:55:07 +08:00
litianxiang
b6a068ebcd SKETCHBOARD传入的text改为获取第一个,为分割获取style的方式 2026-03-23 11:50:24 +08:00
litianxiang
dc291ea086 加入非空校验 2026-03-14 01:50:39 +08:00
litianxiang
2e846e671a romantic风格缺少下装fix 2026-03-13 10:06:26 +08:00
litianxiang
a5093311f9 当style为洛丽塔时无sketch和谷歌风控问题FIX 2026-03-12 19:06:54 +08:00
litianxiang
aed338a6d7 当style为洛丽塔时无sketch和谷歌风控问题FIX 2026-03-12 18:59:17 +08:00
litianxiang
8bdb49d25c 当style为洛丽塔时无sketch和谷歌风控问题FIX 2026-03-12 18:49:57 +08:00
litianxiang
5d53a8cd42 当style为洛丽塔时无sketch和谷歌风控问题FIX 2026-03-12 18:49:28 +08:00
litianxiang
61b7f3072f 当style为洛丽塔时无sketch和谷歌风控问题FIX 2026-03-12 18:36:21 +08:00
litianxiang
a1f489f3a1 比赛url修改 2026-03-12 17:39:05 +08:00
litianxiang
fc3fd877a8 transpose和rotate获取位置修改 2026-03-05 16:58:17 +08:00
litianxiang
fc72d2c430 transpose和rotate获取位置修改 2026-03-05 13:29:14 +08:00
litianxiang
1ac01dd090 测试token恢复 2026-02-25 16:36:06 +08:00
litianxiang
3bbdf7c672 fix:按编号导出参赛选手文件 2026-02-09 10:33:25 +08:00
litianxiang
0646484fba 按编号导出参赛选手文件 2026-02-09 10:21:40 +08:00
litianxiang
96b8613741 映射temp到服务器 2026-02-06 17:29:42 +08:00
litianxiang
cf30226a51 映射temp到服务器 2026-02-06 17:24:43 +08:00
litianxiang
3c15a3ff68 映射temp到服务器 2026-02-06 17:21:07 +08:00
litianxiang
0c904be227 测试临时token 2026-02-06 11:42:34 +08:00
litianxiang
7759b56123 Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev/3.1_release_merge 2026-02-05 17:39:15 +08:00
litianxiang
d5bfaa8822 fix:允许图生图不带提示词 2026-02-05 17:38:38 +08:00
967c0cbc01 Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2026-02-05 16:55:24 +08:00
417e34b41a BUGFIX:1.首次design没有使用library和生成的印花2.design overall印花太小 2026-02-05 16:54:45 +08:00
litianxiang
d51aa84647 fix:参赛者根据链接返回文件参数 2026-02-05 09:41:10 +08:00
litianxiang
5895bc6ab6 Revert "fix:参赛者根据链接返回文件参数"
This reverts commit 3301869f20.
2026-02-05 09:40:35 +08:00
litianxiang
3301869f20 fix:参赛者根据链接返回文件参数 2026-02-05 09:40:15 +08:00
litianxiang
1ec42f4ad5 fix:参赛者id逻辑更改 2026-02-04 17:20:22 +08:00
cc506ff7e9 Merge branch 'dev/3.1_release_merge' into release/3.1 2026-02-04 17:05:59 +08:00
litianxiang
f2d43f06f4 Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev/3.1_release_merge 2026-02-04 15:28:08 +08:00
litianxiang
9251df49f8 比赛新增文件大小和视频时长 2026-02-04 15:27:51 +08:00
430156f4e8 Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2026-02-04 14:48:38 +08:00
litianxiang
d1123aedcc fix:导出为页面下载 2026-02-04 14:45:11 +08:00
8c007077a3 BUGFIX: detail中的merge模式下没有存储partialDesign的图片 2026-02-04 14:43:29 +08:00
litianxiang
d63b4b4e63 fix:参赛选手加入编号 2026-02-04 14:03:30 +08:00
litianxiang
b826f0bf39 参赛选手加入编号,增加导出功能 2026-02-04 13:41:16 +08:00
litianxiang
1decd8e258 参赛选手加入编号,增加导出功能 2026-02-04 13:41:09 +08:00
litianxiang
1286e84488 Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev-ltx 2026-02-04 13:21:19 +08:00
a252fdf7f9 BUGFIX: detail中的default模式报错 2026-02-03 16:56:15 +08:00
807d802178 TASK:motion 参数数据类型变更 2026-02-02 15:30:04 +08:00
53f1b548be CONFIG 2026-02-02 15:28:54 +08:00
45dd78032a BUGFIX: 1.token过期,重新登录无法解决 2.motion生成参数数据类型变更 2026-02-02 15:04:27 +08:00
c160da5132 BUGFIX: token过期,重新登录无法解决 2026-02-02 14:57:32 +08:00
b23faeeee2 Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2026-02-02 13:32:55 +08:00
67789abca4 TASK:getAllPose id的数据类型改为整型 2026-02-02 13:32:27 +08:00
1c78d66aab Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2026-01-30 17:14:50 +08:00
528bc69923 BUGFIX: design single merge模式下取消传递print及elements等元素 2026-01-30 17:10:37 +08:00
litianxiang
22880d128d Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev-ltx 2026-01-30 15:40:25 +08:00
9c56a102cc Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2026-01-29 14:38:20 +08:00
2f59fe074f BUGFIX: 管理员修改用户身份为游客 2026-01-29 14:37:54 +08:00
9c61b1c8fe Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2026-01-29 10:12:47 +08:00
e30fdf7401 BUGFIX:模特上传,事务管理不统一导致library出现孤儿数据 2026-01-29 10:10:21 +08:00
ba2d10afbc paymentMethodConfiguration切换 2026-01-28 15:41:52 +08:00
6146112d04 TO PROD 2026-01-27 16:39:39 +08:00
412550df27 BUGFIX:管理员查design频次与chart中获取到的数量有区别 2026-01-27 14:59:39 +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
3e334d7956 Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev-ltx 2026-01-26 11:16:46 +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
litianxiang
a38895b028 GlobalAward拦截器配置 2026-01-21 10:13:11 +08:00
litianxiang
69a95e66ca GlobalAward上传文件 2026-01-20 16:37:46 +08:00
litianxiang
40518cab37 Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev-ltx
# Conflicts:
#	src/main/java/com/ai/da/controller/GlobalAwardController.java
#	src/main/java/com/ai/da/model/dto/ContestantDTO.java
#	src/main/resources/application-dev.properties
#	src/main/resources/application-prod.properties
2026-01-20 16:20:41 +08:00
litianxiang
46d61cb73f GlobalAward上传文件 2026-01-20 15:58:27 +08:00
08f20fd1fe Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2026-01-20 13:24:49 +08:00
d7edc166b3 TASK:Global Award邮箱验证 2026-01-20 13:14:50 +08:00
litianxiang
79ad02f66b fix:style为all时,like报错 2026-01-19 16:50:14 +08:00
litianxiang
5e261b55c7 Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev/3.1_release_merge 2026-01-19 16:41:02 +08:00
litianxiang
bc92fcbaf4 Merge remote-tracking branch 'origin/dev-ltx' into dev/3.1_release_merge 2026-01-19 16:40:58 +08:00
litianxiang
c6aec917c2 fix:style为all时,like报错 2026-01-19 16:40:28 +08:00
6bc500e78f Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2026-01-16 17:17:25 +08:00
4c43b98c02 TASK:DB中PartialDesign为空时,取undivided_layer作为merge_image_path 2026-01-16 17:17:04 +08:00
litianxiang
5bae785a9f Merge remote-tracking branch 'origin/dev-ltx' into dev/3.1_release_merge 2026-01-16 16:37:49 +08:00
litianxiang
7b619aa4cb GlobalAward首次提交 2026-01-16 16:37:03 +08:00
c93ad6daa9 Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2026-01-16 16:24:38 +08:00
0047be7a03 BUGFIX:PartialDesign传空时,先从数据库获取原数据 2026-01-16 16:23:56 +08:00
4ef209cfd4 Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2026-01-16 14:28:27 +08:00
a19751b4b7 BUGFIX:designType参数校验;print数据验空 2026-01-16 14:28:04 +08:00
litianxiang
bb0e5a4263 Merge remote-tracking branch 'origin/dev-ltx' into dev/3.1_release_merge 2026-01-16 11:04:52 +08:00
litianxiang
9e9df5367d fix:接口SegAnything返回值处理 2026-01-16 11:04:18 +08:00
ba8a2c52de Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev/3.1_release_merge 2026-01-15 17:36:37 +08:00
39d8c7efcf TASK:取消存储/返回UndividedLayer和UndividedLayerWithSinglePrint字段 2026-01-15 17:35:55 +08:00
litianxiang
401910901a Merge remote-tracking branch 'origin/dev-ltx' into dev/3.1_release_merge
# Conflicts:
#	src/main/java/com/ai/da/python/PythonService.java
2026-01-15 17:21:30 +08:00
litianxiang
3f5ce6e0e7 接口SegAnything返回值处理 2026-01-15 17:17:08 +08:00
0787025151 TASK:merge 模式返回mask 2026-01-15 14:07:18 +08:00
08b26872ff Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2026-01-14 14:28:05 +08:00
5bbf1326bb TASK:design single部分cv操作前置,新增merge | default两种designType 2026-01-14 14:26:47 +08:00
litianxiang
c5e27cd220 Merge remote-tracking branch 'origin/dev-ltx' into dev/3.1_release_merge 2026-01-14 13:55:01 +08:00
litianxiang
112e9c3bc9 对接前端和py接口SegAnything 2026-01-14 13:31:33 +08:00
litianxiang
ce95cb5080 Merge remote-tracking branch 'origin/dev-ltx' into dev/3.1_release_merge 2026-01-12 14:42:02 +08:00
litianxiang
71211bfbc3 修改存入userPreference表的时间方式 2026-01-12 14:41:24 +08:00
72ad977dcb BUGFIX: 获取近期新用户图表数据允许userType为null 2026-01-12 11:55:43 +08:00
litianxiang
6400e79929 Merge remote-tracking branch 'origin/dev-ltx' into dev/3.1_release_merge 2026-01-09 14:49:25 +08:00
litianxiang
dd8c72f7d7 切换用户sketch点赞记录存储方式;新增镜像和角度字段,存储前端需要的object 2026-01-09 10:14:46 +08:00
13151b65f5 TASK:限制同一个管理员不允许绑定不同组织的订阅计划 2026-01-07 15:24:38 +08:00
9f523d5953 TASK:分页获取所有用户id,添加按邮箱模糊查询 2026-01-07 11:26:39 +08:00
4879cfeb60 BUGFIX: 2026-01-07 09:53:58 +08:00
9e252b16ef BUGFIX: 2026-01-06 17:36:12 +08:00
e64add14af BUGFIX:更新订阅计划时根据业务需要对参数进行判断并在需要时更新管理员信息 2026-01-06 17:29:33 +08:00
3beb27e491 TASK:获取用户id信息做分页;订阅计划添加国家或地区字段 2026-01-06 09:56:21 +08:00
501032ef17 TASK:试用用户试用期延长至7天 2025-12-31 13:15:13 +08:00
litianxiang
cb25bdd2e0 Merge remote-tracking branch 'origin/dev-ltx' into dev/3.1_release_merge 2025-12-29 14:57:41 +08:00
litianxiang
7a9fb0213b 适配新推荐接口 2025-12-29 13:49:31 +08:00
cd767dce6f BUGFIX:新用户不能获取历史系统通知 2025-12-24 11:47:11 +08:00
bf95b85841 to dev 2025-12-23 16:28:07 +08:00
9e58bd9e7d Merge branch 'release/3.1' into dev/3.1_release_merge
# Conflicts:
#	src/main/java/com/ai/da/common/utils/SendRequestUtil.java
2025-12-23 16:16:30 +08:00
d0ec5c5c26 BUGFIX:邮件发送失败 2025-12-23 16:03:48 +08:00
ab8aa5ea5c Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2025-12-23 14:07:53 +08:00
aefcd2fdb0 BUGFIX:邮件发送失败 2025-12-23 14:07:26 +08:00
e74eab1070 BUGFIX:邮件发送失败 2025-12-23 14:05:20 +08:00
litianxiang
34da437a26 Merge remote-tracking branch 'origin/dev-ltx' into dev/3.1_release_merge 2025-12-22 11:36:23 +08:00
litianxiang
f84935d0bd 登录token存入redis 2025-12-22 11:35:38 +08:00
35edaa0f27 CONFIG: 拦截器配置 2025-12-19 21:43:02 +08:00
f43099e19e CONFIG: redis 配置修改 2025-12-19 21:21:21 +08:00
8079877734 CONFIG: TO DEV 2025-12-19 17:40:37 +08:00
ef686e38ac CONFIG: TO PROD 2025-12-19 17:33:51 +08:00
100019d2a4 Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev/3.1_release_merge 2025-12-19 16:00:55 +08:00
litianxiang
12af237d76 Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev/3.1_release_merge 2025-12-19 15:47:36 +08:00
litianxiang
44dbbb2a4b 更换Moodboard和Printboard提示词 2025-12-19 15:47:07 +08:00
9f42e153a4 Merge branch 'release/3.1' into dev/3.1_release_merge
# Conflicts:
#	.gitea/workflows/develop_build_manual.yaml
2025-12-19 15:01:32 +08:00
4fa70a1c90 BUGFIX:订阅计划创建不允许指定子账号为管理员 2025-12-18 18:03:03 +08:00
dfb34916e7 BUGFIX:订阅计划与子账号新增 2025-12-18 14:52:12 +08:00
9f7987306c BUGFIX:订阅计划 2025-12-18 13:38:38 +08:00
litianxiang
d3fc70fbf2 fix:edit产品图照成排序问题,恢复原逻辑 2025-12-17 16:08:49 +08:00
litianxiang
17645d17e5 关闭batch MQ监听 2025-12-17 16:02:49 +08:00
litianxiang
258eea5277 edit 产品图失败会导致sort不对试验5 2025-12-17 15:43:26 +08:00
litianxiang
bb1d3bd359 Revert "edit 产品图失败会导致sort不对试验5"
This reverts commit 6a8c87ed95.
2025-12-17 15:41:02 +08:00
litianxiang
6a8c87ed95 edit 产品图失败会导致sort不对试验5 2025-12-17 15:40:47 +08:00
litianxiang
eb3826927d edit 产品图失败会导致sort不对试验4 2025-12-17 15:33:14 +08:00
litianxiang
7720c8c771 edit 产品图失败会导致sort不对试验3 2025-12-17 14:12:20 +08:00
litianxiang
b459148d58 edit 产品图失败会导致sort不对试验2 2025-12-17 13:49:07 +08:00
litianxiang
eadda18d1e Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev/3.1_release_merge 2025-12-17 13:28:12 +08:00
litianxiang
d403df51ec edit 产品图失败会导致sort不对试验 2025-12-17 13:28:04 +08:00
6903b98b60 Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev/3.1_release_merge 2025-12-17 13:20:34 +08:00
81bf65515c Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2025-12-17 13:19:54 +08:00
8e984eb283 BUGFIX:订阅计划 2025-12-17 13:18:24 +08:00
litianxiang
afc6041570 临时测试修改 2025-12-17 13:10:09 +08:00
bce368248c Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2025-12-16 16:26:27 +08:00
ca7121dcda BUGFIX:订阅计划 2025-12-16 16:24:52 +08:00
litianxiang
9a206f9979 生产环境配置callbackUrl 2025-12-16 14:10:22 +08:00
litianxiang
eb7a46c7e8 fix:callbackUrl 2025-12-16 13:45:21 +08:00
litianxiang
95ef68a784 Merge remote-tracking branch 'origin/dev-ltx' into dev/3.1_release_merge 2025-12-16 13:20:31 +08:00
litianxiang
6429288fd9 dev环境加入design回调配置 2025-12-16 13:16:36 +08:00
c5af194876 BUGFIX 2025-12-16 10:42:31 +08:00
da84e1e4b4 注解修改 2025-12-15 18:39:16 +08:00
95a9c81a1b Merge branch 'dev/dev_xp' into dev/3.1_release_merge
# Conflicts:
#	src/main/java/com/ai/da/model/dto/SubscriptionPlanDTO.java
#	src/main/java/com/ai/da/model/vo/SubscriptionPlanVO.java
2025-12-15 18:34:30 +08:00
81c0d7eeac TASK:订阅计划相关 2025-12-15 18:30:28 +08:00
litianxiang
fbc473735c fix:对没有like的已发布作品进行二创,会不显示原作者名字 2025-12-15 15:41:58 +08:00
litianxiang
9f48a2ce09 fix:升级swagger注解 2025-12-15 13:38:44 +08:00
459c743ce4 CONFIG: 2025-12-11 16:58:24 +08:00
ce3516916d CONFIG: 2025-12-11 16:18:37 +08:00
0692b29065 Merge branch 'dev/dev_xp' into dev/3.1_release_merge
# Conflicts:
#	src/main/java/com/ai/da/controller/AccountController.java
2025-12-11 16:12:41 +08:00
94cafbd10c TASK:flux积分不足,邮件通知 2025-12-11 16:07:14 +08:00
5c2008ec4a TASK:订阅计划,测试修改 2025-12-11 15:26:20 +08:00
litianxiang
4e4b8bd4d2 Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev-ltx 2025-12-11 15:12:22 +08:00
litianxiang
9c19d061be fix:升级swagger注解 2025-12-11 10:35:08 +08:00
7f094265da TASK:新增订阅计划概念 2025-12-11 09:44:25 +08:00
22bc8750c8 Merge branch 'dev-ltx' into dev/dev_xp 2025-12-03 16:53:17 +08:00
a940105fa4 DEV 数据库切换 2025-12-03 14:18:58 +08:00
4c0edf09bd Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2025-12-03 14:14:11 +08:00
bd69793a72 TASK:订阅到期通知或续订通知(暂时关闭邮件发送) 2025-12-03 13:55:52 +08:00
litianxiang
a643338916 fix:接口文档打不开问题pom更新 2025-12-02 15:43:16 +08:00
litianxiang
9344a946ad fix:接口文档打不开问题 2025-12-02 15:42:51 +08:00
fab0c7b372 更新 .gitea/workflows/develop_build_manual.yaml 2025-12-02 14:48:23 +08:00
fc0867d9b1 Merge branch 'dev/3.1_release_merge' into dev/dev_xp 2025-12-02 14:46:23 +08:00
c36ba6211a DEV 数据库切换 2025-12-02 14:34:12 +08:00
litianxiang
aa0a787e3f dev跨域问题初步验证 2025-12-02 14:27:31 +08:00
litianxiang
964ee1c5cc dev数据库切换 2025-12-02 14:18:18 +08:00
ac98cd01db DEV JDK版本升级,redis配置修改 2025-12-02 13:53:43 +08:00
70d498b90d 更新 .gitea/workflows/develop_build_manual.yaml 2025-12-02 13:14:26 +08:00
ae1a2eff2a 更新 .gitea/workflows/develop_build_manual.yaml 2025-12-02 13:12:38 +08:00
b54eaea7e3 更新 .gitea/workflows/develop_build_manual.yaml 2025-12-02 12:16:01 +08:00
aa2363b9a5 更新 .gitea/workflows/develop_build_manual.yaml 2025-12-02 12:11:04 +08:00
41ef9132e9 更新 .gitea/workflows/develop_build_manual.yaml 2025-12-02 11:05:42 +08:00
3b5b57ab08 更新 .gitea/workflows/develop_build_manual.yaml 2025-12-02 10:55:21 +08:00
2ec9ef3290 上传文件至「.gitea/workflows」 2025-12-02 10:49:14 +08:00
fe3fbbe135 DEV 切换数据库 2025-12-02 10:21:07 +08:00
01e82b4c23 Merge branch 'dev/3.1_release_merge' into dev/dev_xp 2025-12-01 17:11:03 +08:00
litianxiang
e085275aee Merge branch 'dev-ltx' into dev/3.1_release_merge
# Conflicts:
#	src/main/java/com/ai/da/service/impl/DesignItemServiceImpl.java
2025-12-01 17:10:35 +08:00
litianxiang
fa7271567e 解决循环依赖问题 2025-12-01 17:05:57 +08:00
05049ae7a2 [run build] 2025-12-01 16:39:26 +08:00
b023a68f83 Merge remote-tracking branch 'origin/dev/dev_xp' into dev/dev_xp 2025-12-01 16:02:20 +08:00
6cd42b799a 删除 .gitea/workflows/prod_build_schedule.yaml 2025-12-01 10:22:29 +08:00
6e1ed7f9b8 删除 .gitea/workflows/prod_build_manual.yaml 2025-12-01 10:22:25 +08:00
b7be16738b 删除 .gitea/workflows/develop_build_manual.yaml 2025-12-01 10:22:21 +08:00
6da5e91ec1 删除 .gitea/workflows/develop_build_commit.yaml 2025-12-01 10:22:17 +08:00
00c0a65547 删除 .gitea/workflows/prod_build_schedule.yaml 2025-12-01 10:22:09 +08:00
77aab576de 删除 .gitea/workflows/develop_build_manual.yaml 2025-12-01 10:22:06 +08:00
5b2c77f81b 删除 .gitea/workflows/develop_build_commit.yaml 2025-12-01 10:22:02 +08:00
96040f2349 删除 docker-compose.yml
All checks were successful
git commit 控制 AiDA back-java Develop 分支构建部署 / build_and_deploy (push) Has been skipped
2025-11-30 11:01:40 +08:00
a710fdd432 删除 docker-compose.yml 2025-11-30 11:01:12 +08:00
d598f53d3c Merge branch 'dev/3.1_release_merge' into release/3.1
# Conflicts:
#	.gitea/workflows/prod_build_schedule.yaml
2025-11-28 17:16:55 +08:00
62bf538d96 Merge branch 'dev/dev_xp' into dev/3.1_release_merge
All checks were successful
git commit 控制 AiDA back-java Develop 分支构建部署 / build_and_deploy (push) Has been skipped
2025-11-28 16:38:09 +08:00
456cb1ff19 Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev/3.1_release_merge 2025-11-28 16:37:56 +08:00
cbca666e7b BUGFIX: 账号重置为游客后,提示混乱 2025-11-28 16:36:34 +08:00
d622195f9d 更新 .gitea/workflows/develop_build_commit.yaml
All checks were successful
git commit 控制 AiDA back-java Develop 分支构建部署 / build_and_deploy (push) Has been skipped
2025-11-28 16:06:56 +08:00
1917fd518d 更新 docker-compose.yml
All checks were successful
手动 AiDA back-java Develop 分支构建部署 / build_and_deploy (push) Successful in 2m3s
[run build]
2025-11-28 15:35:50 +08:00
96170a9956 更新 .gitea/workflows/prod_build_manual.yaml 2025-11-28 15:25:50 +08:00
8205fb5290 上传文件至「.gitea/workflows」 2025-11-28 15:25:41 +08:00
8f72686809 添加 .gitea/workflows/prod_build_schedule.yaml
All checks were successful
手动 AiDA back-java Develop 分支构建部署 / build_and_deploy (push) Has been skipped
2025-11-28 15:18:20 +08:00
37ddf6f441 更新 .gitea/workflows/develop_build.yaml
All checks were successful
手动 AiDA back-java Develop 分支构建部署 / build_and_deploy (push) Has been skipped
2025-11-28 15:14:57 +08:00
dbf9b2d722 添加 .gitea/workflows/develop_build.yaml
Some checks failed
手动 AiDA back-java Develop 分支构建部署 / build_and_deploy (push) Has been cancelled
2025-11-28 15:13:48 +08:00
a91f9ccdd4 更新 .gitea/workflows/develop_build_manual.yaml 2025-11-28 15:09:33 +08:00
dac51afe73 添加 docker-compose.yml 2025-11-28 15:04:01 +08:00
3aa744895f 添加 .gitea/workflows/develop_build_manual.yaml 2025-11-28 14:55:50 +08:00
9535d8ce59 Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2025-11-28 14:40:38 +08:00
6c8b316dfd BUGFIX: 添加已存在的账号为子账号,该账号有效期没有同步修改 2025-11-28 14:40:09 +08:00
e366d5a2c5 Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2025-11-28 13:41:35 +08:00
b6add404b3 BUGFIX: 添加已存在的账号为子账号,该账号有效期没有同步修改 2025-11-28 13:36:46 +08:00
fcbe4762b3 TO prod 2025-11-27 17:38:24 +08:00
e750adcc94 TO prod 2025-11-27 17:35:47 +08:00
litianxiang
1c782f8fd7 dev fix:designSingle代码本地提交 sysfile加入style字段 2025-11-27 11:33:20 +08:00
litianxiang
b58b8df88f Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev/3.1_release_merge 2025-11-26 16:14:09 +08:00
litianxiang
c09f734a30 fix:兼容老数据detail会创建新数据的问题 2025-11-26 16:13:39 +08:00
1464689657 TASK:视频生成完成站内信语言给中英双语 2025-11-26 10:09:59 +08:00
litianxiang
a2ff345da5 升级JDK到21 2025-11-25 16:46:05 +08:00
9ae1626309 Merge branch 'refs/heads/dev/3.1_release_merge' into dev/dev_xp 2025-11-25 14:25:59 +08:00
70a41bdfbc TASK:用户账号到期邮件通知 2025-11-25 14:24:30 +08:00
litianxiang
8757db4f3d Merge remote-tracking branch 'origin/dev-ltx' into dev/3.1_release_merge 2025-11-25 11:46:29 +08:00
litianxiang
a8e3304db2 Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev-ltx 2025-11-25 11:45:49 +08:00
litianxiang
26f2299381 designSingle改为直接在源数据进行修改而不是逻辑删除再创建新数据 2025-11-25 11:45:09 +08:00
c1a5799da7 to dev 2025-11-25 10:15:32 +08:00
94c0e81335 BUGFIX: 打开佣金计算定时器 2025-11-25 10:10:14 +08:00
b9641474ba Merge branch 'release/3.1' into dev/3.1_release_merge 2025-11-22 00:42:20 +08:00
059d6edc12 BUGFIX: 查询affiliate时,不显示已删除的记录,删除affiliate时,状态也修改 2025-11-22 00:41:35 +08:00
97c5be7b22 CONFIG:修改第二数据源的库 2025-11-22 00:15:13 +08:00
c4da4ea111 CONFIG:to Prod 2025-11-21 17:09:53 +08:00
litianxiang
db1048d875 第二数据源修改库名 2025-11-21 16:49:07 +08:00
bbc8b025a9 CONFIG:to Prod 2025-11-20 16:57:48 +08:00
630f6b2737 Merge branch 'release/3.1' into dev/3.1_release_merge 2025-11-20 15:48:03 +08:00
d14fdfee79 Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2025-11-20 11:11:21 +08:00
c14db62c0a BUGFIX:1.添加系统sketch到个人library 2.video生成结束后总是发送失败站内信 2025-11-20 11:09:20 +08:00
litianxiang
9166bf1a1a Merge remote-tracking branch 'origin/dev-ltx' into dev/3.1_release_merge 2025-11-20 10:50:17 +08:00
litianxiang
84c024eab8 Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev-ltx 2025-11-20 10:48:57 +08:00
litianxiang
b86f3c9f7e 1.fix:高级工具转产品图不需要也没有ageGroup,会导致报错
2.上传sketch模板代码
2025-11-20 10:48:36 +08:00
e2009617db Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2025-11-19 17:00:29 +08:00
65b17fe109 TASK:调用第三方api,视频生成结束发送站内信 2025-11-19 16:59:54 +08:00
0917154283 Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2025-11-19 15:58:11 +08:00
0f525c6c00 BUGFIX: 1.系统消息已读需判断接收人员 2.本地模型视频生成失败时,发送站内信 2025-11-19 15:57:47 +08:00
4beae1094b Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2025-11-18 17:45:53 +08:00
cefdac133e BUGFIX: 获取系统通知未读数 2025-11-18 17:45:11 +08:00
a466f269c2 Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2025-11-18 16:04:37 +08:00
97f0c8f65f BUGFIX: 获取系统通知未读数 2025-11-18 16:02:26 +08:00
ad00ac08ca Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2025-11-18 14:10:24 +08:00
d236057f2a BUGFIX: 获取系统通知未读数 2025-11-18 14:09:58 +08:00
62e3e9c16f Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2025-11-18 13:32:16 +08:00
604c529b42 BUGFIX: 视频生成完成后,站内信通知 2025-11-18 13:31:18 +08:00
bc612481dc Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2025-11-18 10:28:44 +08:00
2f3fa695b2 BUGFIX: 解决部分循环注入问题 2025-11-18 10:27:29 +08:00
313fc19dac Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2025-11-17 16:56:50 +08:00
f36e0488ea TASK: video生成成功后添加站内信通知 2025-11-17 16:55:45 +08:00
f239c8c02b TASK: 订阅或试用用户账号到期邮件通知 2025-11-14 18:08:40 +08:00
litianxiang
1d4017bafd minio上传base64 log补充信息 2025-11-14 15:57:49 +08:00
litianxiang
8c98f91445 minio上传base64 log补充信息 2025-11-14 15:42:24 +08:00
18f5528d59 Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2025-11-14 14:52:29 +08:00
88ce191950 TASK:1.订阅成功和续签成功,通知商家的邮件中添加邮件和国家 2.在getModuleContent的回参中添加motion相关数据 3.修改Affiliate账号状态与修改佣金比例接口合并 2025-11-14 14:51:30 +08:00
litianxiang
f3d6d7b000 fix:进行design后library中可能会生成同样的图片
fix:ageGroup在designSingle时不会被存入数据库导致收藏页面不能显示完整
2025-11-14 13:32:57 +08:00
ef84f32ca0 TASK:添加系统sketch到个人library 性别细节修改 2025-11-13 14:24:07 +08:00
3886aeaa46 Merge branch 'dev/dev_xp' into dev/3.1_release_merge
# Conflicts:
#	src/main/java/com/ai/da/python/PythonService.java
#	src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java
2025-11-13 13:41:31 +08:00
8750ea355a TASK:1.修改affiliate状态 2.添加系统sketch到个人library 3.视频生成新增生成模型 4.获取所有pose,从过去gif改为获取video 2025-11-13 11:40:37 +08:00
litianxiang
b107fa82df 修改第二数据源位置 2025-11-13 11:24:14 +08:00
litianxiang
e56a6176a9 fix:为BoundingBox返回值排序解决每次获取可能会排序错误的bug 2025-11-13 10:51:00 +08:00
litianxiang
e35ed2c768 转产品图提示词更换 2025-11-12 17:25:46 +08:00
litianxiang
52094d58e7 Merge remote-tracking branch 'origin/dev-ltx' into dev/3.1_release_merge 2025-11-12 13:50:14 +08:00
litianxiang
e4e6cfbff7 sketch暂时修改为java端推荐,根据style进行推荐 2025-11-12 13:49:01 +08:00
litianxiang
15f2b78c94 配饰detail显示问题 2025-11-07 11:50:13 +08:00
litianxiang
1fd1f7dd47 配饰更换为其他 2025-11-06 17:20:05 +08:00
litianxiang
2a6d3c1b58 fix:初次从收藏和生成的线稿,再刷新前不会被用于design 2025-11-06 15:21:37 +08:00
59e33c22b7 Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2025-11-05 17:25:21 +08:00
e5eecbfe8d BUGFIX: 路径修改 2025-11-05 17:24:46 +08:00
9759cf4740 BUGFIX: volcengine依赖包使用指定版本 2025-11-05 17:04:31 +08:00
e8766b9af3 Merge branch 'dev/dev_xp' into dev/3.1_release_merge
# Conflicts:
#	src/main/java/com/ai/da/common/config/MyTaskScheduler.java
#	src/main/java/com/ai/da/common/task/PaymentTask.java
2025-11-05 16:51:41 +08:00
4fed5f7439 BUGFIX: design single - sketch modify 2025-11-05 16:40:31 +08:00
litianxiang
c3e0a61ff7 Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev-ltx 2025-11-04 16:41:08 +08:00
litianxiang
58212e92ec 增加配饰类别 2025-11-04 16:37:57 +08:00
5efaaf01b2 task:motion 本地模型接口调用地址修改 2025-11-03 13:10:37 +08:00
18c94ad1e0 BUGFIX:取消续订提前邮件通知 2025-10-30 16:44:45 +08:00
e825c9bd75 BUGFIX:用户订阅后,订阅者和商家无法收到通知邮件 2025-10-22 10:48:29 +08:00
1af705592a BUGFIX:1.design中dislike后排序混乱 2.续订成功通知会再次通知上一次的成功订阅 2025-10-17 17:59:43 +08:00
litianxiang
d426fb34a2 Merge remote-tracking branch 'origin/dev-ltx' into dev/3.1_release_merge 2025-10-16 11:52:20 +08:00
litianxiang
8c3e1fdda5 fix:作品快照序列化问题导致报错 2025-10-16 11:51:29 +08:00
litianxiang
a76b9ba365 Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev/3.1_release_merge 2025-10-16 11:00:36 +08:00
cd74022d04 BUGFIX:generateLike添加年龄段 2025-10-16 10:03:57 +08:00
litianxiang
d5b972ab16 Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev-ltx 2025-10-16 09:32:38 +08:00
a3e63c9877 BUGFIX:排序优化 2025-10-15 18:32:19 +08:00
0c227a1efa BUGFIX:排序优化 2025-10-15 18:03:48 +08:00
litianxiang
59602540a3 Merge remote-tracking branch 'origin/dev-ltx' into dev/3.1_release_merge 2025-10-15 16:03:56 +08:00
4578cb5778 BUGFIX:排序优化 2025-10-15 16:03:08 +08:00
litianxiang
9959a03ccc fix:兼容二创设置旧数据没有性别问题 2025-10-15 15:58:08 +08:00
litianxiang
ff43ffaba6 Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev/3.1_release_merge 2025-10-15 15:17:22 +08:00
litianxiang
1c32aaa46c 防止因为二创导致的数据存在taskId相同导致报错问题 2025-10-15 14:47:04 +08:00
db5f435a4d BUGFIX:1.标签允许不同用户创建相同的标签2.删除指定人员试用名单通知邮箱 2025-10-15 10:46:27 +08:00
litianxiang
c9f9ef0ce2 谷歌模型错误提示词修改 2025-10-15 10:35:59 +08:00
litianxiang
3b6a9882d2 回滚 2025-10-14 18:10:59 +08:00
litianxiang
854847a6f4 去掉打印谷歌base64log 2025-10-14 17:46:06 +08:00
litianxiang
309d95ab3c fix:sort时有类型转换异常 2025-10-14 17:31:30 +08:00
litianxiang
422d547cfd Merge remote-tracking branch 'origin/dev-ltx' into dev/3.1_release_merge
# Conflicts:
#	src/main/java/com/ai/da/service/impl/CollectionSortServiceImpl.java
2025-10-14 17:30:30 +08:00
litianxiang
e6a0706d61 新增谷歌模型违规提示词或图片报错
模型扣除积分修改
压缩转产品图的输入
fix:sort时有类型转换异常
2025-10-14 17:20:23 +08:00
19c08f4237 BUGFIX:1. 排序优化,添加唯一约束和重试
2.like前先查询是否有被like
2025-10-13 17:35:27 +08:00
6ac9680c64 Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev/3.1_release_merge 2025-10-13 13:51:08 +08:00
4ce6fb4190 BUGFIX:为design的排序(collection_sort)添加唯一约束 2025-10-13 13:50:51 +08:00
litianxiang
6b7abafb68 Merge remote-tracking branch 'origin/dev-ltx' into dev/3.1_release_merge 2025-10-13 13:45:31 +08:00
litianxiang
02f7031a67 修改配置增加模特功能修改
fix:模特有时会没有设置成功性别
豆包qwen模型增加违规提示词提醒
2025-10-13 13:42:38 +08:00
3d67ac71f3 BUGFIX:moodboard无法完全删除 2025-10-10 13:26:13 +08:00
litianxiang
67f0ce7c6c Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev/3.1_release_merge 2025-10-09 15:28:08 +08:00
litianxiang
5fbcaf9077 去掉本地vpn设置 2025-10-09 15:23:12 +08:00
ebb19ea15e BUGFIX:漏传 2025-10-09 15:18:05 +08:00
litianxiang
5efa5cad33 Merge remote-tracking branch 'origin/dev-ltx' into dev/3.1_release_merge 2025-10-09 15:06:34 +08:00
litianxiang
f9dfd61b89 fix:谷歌模型新加重试机制,修改nanobanana正式版ID 2025-10-09 15:05:09 +08:00
42aed5804b BUGFIX:1.生成的图案在design时未加入到library
2.获取组织名时出现空字符串
TASK:1. 允许超级管理员按组织名查询用户design频次
2025-10-08 21:04:19 +08:00
litianxiang
df5ee235f2 fix:fast模型匹配为normal 2025-10-08 16:09:39 +08:00
litianxiang
ad2bb7062e Merge remote-tracking branch 'origin/release/3.1' into dev-ltx 2025-10-08 13:09:39 +08:00
litianxiang
4fbacb37c1 google模型添加http重试 2025-10-08 13:08:14 +08:00
litianxiang
3150f5ae57 Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev/3.1_release_merge 2025-10-07 14:02:08 +08:00
litianxiang
20cf415635 Merge remote-tracking branch 'origin/dev-ltx' into dev/3.1_release_merge
# Conflicts:
#	src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java
2025-10-06 22:16:26 +08:00
litianxiang
7bd32914a1 删掉aida.iml 2025-10-06 22:01:57 +08:00
litianxiang
24d54ea9ea 转产品图模型换为nanobanana 2025-10-06 22:00:34 +08:00
c00c2e738b BUGFIX:1.查询组织接口完善 2.设置默认的二级印花分类 3.教育管理员登录时过期处理 2025-10-06 18:09:11 +08:00
litianxiang
6772610129 fix:根据不同类型判断性别进行男女服装筛选,否则会造成design异常 2025-10-03 12:04:48 +08:00
litianxiang
a681a298f4 恢复修改设置会多一个模特fix判断模特是否存在的方式 2025-10-02 12:09:07 +08:00
litianxiang
e6d5d4f614 去掉vpn设定 2025-10-02 09:49:52 +08:00
litianxiang
187c38ad61 Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev/3.1_release_merge 2025-10-02 09:37:29 +08:00
litianxiang
95f6f02290 豆包api key 2025-10-02 09:37:21 +08:00
ab7ef19657 pantone中的rgb替换 2025-10-02 06:26:39 +08:00
litianxiang
d837f0dc78 Merge remote-tracking branch 'origin/dev-ltx' into dev/3.1_release_merge
# Conflicts:
#	src/main/java/com/ai/da/service/WorkspaceService.java
#	src/main/java/com/ai/da/service/impl/DesignServiceImpl.java
#	src/main/java/com/ai/da/service/impl/WorkspaceServiceImpl.java
2025-10-02 00:41:04 +08:00
litianxiang
ab6cc04483 为模特和线稿设置性别
修改设置模特会增多问题
模型更换
设置可以切换男女兼容
TODO:扣除积分价格
转产品图模型未完成
2025-09-30 17:22:23 +08:00
9110e0dd34 dev环境暂时不上生产的变更 2025-09-26 21:46:49 +08:00
0f084c27ea BUGFIX:1. singleDesign颜色返回不对 2. 单品design通过优先级获取图层有误 2025-09-26 18:25:40 +08:00
b1b465a05a BUGFIX:1. 单品设计返回的优先级不对 2. 修改项目参数会导致多一个模特 2025-09-26 16:47:03 +08:00
2e4b1516cc BUGFIX:新增的图层未转为预览地址 2025-09-26 11:40:17 +08:00
1e389bec86 Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2025-09-25 16:52:50 +08:00
2d0936f0f3 BUGFIX:1. to product 不添加衣服类别提示词
2. 新增添加了单个印花的未分割图层返回
3. design中使用的元素,sketch没有被正确的添加年龄段,导致用户无法查询到
2025-09-25 16:51:58 +08:00
dab253c313 BUGFIX:检查所有异常提示的语言是否都做了多语言 2025-09-24 14:21:07 +08:00
ed86cd45ad BUGFIX:创建项目时,已输入的项目名被覆盖 2025-09-23 22:54:07 +08:00
814324430c dev切换到prod,部分功能不上传 2025-09-23 17:34:08 +08:00
1d006342fb BUGFIX:创建优惠券设置开始结束时间失败;开启stripe模块的接口文档 2025-09-23 16:24:00 +08:00
24fe265172 BUGFIX:1.微信注册后绑定邮箱失败;2.按类别查项目历史记录 2025-09-23 14:48:44 +08:00
79e19a029b BUGFIX:undividing layer未设置成功 2025-09-23 10:54:09 +08:00
227a20f6f2 Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2025-09-22 17:50:06 +08:00
efa26d912d TASK:添加默认项目名,存储design结果的undivided_layer 2025-09-22 17:49:13 +08:00
litianxiang
ea19e915db fix:二创旧数据兼容 2025-09-22 15:03:20 +08:00
41759ca44b Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2025-09-22 14:17:05 +08:00
29e1d864ae BUGFIX: saveModuleContent时无法删除最后一个元素
TASK: 打开教育账号检查过期定时器
2025-09-22 14:16:34 +08:00
6cfd420e46 sketch advance 提示词增加修饰 2025-09-20 22:01:21 +08:00
51024508b9 Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2025-09-19 17:31:55 +08:00
b7b07b8843 sketch 提示词未修饰 2025-09-19 17:31:31 +08:00
c1d26a87ce Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2025-09-19 14:09:29 +08:00
d59a69e6f4 切换dev环境的谷歌登录相关配置 2025-09-19 14:08:52 +08:00
litianxiang
042501f9b1 Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev/3.1_release_merge 2025-09-18 17:49:36 +08:00
litianxiang
9e6fcb4f73 fix:查询详细项目信息文件恢复 2025-09-18 17:48:40 +08:00
9386a2c6c4 隐藏检查管理员账号到期接口 2025-09-17 17:49:48 +08:00
c43a716104 BUGFIX: 所有通过邮件注册、登录等的查询,不再区分大小写 2025-09-17 17:46:42 +08:00
litianxiang
950707ab44 Merge remote-tracking branch 'origin/dev-ltx' into dev/3.1_release_merge 2025-09-17 16:45:56 +08:00
litianxiang
b0e5f39765 perf:减少/api/project/getModuleContent数据库交互次数以优化速度 2025-09-17 16:14:08 +08:00
5eebb878ca Merge remote-tracking branch 'origin/dev-ltx' into dev/3.1_release_merge 2025-09-17 15:34:36 +08:00
litianxiang
d568129843 fix:增加projectID匹配,避免因为二创导致查询到多条记录 2025-09-17 15:19:19 +08:00
d093aa9d1a Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2025-09-17 11:35:12 +08:00
3c1d180ed6 BUGFIX: 试用订单邮件发送,区分环境 2025-09-17 11:33:25 +08:00
b9c24386b9 BUGFIX: 未解析用户数据的接口使用了上一个使用这个线程的用户信息 2025-09-16 17:42:39 +08:00
litianxiang
8f53902d18 fix:点击我的喜欢会出现非喜欢的作品
fix:二创因为designID为-1导致报错的bug
2025-09-16 17:21:47 +08:00
c79535ac3f Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2025-09-16 17:02:20 +08:00
106528ce08 TASK: 教育管理员账号到期后降为游客并移除所有子账号 2025-09-16 17:01:18 +08:00
litianxiang
23eda80389 Merge remote-tracking branch 'origin/dev/3.1_release_merge' into dev/3.1_release_merge 2025-09-16 11:49:43 +08:00
litianxiang
eccd2a35e9 fix:9.11代码覆盖恢复 2025-09-16 11:36:43 +08:00
9c69aeae53 Merge branch 'dev/dev_xp' into dev/3.1_release_merge 2025-09-16 11:26:12 +08:00
5bac740efd TASK: Affiliate审批通过后,邮件中添加邀请链接 2025-09-16 11:20:09 +08:00
litianxiang
fa74236035 fix:二创报错 2025-09-16 11:07:54 +08:00
litianxiang
630dfe98a4 /api/project/getModuleContent速度优化 2025-09-16 11:01:22 +08:00
c922563919 TASK: Affiliate审批通过后,邮件中添加邀请链接 2025-09-12 16:25:34 +08:00
ce68696934 TASK: 1. 登录不区分邮箱大小写
2. 将所有删除用户的操作更改为修改身份为游客
2025-09-12 15:46:35 +08:00
5d8bdf9ecc TASK: 子账号积分刷新沿用上月分配的积分
BUGFIX: 获取作品详情
2025-09-11 16:01:25 +08:00
e3b0d3bc0a BUGFIX:1. 新建的教育管理员无法登录、无法分配积分
2. 填写个人信息时会覆盖其他人的信息
TASK:教育用户不能通过个人版登录入口登录
2025-09-10 22:05:45 +08:00
5f5f2c83d7 管理员允许查看各功能使用数据表 2025-09-09 18:49:08 +08:00
aff51a2793 管理员允许查看各功能使用数据表 2025-09-09 18:48:42 +08:00
4c5d8d3c61 修改管理员页面权限校验 2025-09-09 17:32:12 +08:00
f667099f4f 修改管理员页面权限校验 2025-09-09 17:31:51 +08:00
d5a74c1ff3 新建子账号 默认密码修改 2025-09-09 12:04:37 +08:00
c187d25d74 新建子账号时已使用积分为空 2025-09-08 16:20:24 +08:00
f20a85a0e2 Google 回调地址修改 2025-09-07 20:52:49 +08:00
4f93ec144b BUGFIX:添加已存在的子账号时,不指定密码则不会修改原账号密码 2025-09-04 21:18:21 +08:00
de16437d08 BUGFIX:1. 所有作品中无法查看个人刚发布的作品
2. 100月付用户的邮件中续订金额不对,发送给商家的邮件中夹杂中文
3. 推广码没有截止有效期时使用该推广码报错
2025-09-04 18:29:52 +08:00
c67d197da0 BUGFIX:无法通过谷歌登录/教育管理员无法查看design使用频次 2025-09-03 18:15:23 +08:00
d8f0188596 BUGFIX:无法通过谷歌登录 2025-09-03 15:50:13 +08:00
ddc089faa4 BUGFIX:印花pin的数量为9时无法design 2025-09-03 15:48:45 +08:00
f5ecd34a9c BUGFIX:无法查看我喜欢的作品 2025-09-03 00:23:32 +08:00
3c071378ad BUGFIX:无法查看我的作品 2025-09-02 23:46:40 +08:00
8b2aab2e5e Merge branch 'dev/3.1_release_merge' into release/3.1 2025-09-02 22:28:58 +08:00
c4a42b03f6 BUGFIX:发布作品中没有like的衣服导致查看作品详细报错 2025-09-02 22:28:33 +08:00
0dad9ff618 切换端口9994->9990 2025-09-02 21:12:34 +08:00
136bcdf82b 切换正式支付环境 2025-09-02 20:13:37 +08:00
a59acb0903 BUGFIX: 2025-09-02 20:09:37 +08:00
feca192f53 BUGFIX: 无法二创 2025-09-01 23:13:54 +08:00
179b79812a release 3.1 dev与prod代码合并冲突处理 2025-08-31 22:02:28 +08:00
94cf82340a Merge branch 'release/3.1' into dev/3.1_release_merge
# Conflicts:
#	src/main/java/com/ai/da/common/config/MyTaskScheduler.java
#	src/main/java/com/ai/da/common/enums/ProductEnum.java
#	src/main/java/com/ai/da/common/task/PaymentTask.java
#	src/main/java/com/ai/da/common/utils/LocalCacheUtils.java
#	src/main/java/com/ai/da/common/utils/RedisUtil.java
#	src/main/java/com/ai/da/controller/AffiliateController.java
#	src/main/java/com/ai/da/controller/ConvenientInquiryController.java
#	src/main/java/com/ai/da/controller/StripeController.java
#	src/main/java/com/ai/da/mapper/primary/entity/Library.java
#	src/main/java/com/ai/da/mapper/primary/entity/ProductCoupons.java
#	src/main/java/com/ai/da/model/dto/CreateCouponDTO.java
#	src/main/java/com/ai/da/model/vo/CheckCouponsVO.java
#	src/main/java/com/ai/da/service/AffiliateService.java
#	src/main/java/com/ai/da/service/PaymentInfoService.java
#	src/main/java/com/ai/da/service/StripeService.java
#	src/main/java/com/ai/da/service/impl/AccountServiceImpl.java
#	src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java
#	src/main/java/com/ai/da/service/impl/CollectionElementServiceImpl.java
#	src/main/java/com/ai/da/service/impl/ConvenientInquiryServiceImpl.java
#	src/main/java/com/ai/da/service/impl/DesignItemServiceImpl.java
#	src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java
#	src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java
#	src/main/java/com/ai/da/service/impl/StripeServiceImpl.java
#	src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java
#	src/main/resources/messages_en.properties
#	src/main/resources/messages_zh.properties
2025-08-31 17:54:44 +08:00
c649907222 数据迁移代码 2025-08-31 14:16:08 +08:00
c93ae85b65 BUGFIX: 1、singleDesign使用generate的印花没有传minio导致出现错误
2、项目中没有保存生成和上传的印花的类型
2025-08-29 14:18:17 +08:00
6441bfbbba BUGFIX: 子账号信息无法正确导出为excel 2025-08-28 19:22:55 +08:00
933522482b TASK:审批affiliate 2025-08-28 14:01:48 +08:00
56b56981b1 TASK:便利查询,查询所有用户id时根据用户身份限定查询范围 2025-08-28 11:29:30 +08:00
9e2ea2de62 TASK:导出数据时添加校验 2025-08-27 17:40:05 +08:00
7005b75e11 TASK:导出数据时添加校验 2025-08-27 15:24:43 +08:00
5b09d2cbf5 BUGFIX:查询design使用情况数据不对 2025-08-27 14:57:15 +08:00
126ac209c6 BUGFIX:普通生成积分扣除有误 2025-08-27 14:15:58 +08:00
98eb29eeb5 BUGFIX:普通生成积分扣除有误 2025-08-27 13:44:32 +08:00
ee551a0be2 BUGFIX:编辑子账号邮箱时积分回流策略有漏洞 2025-08-27 11:41:07 +08:00
c3cbb61c16 BUGFIX:积分扣除失败 2025-08-27 11:22:08 +08:00
71f0293cd9 BUGFIX:修改用户邮箱异常时事务没回滚 2025-08-27 10:39:46 +08:00
35604e5130 BUGFIX:超管创建机构管理员 2025-08-27 10:15:59 +08:00
18c38b020e TASK:默认积分分配改为平均分配;超级管理员可新增教育、企业管理员账户;组织成员使用积分时需要记录creditsUsage;试用用户初始50积分 2025-08-26 23:53:40 +08:00
6e9213ec5a BUGFIX:获取brand dna计算时间为空 2025-08-26 16:24:52 +08:00
83ba69c950 BUGFIX:子账号批量导入、brand dna返回计算时间、按权限范围查询design频次 2025-08-26 15:49:02 +08:00
3cc329f983 param change 2025-08-26 14:49:43 +08:00
c42ee8a1bf Merge branch 'dev/dev_xp' into dev/dev 2025-08-26 14:27:50 +08:00
9a650afc7d TASK:优化查询子账号design试用频次,根据管理员身份限定查询范围 2025-08-26 14:10:28 +08:00
45a336ced3 TASK:brand dna获取进度 返回计算时间 2025-08-26 13:33:28 +08:00
e258166a16 Merge branch 'dev/dev_xp' into dev/dev 2025-08-26 11:54:24 +08:00
f9ec733f07 BUGFIX: 编辑referral状态 2025-08-26 11:53:53 +08:00
54b09b4940 TASK:万相补偿获取结果之后通知用户 2025-08-26 09:35:18 +08:00
6d0c29f5c3 TASK:motion生成完成后邮件通知 2025-08-25 18:16:57 +08:00
23523f73da TASK:教育版子账号积分刷新策略更新 2025-08-25 18:07:37 +08:00
e45d572078 TASK:Stripe订阅,添加月付(经济版)及相应费用、积分的更新 2025-08-25 15:02:34 +08:00
eebb790aeb BUGFIX:教育子账号新增-积分分配问题 2025-08-25 09:18:07 +08:00
9c6573f1a6 BUGFIX:删除library元素时没有将brand中关联的数据删除,导致出现空指针 2025-08-22 15:27:09 +08:00
6a5282e4d5 BUGFIX:将已存在的账号添加到子账号中,积分计算混乱 2025-08-21 16:03:24 +08:00
3c5a5ff225 Merge branch 'dev/dev' into dev/dev_xp 2025-08-21 13:22:48 +08:00
e4ce7e9e63 TASK:获取affiliate的用户名和id;BUGFIX:模特无法保存 2025-08-21 13:22:22 +08:00
1089a5a2a5 TASK:flux 生成pattern时输出图片比例设置为1:1 2025-08-20 18:15:46 +08:00
156fcfae6b Merge branch 'dev/dev_xp' into dev/dev 2025-08-20 18:02:18 +08:00
7436fa17c0 TASK:添加接口说明 2025-08-20 18:01:28 +08:00
d9f19f1728 Merge branch 'dev/dev_xp' into dev/dev 2025-08-20 16:41:14 +08:00
81c417ed76 BUGFIX:1、子账号查询,无法批量根据用户名或邮箱查
2、教育版子账号创建及修改涉及的积分问题
2025-08-20 16:40:44 +08:00
59a3015170 TASK:查affiliate列表接口添加参数校验;打开佣金计算定时器 2025-08-20 09:37:35 +08:00
b02009bf14 Merge branch 'dev/dev_xp' into dev/dev 2025-08-19 17:45:11 +08:00
caa9985d11 TASK: 1.affiliate 新增referral新增、查询、修改以及其他相关的自动结算佣金的功能;2.删除affiliate_income表及相关mapper 2025-08-19 17:44:34 +08:00
80957bfc00 Merge branch 'dev/dev_xp' into dev/dev 2025-08-19 09:33:16 +08:00
552ec828ab BUGFIX:1、删除模特后保存失败
2、获取个人库中的模特不准确
2025-08-18 16:18:51 +08:00
42273750f4 BUGFIX:从缓存获取模特 2025-08-15 18:00:41 +08:00
45d6af92e8 BUGFIX:1、教育通过上传文件批量创建子账号没有任何校验
2、下载子账号所有信息接口缺失(原下载模板接口保留)
3、保存个人模特到collection时类型设置为System
4、创建子账号时设置积分无效
2025-08-15 17:44:45 +08:00
c28db81893 BUGFIX:同一浏览器切换版本登录时,密码被置空 2025-08-13 16:45:30 +08:00
1e25ae36f1 TASK:1、教育版添加新用户、修改用户、移除用户需求更改;2、修改登入校验条件
BUGFIX:当用户积分为空时报错
2025-08-13 15:52:19 +08:00
9bf40d879f BUGFIX: 用户选择作品进行二创后,无法正确展示原作品中被like的design 2025-08-05 16:50:54 +08:00
878f556a0b BUGFIX:分页查询所有项目历史记录,根据更新时间排序,解决项目记录没有更新时间导致空指针问题 2025-08-04 13:29:12 +08:00
4ad2cd027c TASK:1. 通过定时任务,补偿获取第三方api的运行结果;
2. pose 生成,对使用万相模型的生成限流,最大支持5个并发
3. Slogan限流,一分钟内,最多接收3个请求
2025-08-01 17:21:41 +08:00
132f48eb60 CONFIG:dev添加死信队列信息 2025-08-01 11:29:47 +08:00
5b33e31504 BUGFIX:画布存在minioUrl为空的情况,此时不处理minio地址 2025-08-01 11:12:11 +08:00
e16268a013 TASK: 邮件模板 2025-07-31 18:20:43 +08:00
739e637267 TASK: 发送邮件功能及发送失败后的重试机制 2025-07-31 15:57:47 +08:00
7edc959432 TASK: 保存画布时返回画布id
BUGFIX: 用户输入的prompt没有传入flux
2025-07-31 14:57:20 +08:00
c444d5a69f TASK: to product、relight、pose未like的数据也需要返回parentId 2025-07-30 15:12:38 +08:00
830d06a900 BUGFIX: 更新flux生成结果失败 2025-07-29 15:59:57 +08:00
0fcd8e5444 BUGFIX: 1、修改画布时,不再上传新文件,改为覆盖原文件
2、删除toProduct relight结果时没删干净导致获取源文件失败
2025-07-29 15:00:13 +08:00
020cfe9016 TASK:design single中添加单件衣服画布保存 2025-07-29 13:12:20 +08:00
39903f3da6 BUGFIX:循环依赖导致项目无法启动 2025-07-28 17:27:00 +08:00
b1d682a909 TASK:1、to product修改任务状态字段为task 2、异步向api_generate表中添加记录 3、优化flux结果获取,避免重复获取结果时因图片过期覆盖原可用图片 2025-07-28 15:01:16 +08:00
07d60303db BUGFIX: to product 用户未输入prompt时,出现空指针 2025-07-28 12:10:39 +08:00
5287d83b82 BUGFIX:1、userLikeService中业务划分不清晰导致与generateService出现循环依赖问题。解决:将CollectionSort单独划分为一个Service
2、新建t_api_generate表用于补偿查询生成结果
2025-07-25 17:13:06 +08:00
e2085190d1 BUGFIX:单品设计存储时,不要涉及body相关数据 2025-07-25 13:17:23 +08:00
565b5c3de1 BUGFIX:单品设计偏移量为空问题 2025-07-24 17:18:40 +08:00
fd29452e0c BUGFIX:flux请求失败后的日志打印问题 2025-07-24 11:33:28 +08:00
0f93099d04 BUGFIX:修改获取flux结果的get方法名 2025-07-24 09:40:34 +08:00
e2d50a6dfa TASK: 优化generate请求方法,将长方法拆分为由多个小方法组成 2025-07-23 17:25:00 +08:00
c4d20cd522 TASK: 1、印花生成允许使用flux
2、修改sketch\print允许修改上传的元素
3、印花生成结果中添加level2Type
2025-07-23 16:59:41 +08:00
229e1353f4 BUGFIX: 获取万相的生成结果时没有返回status 2025-07-22 17:36:16 +08:00
07571aaad1 TASK: 画布数据 回参处理不为空时的minio地址 2025-07-22 13:42:07 +08:00
bb0a3bd1cd BUGFIX: 1、允许存储没有潘通值的颜色
2、getModule时design子元素回参增加
2025-07-22 11:09:47 +08:00
3bd9ff82d7 BUGFIX: 获取我的作品时,无法查看设置为私有的作品 2025-07-21 17:54:12 +08:00
f0fccaaf51 TASK:pose transfer添加返回参数 2025-07-21 17:11:10 +08:00
2041809ea6 TASK:pose transfer添加返回参数 2025-07-20 19:19:07 +08:00
e2e0bd6b47 TASK:toProduct relight pose 返回的数据中需包含设置的参数信息 2025-07-18 16:37:37 +08:00
785ae33e86 BUGFIX: 旧作品中有的没有项目id 2025-07-17 17:34:03 +08:00
20f7dc0ef9 TASK:作品更新接口,将通过projectId替换userLikeGroupId 2025-07-17 17:21:14 +08:00
0155154664 BUGFIX: cloudTask数据插入的时间晚于python端向MQ中发消息的时间 2025-07-17 11:48:38 +08:00
d264c29557 TASK: 删除toProduct Relight Pose后重新排序 2025-07-17 10:51:43 +08:00
432149dce2 TASK: 拼贴 未进行生成时也显示上传的图片 2025-07-16 19:29:52 +08:00
5b3a52152a TASK: ToProduct Relight Pose新增删除接口 2025-07-16 19:14:41 +08:00
301f58bc62 TASK: 拼贴功能保存用户上传的图片并返回 2025-07-15 18:11:12 +08:00
64318de24a BUGFIX: 创建pose transfer任务error 2025-07-15 13:12:29 +08:00
fb01250142 BUGFIX: 通过projectId获取pose transfer结果路径出错 2025-07-15 13:02:59 +08:00
0beec5392e Merge branch 'dev/dev_xp' into dev/dev
# Conflicts:
#	src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java
2025-07-15 12:10:55 +08:00
f551ba452f BUGFIX: 通过projectId获取pose transfer结果路径出错 2025-07-15 11:58:13 +08:00
f4b22fe874 BUGFIX: 1、还未生成出结果但是没有失败的pose transfer需返回taskID 2025-07-14 19:17:21 +08:00
e95444266b BUGFIX: 1、getModuleContent没有返回taskId
2、万相生成的pose没有更新状态
2025-07-14 18:05:10 +08:00
e361960e51 TASK: 1、对于生成失败情况,在数据库添加状态记录,并在getModuleContent时不返回该条记录 2025-07-11 17:56:15 +08:00
d0a9c05d4b BUGFIX: 1、相同的relation_id,relation_type重复排序,针对脏数据做处理 2、传入数据库中没有的userLikeSortId 2025-07-11 14:22:38 +08:00
f852927116 BUGFIX: 1、积分重复扣除 2、pose transfer没有开始时间,没有项目id 2025-07-11 11:07:27 +08:00
daa88889d0 TASK:1、印花允许修改并保存
BUGFIX: 1、批量生成有的类型没有任务开始执行时间,任务结束时间有误
2025-07-10 17:50:31 +08:00
766e75f2ed BUGFIX: 批量生成积分扣除有误 2025-07-10 13:38:00 +08:00
eb7f2a1419 BUGFIX: 批量生成积分扣除有误 2025-07-10 11:24:25 +08:00
c7c69417ef TASK: 1、更换pose,重新生成templateId
2、brandDNA 开启分析attributes功能
2025-07-09 17:01:53 +08:00
9f548d299b TASK: 默认不like时,不要将元素添加到父元素子集但是要返回parentId 2025-07-09 12:10:10 +08:00
1dc6c6f8c4 TASK:生成获取结果接口返回parentId 2025-07-08 18:53:21 +08:00
5472e59a84 TASK: sketchboard library数据添加年龄组 2025-07-08 16:09:01 +08:00
d379f778dc TASK: 默认不like的元素,如有parentId,需要添加到CollectionSort表中 2025-07-08 14:29:54 +08:00
ec44c2a6b5 TASK: 1、默认不like的元素,如有parentId,需要回传
2、project查询 需要按id查
2025-07-08 13:54:27 +08:00
1f77500d61 TASK:product/relight/pose transfer的入参添加是否需要默认like 2025-07-08 11:39:05 +08:00
060db899cf TASK:product/pose transfer的回参添加sort和id 2025-07-08 10:21:28 +08:00
9fc8f52aca BUGFIX: 1、对话历史记录 有的回答没有深度思考标识 2、批量生成,积分扣除不足 2025-07-07 18:32:14 +08:00
9af1bc867a TASK:to product\relight的结果分like 没like返回 2025-07-07 16:34:22 +08:00
e92bb0c7cd TASK:获取模板内容 不再限制是否like 2025-07-07 14:49:36 +08:00
1d07d7d88a TASK:generate 普通生成改回按生成次数收费 2025-07-07 14:26:21 +08:00
ec7d84b354 BUGFIX:未生成完成的项目获取moduleContent报错 2025-07-07 14:14:45 +08:00
0a2c5e028f BUGFIX:对项目进行各种生成修改时没有更新项目更新时间 2025-07-07 11:53:50 +08:00
4379b9cff1 BUGFIX:design中的排序问题 倒序问题 再次修改 2025-07-04 19:08:59 +08:00
1b7c2041be BUGFIX:design中的排序问题 2025-07-04 17:20:35 +08:00
f3632f53e3 BUGFIX:生成没出结果之前获取结果报空指针 2025-07-04 12:43:14 +08:00
d76a9e6afd 1、design流程中使用to product、relight、pose transfer默认加到like
2、万象的pose transfer结果存到redis
2025-07-04 12:02:05 +08:00
e67acc4319 1、添加日志打印
2、batch获取结果报错
2025-07-03 19:03:45 +08:00
373a360e76 BUGFIX:FLUX童装prompt修改;获取video结果允许传入list 2025-07-03 14:20:33 +08:00
f541bee0e7 Merge branch 'dev/dev_xp' into dev/dev 2025-07-03 11:24:59 +08:00
75d086f680 pose transfer 万象入参添加日志打印 2025-07-03 11:21:10 +08:00
81ca723486 BUGFIX:Batch_Relight默认创建的项目类型是ToProduct 2025-07-03 09:48:21 +08:00
d51bbffb3e TASK:BrandDNA 2025-07-03 09:40:56 +08:00
07aad4afa0 Merge branch 'dev/dev_xp' into dev/dev 2025-07-02 19:04:52 +08:00
6495bb2be3 TASK:语言适配 2025-07-02 19:02:39 +08:00
3d8363c99b BUGFIX:批量生成创建姿势变更项目失败 2025-07-02 17:44:32 +08:00
333c11f81e 增加日志打印 2025-07-02 17:03:40 +08:00
77fc3e967a TASK: 批量生成 prompt微调获取接口,端口变更 2025-07-02 16:29:00 +08:00
a447cde05b TASK: 批量生成获取任务序号 2025-07-02 16:16:15 +08:00
e8ad241653 TASK: 生成项目参数 参数变更 2025-07-02 15:06:52 +08:00
1f824f3ae6 BUGFIX: 获取模块内容-pose transfer返回的图片无法显示 2025-07-02 13:35:15 +08:00
8c87333fa2 Merge branch 'dev/dev_xp' into dev/dev 2025-06-30 19:34:34 +08:00
4273d0efc0 BUGFIX: 系列设计 修改模特后,原模特丢失问题 2025-06-30 19:32:16 +08:00
a37b64be91 BUGFIX: 使用万象生成失败时直接报错 2025-06-30 15:54:58 +08:00
905d296bdf TASK: 批量生成 存储任务序号 2025-06-30 15:17:07 +08:00
9a25e8ce4a TASK: 批量生成 获取任务序号 2025-06-30 15:11:31 +08:00
68311e1d8b TASK: 通过对话创建项目 请求地址变更 2025-06-30 13:13:58 +08:00
de5da5b299 TASK: 对话 扣除积分 2025-06-30 12:03:23 +08:00
dcd63668bd TASK: 添加注释 2025-06-27 13:09:36 +08:00
shahaibo
1a52399ec9 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-27 09:59:39 +08:00
shahaibo
b01f5f59d1 TASK: 数据迁移拆分; 2025-06-27 09:59:08 +08:00
c70231d5de Merge branch 'dev/dev_xp' into dev/dev 2025-06-26 14:15:35 +08:00
d3deec72eb TASK: 切换chat agent请求api地址 2025-06-26 14:11:42 +08:00
shahaibo
a7347c9dc0 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-26 11:53:53 +08:00
shahaibo
6ad5d373d5 bugfix: single design没结果,posetransfer没回显正在进行的结果; 2025-06-26 11:21:35 +08:00
e048b75ed7 BUGFIX: 去除base64控制台输出 2025-06-25 19:13:57 +08:00
469681b96c BUGFIX: 向flux发起生成请求时,功能指定错误 2025-06-25 19:04:29 +08:00
89457b0593 TASK: 使用Flux生成前,to Product Image,为输入透明图添加白色背景 2025-06-25 18:43:52 +08:00
7a6b257714 BUGFIX:批量生成,获取design的结果中缺失ResultType 2025-06-25 17:20:35 +08:00
443b557623 BUGFIX:1、design 渐变色没存 2、展示文本更新 3、取消拼贴图入参日志打印 2025-06-25 17:10:56 +08:00
shahaibo
84691f45b5 bugfix: parentId结果返回; 2025-06-25 15:52:11 +08:00
de65f78e89 BUGFIX:Batch generation 创建时允许projectId为空 2025-06-25 14:10:24 +08:00
252cd0a69c BUGFIX:design 没有存储渐变色 2025-06-25 11:30:36 +08:00
d77aabca92 TASK:修改relight默认prompt 2025-06-24 19:35:07 +08:00
eaf90ab9e8 BUGFIX:注册用户登录没有邮件发送记录和登录记录 2025-06-24 17:53:52 +08:00
f828983969 BUGFIX:对话 控制台输出改为日志输出 2025-06-24 16:41:41 +08:00
be6eb64b35 Merge branch 'dev/dev_xp' into dev/dev 2025-06-24 16:30:28 +08:00
abc6c088fe BUGFIX:批量生成 relight和design创建的任务查不到 2025-06-24 16:27:15 +08:00
6f44489c6e BUGFIX:消息监听,消息解析失败,重复消费异常消息导致日志文件内容骤增 2025-06-24 16:11:53 +08:00
a809905c52 BUGFIX:batch generation like报错 2025-06-24 15:03:17 +08:00
7abab7121a BUGFIX:batch generate积分扣除报错 2025-06-24 14:22:41 +08:00
8e31968fd3 BUGFIX:1、积分消耗值不准确 2、flux获取结果报错 2025-06-23 18:16:23 +08:00
3d08e86049 BUGFIX:图片分割参数值变更 2025-06-23 13:44:56 +08:00
e0fdf1cc88 Merge branch 'dev/dev_xp' into dev/dev 2025-06-23 13:09:13 +08:00
4acdd8adb9 BUGFIX:1、积分扣除,金额不对 2、图片分割允许指定上传图片id 2025-06-23 12:02:16 +08:00
shahaibo
e8e6f8bc17 bugfix: posetransfer结果; 2025-06-20 17:28:34 +08:00
shahaibo
27983fe8ee bugfix: collectionSortParentId非必穿; 2025-06-20 17:01:47 +08:00
shahaibo
c3d92aacd5 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-20 16:29:06 +08:00
shahaibo
b287ec8529 bugfix: 对话中断排查日志添加; 2025-06-20 16:27:27 +08:00
07d3f6e224 Merge branch 'dev/dev_xp' into dev/dev 2025-06-20 16:23:38 +08:00
fc42f361fa BUGFIX:含小数的积分扣除失败 2025-06-20 16:14:56 +08:00
shahaibo
424f9a126d TASK: 结果返回parentId; 2025-06-20 15:20:35 +08:00
a042f05401 Merge branch 'dev/dev_xp' into dev/dev
# Conflicts:
#	src/main/java/com/ai/da/model/vo/MagicToolResultVO.java
2025-06-20 14:57:39 +08:00
f59adbe9bd TASK:更新各生成功能需要消耗的积分 2025-06-20 14:53:10 +08:00
a0ece486d8 TASK:更新各生成功能需要消耗的积分 2025-06-20 14:49:15 +08:00
shahaibo
4caa0a9b0d Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-20 13:51:21 +08:00
shahaibo
df5bbc3675 TASK: 结果返回parentId; 2025-06-20 13:50:29 +08:00
92278cf91b BUGFIX:获取all pose的预览地址报错 2025-06-20 12:01:17 +08:00
6b165fe5bc Merge branch 'dev/dev_xp' into dev/dev 2025-06-19 18:26:16 +08:00
64b32dc3a3 BUGFIX:sketch搜索出的图片去白边失败 2025-06-19 18:24:07 +08:00
1f84b4b3e6 BUGFIX: 2025-06-19 17:22:43 +08:00
a0979caba6 Merge branch 'dev/dev_xp' into dev/dev 2025-06-19 17:20:04 +08:00
18be52e806 BUGFIX: 1、llm使用sketch查询工具数据没有保存到历史记录中
2、flux运行失败状态下,获取结果报错
3、618福利邮件通知
2025-06-19 17:16:48 +08:00
shahaibo
627dad7aac Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-19 15:57:40 +08:00
shahaibo
7166db59bd Bugfix: 对话历史记录; 2025-06-19 15:44:26 +08:00
13759d806b Merge branch 'dev/dev_xp' into dev/dev 2025-06-19 14:58:56 +08:00
0fd1ddcde1 TASK: 1、LLM对话新增两个工具,查找sketch和修改项目参数 2、新增接口获取最新的minio图片预览地址 2025-06-19 14:56:18 +08:00
shahaibo
a5e743ce84 TASK: 数据迁移; 2025-06-19 14:29:44 +08:00
161bba896c BUGFIX: 获取当前任务结果报错(获取模型名出现空指针) 2025-06-19 14:08:25 +08:00
shahaibo
da8338be3f Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-19 11:52:03 +08:00
shahaibo
ea235b0d5c bugfix: delete collection; 2025-06-19 11:50:39 +08:00
98ea6004b4 TASK: 新增pose transfer模特姿势选项 2025-06-18 14:19:45 +08:00
62cbc612a7 Merge branch 'dev/dev_xp' into dev/dev 2025-06-17 16:56:45 +08:00
589fa8501e TASK: 优化童装prompt 2025-06-17 16:54:23 +08:00
shahaibo
d6285781f2 bugfix: delete collection; 2025-06-17 16:29:06 +08:00
shahaibo
137ef7045b TASK: cloud、posetransfer; 2025-06-17 16:25:57 +08:00
shahaibo
5e066995e8 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-17 14:53:52 +08:00
shahaibo
c1c50cb28b TASK: cloud、posetransfer; 2025-06-17 14:51:19 +08:00
3f13f64ab9 Merge branch 'dev/dev_xp' into dev/dev 2025-06-17 14:43:10 +08:00
5abe45ff34 TASK: 当选择童装时,sketch生成和to product的prompt需添加儿童限定词 2025-06-17 14:41:27 +08:00
shahaibo
0970127f68 TASK: collection sort; 2025-06-17 10:10:00 +08:00
shahaibo
93bb8d2f31 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-17 09:42:15 +08:00
shahaibo
88d8b75298 TASK: collection sort; 2025-06-17 09:41:19 +08:00
ea395e87ba Merge branch 'dev/dev_xp' into dev/dev 2025-06-16 18:52:41 +08:00
8d7b4adf48 BUGFIX: 1、sketch extract 没返回taskId
2、relight输入文本太长导致数据存储报错
2025-06-16 18:51:09 +08:00
e3ee724e6f BUGFIX:pose transfer 视频转GIF依赖操作系统环境切换 2025-06-16 18:25:32 +08:00
shahaibo
9d022ae13e Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-16 16:55:37 +08:00
shahaibo
8b0f9cfd11 TASK: cloud、posetransfer、sort; 2025-06-16 16:53:50 +08:00
f36b3818c5 Merge branch 'dev/dev_xp' into dev/dev 2025-06-16 16:17:56 +08:00
2ccbbf8893 BUGFIX:pose transfer 视频转GIF依赖缺失 2025-06-16 16:16:08 +08:00
76219aa4fe BUGFIX:pose transfer 记录重复存储问题 2025-06-16 15:32:32 +08:00
5ed3d8dfab Merge branch 'dev/dev_xp' into dev/dev 2025-06-16 15:08:50 +08:00
4dd3ddb1d0 BUGFIX:无法获取wx pose transfer的结果 2025-06-16 15:07:22 +08:00
fb16840a98 Merge branch 'dev/dev_xp' into dev/dev 2025-06-16 14:06:34 +08:00
9ad6acf28c BUGFIX:1、修改新增生成接口失败的状态 2、添加aliyun请求接口的密钥 2025-06-16 13:49:30 +08:00
shahaibo
774a20257d Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-16 13:45:25 +08:00
shahaibo
3db0a94981 TASK: cloud、posetransfer; 2025-06-16 13:44:22 +08:00
891b26d493 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-16 11:04:34 +08:00
86a991db81 BUGFIX:获取当前生成来自哪个模型 2025-06-16 11:03:40 +08:00
shahaibo
fd8e6fd2e8 BUGFIX: 切换性别 年龄段; 2025-06-13 17:03:07 +08:00
78239d3ead Merge branch 'dev/dev_xp' into dev/dev 2025-06-13 16:41:15 +08:00
174d1bf0d0 TASK:1、将imageToSketch接口调用转为异步 2、imageToSketch加入flux 2025-06-13 16:37:45 +08:00
da9f54982c Merge branch 'dev/dev_xp' into dev/dev 2025-06-13 15:58:37 +08:00
b6993b04c2 TASK:视频图像处理依赖包精简 2025-06-13 15:55:17 +08:00
shahaibo
4cca30ec75 BUGFIX: cloud; 2025-06-13 15:09:32 +08:00
shahaibo
b6c43e534b BUGFIX: 上传元素删除; 2025-06-13 14:07:38 +08:00
shahaibo
942b5eb19b BUGFIX: cloud; 2025-06-13 11:48:08 +08:00
shahaibo
31b2bd97b4 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-13 10:56:44 +08:00
shahaibo
3eaa0d017c BUGFIX: cloud; 2025-06-13 10:55:55 +08:00
be42550d0a Merge branch 'dev/dev_xp' into dev/dev
# Conflicts:
#	src/main/java/com/ai/da/model/dto/ToProductImageDTO.java
2025-06-12 16:54:15 +08:00
6e32289b98 TASK:Flux接入,应用于to product image和relight 2025-06-12 16:50:27 +08:00
shahaibo
a750a91f7b BUGFIX: 创建项目; 2025-06-12 15:59:15 +08:00
shahaibo
2cf3b75e46 BUGFIX: 创建项目; 2025-06-12 15:47:46 +08:00
shahaibo
9586be40ce TASK:3d print; 2025-06-12 13:50:04 +08:00
shahaibo
4494ec7dbc TASK:cloud; 2025-06-12 13:41:13 +08:00
shahaibo
33af9d0b9d TASK:cloud; 2025-06-12 13:31:34 +08:00
shahaibo
7f30b2d05b Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-12 13:13:31 +08:00
shahaibo
3cd86042ff TASK:上传回显; 2025-06-12 13:12:44 +08:00
af1fab644a pose transform 打开输入图片的检测 2025-06-11 17:45:17 +08:00
ace53e81f2 pose transform 开放自定义输入图片 2025-06-11 17:35:00 +08:00
shahaibo
f179368668 BUGFIX:library ageGroup切换; 2025-06-11 15:58:06 +08:00
shahaibo
9134933a07 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-11 11:39:01 +08:00
shahaibo
290f6a9a35 BUGFIX:library ageGroup切换; 2025-06-11 11:37:29 +08:00
ac2d1e611b BUGFIX: prompt提取接口传参格式修改 2025-06-10 18:13:53 +08:00
1b75e2ab55 TASK: prompt提取接口地址切换 2025-06-10 18:08:16 +08:00
de9750b24a Merge branch 'dev/dev_xp' into dev/dev 2025-06-10 17:53:03 +08:00
595effa04c TASK: 接入第三方api freepik 新增sketch extract variation 2025-06-10 17:50:04 +08:00
shahaibo
09e24ab062 TASK:cloud; 2025-06-10 15:05:41 +08:00
shahaibo
391208f8bd TASK:cloud; 2025-06-10 15:02:44 +08:00
shahaibo
3cf47eb723 TASK:cloud; 2025-06-10 11:13:17 +08:00
shahaibo
c3ce25315c TASK:cloud; 2025-06-10 11:03:15 +08:00
shahaibo
ae71564b94 TASK:cloud; 2025-06-10 10:55:56 +08:00
shahaibo
d6bd24865e TASK:cloud; 2025-06-09 13:41:02 +08:00
shahaibo
c420300c11 TASK:cloud; 2025-06-09 11:30:23 +08:00
shahaibo
4c67fce8d1 TASK:cloud; 2025-06-09 10:15:40 +08:00
shahaibo
b8d3b0192d TASK:cloud; 2025-06-06 17:18:59 +08:00
shahaibo
1afd86d3ce Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-06 15:25:26 +08:00
shahaibo
daa133b993 TASK:cloud; 2025-06-06 15:22:07 +08:00
shahaibo
bf258ee4f9 TASK:cloud; 2025-06-06 15:19:00 +08:00
2bc17ec4d0 Merge branch 'dev/dev_xp' into dev/dev 2025-06-06 13:54:00 +08:00
090b9ab6ab TASK: 取消animate假数据,直接调用第三方接口 2025-06-06 13:53:43 +08:00
shahaibo
fb5b52bec2 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-06 11:58:01 +08:00
shahaibo
df678a12b9 TASK:cloud; 2025-06-06 11:57:10 +08:00
21f85a7322 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-06 11:51:34 +08:00
4e2590fd0f Merge branch 'dev/dev_xp' into dev/dev 2025-06-06 11:51:06 +08:00
31c5fef5c0 BUGFIX: 获取万象生成结果时,需指定api_key 2025-06-06 11:50:41 +08:00
shahaibo
94e26ac912 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-06-06 11:10:58 +08:00
shahaibo
711859ce89 TASK:cloud; 2025-06-06 11:08:53 +08:00
8502fffb68 Merge branch 'dev/dev_xp' into dev/dev 2025-06-06 11:03:45 +08:00
6f0cc3aaf8 TASK: 更换第三方access key获取方式,从系统变量中获取改为从配置文件中获取 2025-06-06 10:59:13 +08:00
shahaibo
ce13874431 TASK:cloud; 2025-06-06 10:51:25 +08:00
shahaibo
054c9fd604 TASK:cloud; 2025-06-06 10:46:57 +08:00
f5501db19e TASK: 接入第三方api 添加access key 2025-06-06 09:56:02 +08:00
4609af875e Merge branch 'dev/dev_xp' into dev/dev 2025-06-05 18:36:22 +08:00
1dad0a008a TASK: 接入第三方api 通过万象实现text2image和animate,完成数据传输与原接口的兼容 2025-06-05 18:03:19 +08:00
shahaibo
b757cdc5dd TASK:batch toProductImage;chatStream; 2025-06-05 17:09:03 +08:00
shahaibo
249351bf52 TASK:batch toProductImage;chatStream; 2025-06-05 17:06:11 +08:00
shahaibo
38ca810068 TASK:batch toProductImage;chatStream; 2025-06-05 15:44:23 +08:00
shahaibo
bab5c9a8e6 TASK:batch toProductImage;chatStream; 2025-06-05 15:33:08 +08:00
shahaibo
4e80493a26 TASK:batch toProductImage;chatStream; 2025-06-05 14:00:38 +08:00
shahaibo
12dbe90150 TASK:batch toProductImage;chatStream; 2025-06-05 13:35:13 +08:00
shahaibo
f2c268683c TASK:collection sort; 2025-06-03 15:05:40 +08:00
shahaibo
f69eaa4fe3 TASK:collection sort; 2025-06-03 14:39:56 +08:00
shahaibo
a9172dcd36 TASK:collection sort; 2025-06-03 14:31:51 +08:00
shahaibo
442e87267a TASK:collection sort; 2025-06-03 13:41:45 +08:00
shahaibo
32c8aaec9b TASK:collection sort; 2025-06-03 11:26:21 +08:00
shahaibo
112294bd7b TASK:collection sort; 2025-06-03 11:23:13 +08:00
shahaibo
3bfbd8abc1 TASK:collection sort; 2025-06-03 10:42:11 +08:00
shahaibo
78341850e1 TASK:collection sort; 2025-06-02 16:31:17 +08:00
shahaibo
becdbf1891 TASK:collection sort; 2025-06-02 16:19:41 +08:00
shahaibo
f0b1d3f9ce TASK:collection sort; 2025-05-30 15:02:39 +08:00
shahaibo
73bab2338e TASK:collection sort; 2025-05-30 14:04:18 +08:00
shahaibo
448e6d2c40 TASK:mannequin; 2025-05-30 13:08:19 +08:00
shahaibo
131d782b54 TASK:test; 2025-05-30 11:49:10 +08:00
shahaibo
d6cc8ab9a2 TASK:test; 2025-05-30 11:42:27 +08:00
shahaibo
d9e25fd0e4 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-05-29 16:17:49 +08:00
shahaibo
276994759e TASK:mannequin; 2025-05-29 16:17:39 +08:00
a569ee7736 Merge remote-tracking branch 'origin/dev/dev' into dev/dev
# Conflicts:
#	src/main/java/com/ai/da/mapper/primary/entity/DesignItem.java
2025-05-28 16:57:49 +08:00
d7762cbfed Merge branch 'dev/dev_xp' into dev/dev 2025-05-28 16:57:15 +08:00
8356326c7d TASK: DesignDetail中允许修改模特 2025-05-28 16:56:32 +08:00
shahaibo
8003a799c2 TASK:mannequin; 2025-05-28 16:42:54 +08:00
shahaibo
6de1ad150c TASK:mannequin; 2025-05-28 15:28:55 +08:00
shahaibo
b6a7354322 TASK:mannequin; 2025-05-28 13:59:52 +08:00
shahaibo
6e96f38c90 TASK:mannequin; 2025-05-28 13:59:00 +08:00
shahaibo
fc24e1fab8 TASK:mannequin; 2025-05-28 13:47:45 +08:00
shahaibo
718e1c93f6 TASK:mannequin; 2025-05-28 11:12:26 +08:00
shahaibo
74540610c6 TASK:mannequin; 2025-05-28 10:34:54 +08:00
shahaibo
1be4701f6d TASK:mannequin; 2025-05-28 09:37:27 +08:00
shahaibo
d3b4d15df8 TASK:mannequin; 2025-05-23 16:33:43 +08:00
shahaibo
8fc79f6699 TASK:mannequin; 2025-05-23 15:13:46 +08:00
shahaibo
91ee58db1b TASK:LLM; 2025-05-22 13:43:50 +08:00
shahaibo
af1c839495 TASK:LLM; 2025-05-22 13:24:28 +08:00
shahaibo
083416951a TASK:LLM; 2025-05-22 12:34:01 +08:00
shahaibo
cd20bdd88f TASK:LLM; 2025-05-22 12:27:00 +08:00
shahaibo
5a0fb6fd3f TASK:LLM; 2025-05-22 10:11:21 +08:00
shahaibo
93fe0781b2 TASK:LLM; 2025-05-21 21:04:28 +08:00
shahaibo
94e00459b6 TASK:LLM; 2025-05-21 21:03:15 +08:00
shahaibo
9614985690 TASK:LLM; 2025-05-20 16:59:07 +08:00
shahaibo
8c597db8a9 TASK:LLM; 2025-05-20 16:54:20 +08:00
shahaibo
a0bd4cfa38 TASK:LLM; 2025-05-20 16:47:43 +08:00
shahaibo
82388b0c19 TASK:LLM; 2025-05-20 16:12:08 +08:00
shahaibo
588202311c TASK:LLM; 2025-05-20 16:02:38 +08:00
shahaibo
46820505ae TASK:LLM; 2025-05-20 14:37:34 +08:00
shahaibo
b030e9c09b TASK:LLM; 2025-05-20 14:31:05 +08:00
shahaibo
f1adbb4da7 TASK:LLM; 2025-05-20 14:24:16 +08:00
shahaibo
4dfee09abb TASK:LLM; 2025-05-20 13:56:42 +08:00
shahaibo
16e4f7c5b5 TASK:LLM; 2025-05-20 13:37:46 +08:00
shahaibo
e9e40e53bc TASK:LLM; 2025-05-20 13:16:57 +08:00
shahaibo
a2625fa73f TASK:LLM; 2025-05-20 11:24:02 +08:00
shahaibo
ab804d57c1 TASK:LLM; 2025-05-20 10:42:18 +08:00
shahaibo
cef2fca099 TASK:LLM; 2025-05-20 10:39:00 +08:00
shahaibo
3d783974fc Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-05-20 10:29:30 +08:00
shahaibo
7f5a1615b3 TASK:LLM; 2025-05-20 10:29:22 +08:00
6c625de936 Merge branch 'dev/dev_xp' into dev/dev 2025-05-19 14:04:40 +08:00
aeb372bc17 TASK:企业、教育版library元素共享、作品广场作品发布到公共gallery 2025-05-19 14:02:42 +08:00
shahaibo
738144ad22 TASK:LLM; 2025-05-19 10:47:02 +08:00
shahaibo
a67b487dc0 TASK:LLM; 2025-05-19 10:23:53 +08:00
shahaibo
8613d4fc7a TASK:LLM; 2025-05-19 10:15:16 +08:00
shahaibo
6aa1a3d167 TASK:LLM; 2025-05-19 10:00:19 +08:00
shahaibo
59ffa38ff7 TASK:LLM; 2025-05-18 12:46:12 +08:00
bf92edb267 BUGFIX: 消息被双重转义时无法被正常解析,导致消息一直被重复消费 2025-05-09 07:51:37 +08:00
c72f382804 designSingle 取消颜色限制 2025-05-08 14:23:40 +08:00
shahaibo
6d6768e6cb TASK:模块化; 2025-05-06 17:30:01 +08:00
shahaibo
a84fe12a28 TASK:模块化; 2025-05-02 14:33:53 +08:00
shahaibo
be019dcdd0 TASK:模块化; 2025-05-02 14:26:21 +08:00
shahaibo
82d65c3015 TASK:模块化; 2025-04-29 17:21:16 +08:00
shahaibo
815392fffa TASK:模块化; 2025-04-29 16:16:36 +08:00
shahaibo
35e95c835e Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-04-29 15:09:09 +08:00
shahaibo
1263409d7c TASK:模块化; 2025-04-29 15:08:59 +08:00
e5b184ea6d Merge branch 'dev/dev_xp' into dev/dev 2025-04-28 15:26:35 +08:00
aa0778958e BUGFIX: 用户被删除的情况下,获取该云过户原来的评论,点赞等记录 2025-04-28 15:26:07 +08:00
50b78e9898 Merge branch 'dev/dev_xp' into dev/dev 2025-04-28 14:56:48 +08:00
58af5c5570 删除优惠券 2025-04-28 14:56:13 +08:00
63cde1f6a0 Merge branch 'dev/dev_xp' into dev/dev 2025-04-28 14:53:04 +08:00
89e6ee9eff 用户账号不存在的情况下获取评论报错 2025-04-28 14:51:19 +08:00
200c0adfba Affiliate 允许为不同的用户设置不同的affiliate
Stripe 添加优惠券删除接口;限制优惠券只能在订阅时使用
2025-04-28 14:40:42 +08:00
shahaibo
306f4f3987 TASK:模块化; 2025-04-25 15:34:35 +08:00
shahaibo
1240a57405 TASK:模块化; 2025-04-25 11:01:06 +08:00
shahaibo
a9acc83bdf TASK:模块化; 2025-04-25 10:19:12 +08:00
a2d259aea1 从Stripe退款后,修改订单状态,添加退款记录 2025-04-25 10:06:07 +08:00
shahaibo
7ff8a9db22 TASK:模块化; 2025-04-23 15:36:56 +08:00
shahaibo
7b6904059f TASK:模块化; 2025-04-23 15:35:21 +08:00
shahaibo
eec9c6ebf2 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-04-23 14:52:39 +08:00
shahaibo
1e8884a7c3 TASK:模块化; 2025-04-23 14:52:32 +08:00
9d591bb070 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-04-23 14:23:46 +08:00
db4bad22f4 Merge branch 'dev/dev_xp' into dev/dev 2025-04-23 14:23:30 +08:00
58bd986090 图片分割,区分类型 2025-04-23 14:22:21 +08:00
shahaibo
9e5bafc75e TASK:模块化; 2025-04-23 14:05:14 +08:00
shahaibo
938ad7366f TASK:模块化; 2025-04-23 11:22:52 +08:00
shahaibo
56ec903807 TASK:模块化; 2025-04-23 10:56:32 +08:00
shahaibo
5913445257 TASK:模块化; 2025-04-23 10:25:02 +08:00
shahaibo
2d1d458929 TASK:模块化; 2025-04-23 10:14:15 +08:00
shahaibo
5a0c461961 TASK:模块化; 2025-04-22 16:24:05 +08:00
shahaibo
74ad20646d TASK:模块化; 2025-04-22 16:11:00 +08:00
shahaibo
604c57c208 TASK:模块化; 2025-04-22 15:59:08 +08:00
shahaibo
aca21b9d98 TASK:模块化; 2025-04-22 15:26:55 +08:00
shahaibo
b83a416dda TASK:模块化; 2025-04-22 14:20:57 +08:00
shahaibo
d1858ddf83 TASK:模块化; 2025-04-22 14:18:54 +08:00
shahaibo
aa1c48fcfe TASK:模块化; 2025-04-22 13:48:36 +08:00
shahaibo
b19bbf91f2 TASK:模块化; 2025-04-22 11:24:28 +08:00
shahaibo
d9e4fb3022 TASK:模块化; 2025-04-22 09:58:14 +08:00
shahaibo
cc8f2e0778 TASK:模块化; 2025-04-21 23:44:55 +08:00
shahaibo
9b1881349f TASK:模块化; 2025-04-21 23:40:30 +08:00
shahaibo
eacceb4b76 TASK:模块化; 2025-04-21 22:36:03 +08:00
shahaibo
c50c193a46 TASK:模块化; 2025-04-21 22:35:32 +08:00
shahaibo
dfe99ef080 TASK:模块化; 2025-04-21 22:13:53 +08:00
shahaibo
98e1f37c1d TASK:模块化; 2025-04-21 21:50:03 +08:00
shahaibo
05295b1a0d TASK:模块化; 2025-04-21 21:21:23 +08:00
shahaibo
6fb04a66df TASK:模块化; 2025-04-21 21:18:29 +08:00
shahaibo
ba14b67c24 TASK:模块化; 2025-04-21 19:40:41 +08:00
shahaibo
0a4d6ff13b TASK:模块化; 2025-04-21 18:51:43 +08:00
shahaibo
fc2795b83e TASK:模块化; 2025-04-17 16:30:06 +08:00
shahaibo
4c726ff747 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-04-17 16:08:17 +08:00
shahaibo
4ed93c7e48 TASK:模块化; 2025-04-17 16:08:10 +08:00
shahaibo
acb37bc255 TASK:模块化; 2025-04-17 16:07:50 +08:00
shahaibo
9b5040d449 TASK:模块化; 2025-04-16 16:35:51 +08:00
shahaibo
fe0d1f39b0 TASK:模块化; 2025-04-16 16:28:27 +08:00
79d2720733 Merge branch 'dev/dev_xp' into dev/dev 2025-04-15 15:58:51 +08:00
218d828e0d Stripe推广码 部分功能完善 2025-04-15 15:58:22 +08:00
2269662290 Stripe支付测试--切换支付方式配置 2025-04-15 11:20:03 +08:00
eaec1e4177 Stripe支付测试--切换支付环境 2025-04-15 10:38:10 +08:00
eaff87882e Merge branch 'dev/dev_xp' into dev/dev 2025-04-15 10:23:30 +08:00
0ba28588da Stripe支付--添加推广码功能及相应佣金计算 2025-04-15 10:22:45 +08:00
25f64831f3 Merge branch 'dev/dev_xp' into dev/dev 2025-04-14 15:20:32 +08:00
d6c869727a 应要求修改参数名 2025-04-14 15:18:54 +08:00
77a06e0edd bugfix:account mapper count 去重问题 2025-04-14 14:58:23 +08:00
21efcf3ea6 查询所有的生成功能名字 2025-04-14 14:14:45 +08:00
d77e1d74b0 Merge branch 'dev/dev_xp' into dev/dev 2025-04-14 13:37:25 +08:00
1ce6c74f2c 优惠券查询DTO 2025-04-14 13:37:01 +08:00
3c4b645772 Merge branch 'dev/dev_xp' into dev/dev 2025-04-14 13:34:56 +08:00
909978467c 查询积分DTO 2025-04-14 13:34:35 +08:00
912c449161 Merge branch 'dev/dev_xp' into dev/dev
# Conflicts:
#	src/main/java/com/ai/da/service/CollectionElementService.java
#	src/main/java/com/ai/da/service/impl/CollectionElementServiceImpl.java
2025-04-14 13:30:02 +08:00
7f05bb2f7d 新增接口:图片分割 2025-04-14 13:26:56 +08:00
cbc760ebaf 便利查询--各版本管理员查看用户的design频次和各生成功能使用频次以及积分使用情况 2025-04-13 17:20:14 +08:00
shahaibo
48bb0cbff5 TASK:模块化; 2025-04-11 17:42:36 +08:00
shahaibo
1403b7851a TASK:模块化; 2025-04-11 15:11:44 +08:00
shahaibo
c36081996d TASK:模块化; 2025-04-11 14:33:25 +08:00
shahaibo
14dbc35eda TASK:模块化; 2025-04-11 14:16:54 +08:00
shahaibo
64c03768ff TASK:模块化; 2025-04-11 14:07:37 +08:00
shahaibo
b806bef0bf TASK:模块化; 2025-04-11 11:03:48 +08:00
shahaibo
811d22e229 TASK:模块化; 2025-04-11 10:49:22 +08:00
shahaibo
1ee612674e TASK:模块化; 2025-04-11 10:10:38 +08:00
shahaibo
cf9b621159 TASK:模块化; 2025-04-10 14:17:28 +08:00
shahaibo
03ae184541 TASK:模块化; 2025-04-10 14:00:33 +08:00
shahaibo
6b62d26544 TASK:模块化; 2025-04-10 11:01:24 +08:00
shahaibo
3883864558 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-04-09 10:30:56 +08:00
shahaibo
1089f37022 TASK:模块化; 2025-04-09 10:30:25 +08:00
c661767de3 Merge branch 'dev/dev_xp' into dev/dev 2025-04-09 09:48:51 +08:00
7b75e6ac69 获取所有姿势变换的pose 2025-04-09 09:48:00 +08:00
bd1f1deb53 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-04-08 18:07:00 +08:00
e142d50d18 Merge branch 'dev/dev_xp' into dev/dev 2025-04-08 18:06:40 +08:00
6250e763c3 获取所有姿势变换的pose 2025-04-08 18:05:49 +08:00
shahaibo
4cda43f3b5 TASK:模块化; 2025-04-08 17:29:10 +08:00
shahaibo
fd8d71e2a2 TASK:模块化; 2025-04-08 15:15:39 +08:00
shahaibo
87b702c24b TASK:模块化; 2025-04-08 11:09:28 +08:00
shahaibo
27cd98f0db TASK:模块化; 2025-04-07 17:12:33 +08:00
shahaibo
d1603fbc16 TASK:模块化; 2025-04-07 16:07:26 +08:00
shahaibo
96ba29a9a2 TASK:模块化; 2025-04-03 15:31:39 +08:00
shahaibo
5d9ca09272 TASK:模块化; 2025-04-03 14:27:03 +08:00
shahaibo
64676736b5 TASK:模块化; 2025-04-03 14:22:21 +08:00
shahaibo
7106482831 TASK:模块化; 2025-04-03 14:14:28 +08:00
shahaibo
b1c8606432 TASK:模块化; 2025-04-03 13:49:36 +08:00
shahaibo
0eb02c598e Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-04-02 17:14:32 +08:00
shahaibo
b6367d72ba TASK:模块化; 2025-04-02 17:13:58 +08:00
2e76bded8c Merge branch 'dev/dev_xp' into dev/dev 2025-04-02 15:57:18 +08:00
0e7c07b3b5 上传模特时保存点位信息接口修改 2025-04-02 15:56:05 +08:00
shahaibo
3e3b1eb868 TASK:模块化; 2025-04-02 15:32:48 +08:00
shahaibo
ec0309d6f2 TASK:模块化; 2025-04-02 15:27:16 +08:00
shahaibo
8ee7a030bd Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-04-02 15:18:27 +08:00
shahaibo
ca9778a416 TASK:模块化; 2025-04-02 15:18:20 +08:00
07504d8412 Merge branch 'dev/dev_xp' into dev/dev 2025-04-02 13:34:11 +08:00
88796f7f28 修改添加系统模特到个人lib接口和保存模特接口 2025-04-02 13:32:12 +08:00
shahaibo
8764e750ff Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-04-02 13:14:16 +08:00
shahaibo
9d2cb29255 TASK:模块化; 2025-04-02 13:09:48 +08:00
a1b8f9e000 修改添加系统模特到个人lib接口 2025-04-02 12:03:48 +08:00
6f2c670fce Merge branch 'dev/dev_xp' into dev/dev 2025-04-02 11:09:41 +08:00
d21cb4adfc 修改模特保存接口和添加系统模特到个人lib接口 2025-04-02 11:08:35 +08:00
shahaibo
97b922c1be TASK:模块化; 2025-04-01 17:52:55 +08:00
shahaibo
0af5b2121c TASK:模块化; 2025-04-01 17:44:16 +08:00
36be8b5420 修改模特比例接口不再与模特点位信息关联 2025-04-01 17:22:45 +08:00
a34d775f63 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-04-01 17:16:49 +08:00
1bee672592 Merge branch 'dev/dev_xp' into dev/dev 2025-04-01 17:16:27 +08:00
shahaibo
cf08f9126e TASK:模块化; 2025-04-01 17:16:27 +08:00
8e938e9f06 更新模特点位接口修改 2025-04-01 17:15:38 +08:00
shahaibo
a08744f71a TASK:模块化; 2025-04-01 15:42:15 +08:00
shahaibo
913c4c1ece TASK:模块化; 2025-04-01 15:20:59 +08:00
shahaibo
03f3162dc1 TASK:模块化; 2025-03-31 15:40:36 +08:00
shahaibo
0eb839e7c7 TASK:模块化; 2025-03-31 15:37:05 +08:00
shahaibo
807d3e1c46 TASK:模块化; 2025-03-31 15:27:17 +08:00
shahaibo
e6f990b766 TASK:模块化; 2025-03-31 15:02:44 +08:00
shahaibo
6dcc492127 TASK:模块化; 2025-03-31 11:53:43 +08:00
shahaibo
a2bd2fa6c6 TASK:模块化; 2025-03-31 11:21:45 +08:00
shahaibo
2edf7d211b TASK:模块化; 2025-03-30 23:31:00 +08:00
shahaibo
890265611a TASK:模块化; 2025-03-30 16:14:13 +08:00
shahaibo
48c7182f98 TASK:模块化; 2025-03-30 15:56:03 +08:00
shahaibo
2cfd342ef8 TASK:模块化; 2025-03-28 11:14:48 +08:00
shahaibo
63513df053 TASK:模块化; 2025-03-28 11:05:45 +08:00
shahaibo
bb00d9a714 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-03-28 09:37:51 +08:00
shahaibo
3398992bcd TASK:模块化; 2025-03-28 09:37:42 +08:00
2912463562 Merge branch 'dev/dev_xp' into dev/dev 2025-03-27 17:46:47 +08:00
3df4433381 BUGFIX: sketch拼贴 2025-03-27 17:46:09 +08:00
shahaibo
a8f868e215 TASK:模块化; 2025-03-27 14:32:56 +08:00
shahaibo
78a5bebb4f TASK:模块化; 2025-03-27 13:55:16 +08:00
shahaibo
33582922be TASK:模块化; 2025-03-27 13:38:47 +08:00
shahaibo
e6234213f0 TASK:模块化; 2025-03-27 13:33:09 +08:00
shahaibo
1d9a89d7c7 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-03-26 15:13:06 +08:00
shahaibo
b0560b840f TASK:模块化; 2025-03-26 15:12:55 +08:00
20b15c0b78 sketch拼贴 添加返回服装分类 2025-03-26 13:39:39 +08:00
a4365abd4d 模特比例修改参数变换 2025-03-25 17:37:35 +08:00
1cb02a62e8 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-03-25 16:20:14 +08:00
67225c1a96 从统一接口获取pose transformation的生成记录 2025-03-25 16:20:00 +08:00
50ecc3a177 Merge branch 'dev/dev_xp' into dev/dev 2025-03-25 16:11:33 +08:00
63c9ff36a1 新增like\dislike pose transformation接口 2025-03-25 16:11:03 +08:00
shahaibo
dc62ca956c Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-03-25 16:10:19 +08:00
shahaibo
d45c555415 TASK:模块化; 2025-03-25 16:10:10 +08:00
a657464d22 sketch拼贴 获取模块信息走统一接口 2025-03-25 14:56:16 +08:00
b5b67e0c75 Merge branch 'dev/dev_xp' into dev/dev 2025-03-25 14:43:47 +08:00
619d0e817f sketch拼贴 获取画布走统一接口 2025-03-25 14:37:38 +08:00
shahaibo
5d7beca57d Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-03-25 13:16:40 +08:00
shahaibo
9a933e74ff TASK:模块化; 2025-03-25 13:16:31 +08:00
0b60dd799f Merge branch 'dev/dev_xp' into dev/dev 2025-03-25 11:45:37 +08:00
a38c15005e 开发环境 添加邮件相关配置信息 2025-03-25 11:45:10 +08:00
b5a8c635d6 Merge branch 'dev/dev_xp' into dev/dev 2025-03-25 11:38:31 +08:00
6b288a3b3c 邮件发送系统-初版 2025-03-25 11:37:53 +08:00
9a5718cc35 Merge remote-tracking branch 'origin/dev/dev' into dev/dev
# Conflicts:
#	src/main/java/com/ai/da/python/PythonService.java
2025-03-25 11:26:50 +08:00
cc804bac7d Merge branch 'dev/dev_xp' into dev/dev
# Conflicts:
#	src/main/java/com/ai/da/python/PythonService.java
2025-03-25 11:25:22 +08:00
b18a5a0050 模特比例修改、sketch拼贴 2025-03-25 11:22:17 +08:00
078a0c0dfb 模特比例修改、sketch拼贴 2025-03-25 11:19:55 +08:00
shahaibo
d080fc04bb TASK:模块化; 2025-03-25 10:51:16 +08:00
shahaibo
ae484c9e6c TASK:模块化; 2025-03-24 15:59:46 +08:00
shahaibo
39cb20618b TASK:代码覆盖修复; 2025-03-24 15:08:23 +08:00
shahaibo
5b95401204 TASK:AiDA模块化 2025-03-21 09:59:42 +08:00
6b62cf7299 PoseTransformation-初版 2025-03-20 17:42:16 +08:00
shahaibo
af352bbfe8 TASK:AiDA模块化 2025-03-20 16:47:34 +08:00
shahaibo
4d7673e8df TASK:AiDA模块化 2025-03-20 16:46:13 +08:00
shahaibo
55ec6da74b TASK:AiDA模块化 2025-03-19 14:13:16 +08:00
shahaibo
83d9a5befb TASK:AiDA模块化 2025-03-19 14:08:16 +08:00
shahaibo
ec836a6470 TASK:AiDA模块化 2025-03-19 12:17:29 +08:00
shahaibo
d6f9aa155e TASK:AiDA模块化 2025-03-19 11:55:38 +08:00
shahaibo
d3b507ed45 TASK:AiDA模块化 2025-03-19 11:35:13 +08:00
shahaibo
b027396567 TASK:AiDA模块化 2025-03-19 11:09:15 +08:00
shahaibo
7d0a6ae2bf TASK:AiDA模块化 2025-03-19 11:02:13 +08:00
shahaibo
d12bf41021 TASK:AiDA模块化 2025-03-19 10:51:15 +08:00
shahaibo
ca3a584100 TASK:AiDA模块化 2025-03-19 10:47:39 +08:00
shahaibo
47d0856296 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-03-19 10:39:52 +08:00
shahaibo
a828d75248 TASK:AiDA模块化 2025-03-19 10:39:42 +08:00
edc769ca79 to dev 2025-03-19 09:56:21 +08:00
0a22f01587 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-03-19 09:52:49 +08:00
45f0d571d6 Merge branch 'release/3.0' into dev/dev
# Conflicts:
#	src/main/java/com/ai/da/common/config/MyTaskScheduler.java
2025-03-19 09:51:36 +08:00
shahaibo
880adf7c69 TASK:AiDA模块化 2025-03-19 09:48:14 +08:00
shahaibo
591b4bf119 TASK:AiDA模块化 2025-03-19 09:27:10 +08:00
shahaibo
2db65776b1 TASK:AiDA模块化 2025-03-18 17:38:28 +08:00
shahaibo
7742bd56f8 TASK:AiDA模块化 2025-03-18 17:11:36 +08:00
shahaibo
3159208a0a TASK:AiDA模块化 2025-03-18 16:54:21 +08:00
shahaibo
971b2034ee TASK:AiDA模块化 2025-03-18 13:43:59 +08:00
shahaibo
f17d171231 TASK:AiDA模块化 2025-03-17 11:42:02 +08:00
shahaibo
4be008382f TASK:AiDA模块化 2025-03-17 11:37:12 +08:00
shahaibo
1ae1703f53 Merge remote-tracking branch 'origin/dev/dev' into dev/dev 2025-03-17 11:30:48 +08:00
shahaibo
340227d9a6 TASK:AiDA模块化 2025-03-17 11:30:09 +08:00
shahaibo
fb99e83b2d TASK:AIDA模块化; 2025-03-16 13:48:54 +08:00
shahaibo
8fa76c6732 TASK:AiDA模块化 2025-03-16 13:09:50 +08:00
shahaibo
1637db2fe3 TASK:AiDA模块化 2025-03-13 17:57:27 +08:00
shahaibo
575d1492ad BUGFIX: 隐藏加载不出minio的相关数据; 2025-03-12 23:22:41 +08:00
79abe93744 Stripe 回调判空并直接返回 2025-02-28 14:27:36 +08:00
f580955c97 Stripe 回调判空 2025-02-28 14:18:32 +08:00
6a625ed4ea 设置未修改局部design图时的图片地址 2025-02-27 09:58:35 +08:00
8a47d9f3da 修改历史数据中的mask分割状态 2025-02-25 18:27:23 +08:00
148b6492ea 现在design后的mask 默认已分割 2025-02-25 18:14:43 +08:00
be3fa7a704 编辑前后片,添加日志打印 2025-02-25 18:03:52 +08:00
63af2daf28 打开前后片编辑 2025-02-25 15:44:21 +08:00
37be3a1759 1、局部design 未保存前,不覆盖原图
2、打开前后片编辑
2025-02-25 15:22:14 +08:00
df2547ff81 参数名统一 2025-02-25 14:24:15 +08:00
7693de93dc 参数名统一 2025-02-25 14:19:32 +08:00
c061045466 Merge branch 'dev/dev_xp' into dev/dev 2025-02-25 14:02:58 +08:00
abd68f2dc8 参数结构修改 2025-02-25 14:02:29 +08:00
285f956caa 配置修改 添加桶 2025-02-25 13:03:52 +08:00
019cf4adf4 Merge branch 'dev/dev_xp' into dev/dev 2025-02-25 11:48:39 +08:00
cf38e7253f 局部design 2025-02-25 11:48:08 +08:00
596 changed files with 44723 additions and 13319 deletions

View File

@@ -0,0 +1,176 @@
name: 手动 AiDA back-java 开发分支构建部署
on:
workflow_dispatch:
jobs:
build_and_deploy:
runs-on: ubuntu-latest
outputs:
build_status: ${{ job.status }}
build_url: ${{ gitea.server_url }}/${{ gitea.repository.owner.name }}/${{ gitea.repository.name }}/actions/runs/${{ gitea.run_id }}
permissions:
contents: read
packages: write
env:
REMOTE_DEPLOY_PATH: /workspace/workspace_aida/DevelopVersion/develop-version-aida-back
steps:
- name: 0.记录开始时间
id: build_start_time
run: echo "current_time=$(TZ='Asia/Hong_Kong' date '+%Y-%m-%d %H:%M:%S %Z')" >> $GITHUB_OUTPUT
- name: 1.检出代码
uses: actions/checkout@v4
with:
ref: dev/3.1_release_merge
- name: 2.Set up JDK 21
uses: actions/setup-java@v5
with:
java-version: '21'
distribution: 'temurin'
- name: 3.设置JAVA Maven 环境
run: |
# 适配root/普通用户
SUDO=""
[ "$(id -u)" != "0" ] && SUDO="sudo"
# 安装依赖
$SUDO apt update && $SUDO apt install -y wget tar --no-install-recommends
# 下载Maven
MAVEN_VERSION="3.9.11"
MAVEN_TAR="apache-maven-${MAVEN_VERSION}-bin.tar.gz"
MAVEN_URL="https://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries/${MAVEN_TAR}"
wget --no-verbose -O /tmp/${MAVEN_TAR} ${MAVEN_URL}
# 解压+软链接
$SUDO tar -xzf /tmp/${MAVEN_TAR} -C /usr/local/
$SUDO ln -sf /usr/local/apache-maven-${MAVEN_VERSION} /usr/local/maven
# 配置PATH
echo "/usr/local/maven/bin" >> $GITHUB_PATH
export PATH="/usr/local/maven/bin:$PATH"
# 验证
mvn -v
- name: 4.构建jar包
run: |
echo "===== 开始构建JAR包 ====="
# 新增:打印当前构建分支(两种方式双重确认)
echo "当前工作目录分支:$(git branch --show-current)"
echo "Gitea检出分支:${{ github.ref_name }}"
echo "预期构建分支:dev/3.1_release_merge"
echo "========================"
mvn -B clean install -DskipTests -Pdev 2>&1
# 检查构建是否成功
if [ $? -ne 0 ]; then
echo "JAR包构建失败!"
exit 1
fi
- name: 5.生成Dockerfile
run: |
echo "===== 生成Dockerfile ====="
cat > Dockerfile << 'EOF'
FROM openjdk:21-ea-21-jdk-slim
VOLUME /tmp
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' > /etc/timezone
ADD ./aida-0.0.1-SNAPSHOT.jar /app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
EOF
echo "Dockerfile内容:"
cat Dockerfile
- name: 6.生成docker-compose.yml
run: |
echo "===== 生成docker-compose.yml ====="
cat > docker-compose.yml << 'EOF'
version: '3'
services:
aida_back:
container_name: develop-version-aida-back
build: .
volumes:
# 数据挂载
- ./log:/log
- ./temp:/temp
- ./uploads:/temp/uploads
ports:
- '10090:5567'
restart: always
EOF
# 验证docker-compose.yml生成
echo "docker-compose.yml内容:"
cat docker-compose.yml
- name: 7.安装SSH工具
run: |
$SUDO apt install -y sshpass openssh-client --no-install-recommends
# 配置SSH免密
mkdir -p ~/.ssh
echo "${{ secrets.SSH_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H ${{ secrets.SERVER_HOST }} >> ~/.ssh/known_hosts
- name: 8.同步文件到远程服务器
run: |
echo "===== 同步文件到远程服务器 ====="
# 使用scp同步文件
scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
./target/*.jar ./Dockerfile ./docker-compose.yml \
${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }}:${{ env.REMOTE_DEPLOY_PATH }} 2>&1
- name: 9.部署和运行服务
run: |
echo "===== 开始部署服务 ====="
# SSH执行部署命令
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }} << 'EOF_SSH'
cd ${{ env.REMOTE_DEPLOY_PATH }}
echo "停止旧容器..."
docker compose down || true
echo "清理Docker资源..."
docker system prune -f
echo "构建镜像..."
docker compose build --no-cache
echo "启动服务..."
docker compose up -d
echo "验证容器状态..."
docker compose ps
echo "部署完成!"
EOF_SSH
- name: 10.发送构建结果邮件
if: always() # 无论上一步是否失败,都执行此步骤
uses: dawidd6/action-send-mail@v3
with:
from: ${{ secrets.MAIL_USERNAME }}
# --- 邮件配置 ---
server_address: smtp.gmail.com # 替换为你的SMTP服务器地址
server_port: 465 # 替换为你的SMTP端口 (通常是465或587)
username: ${{ secrets.MAIL_USERNAME }} # 存储在Secrets中的邮箱用户名
password: ${{ secrets.MAIL_PASSWORD }} # 存储在Secrets中的邮箱密码
subject: 'Gitea Actions 构建通知: ${{ job.status }} - AiDA back-java Develop'
# 收件人列表,可以根据需要更改
to: 'cgzhou@aidlab.hk,zchengrong@yeah.net' # 替换为实际收件人邮箱
# --- 邮件正文内容 ---
body: |
项目: AiDA back-java Develop
分支: dev/3.1_release_merge
🎉 构建结果: ${{ job.status }}
📅 构建时间: ${{ steps.build_start_time.outputs.current_time }}
🔗 构建链接: ${{ gitea.server_url }}/${{ gitea.repository.owner.name }}/${{ gitea.repository.name }}/actions/runs/${{ gitea.run_id }}
# 确保邮件内容为纯文本,或者你可以设置为 html: true 并调整 body
content_type: text/plain

1
.gitignore vendored
View File

@@ -48,3 +48,4 @@ log
temp/
docker-compose.yml
/src/main/resources/application-local.properties

View File

@@ -1,7 +0,0 @@
FROM openjdk:8
VOLUME /tmp
#时区设置
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' > /etc/timezone
ADD ./target/aida-0.0.1-SNAPSHOT.jar /app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="FacetManager">
<facet type="Spring" name="Spring">
<configuration />
</facet>
</component>
</module>

844
pom.xml
View File

@@ -1,364 +1,480 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.aida</groupId>
<artifactId>aida</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>aida</name>
<description>ai da</description>
<properties>
<java.version>8</java.version>
<mybatis.plus.version>3.5.2</mybatis.plus.version>
<hutool.version>5.8.2</hutool.version>
<wx.java.version>4.2.7.B</wx.java.version>
<fastjson.version>2.0.6.graal</fastjson.version>
<security.jwt.version>1.1.1.RELEASE</security.jwt.version>
<jjwt.version>0.9.1</jjwt.version>
<guava.version>31.1-jre</guava.version>
<jaxb-api>2.4.0-b180830.0359</jaxb-api>
<jaxb-impl>4.0.0</jaxb-impl>
<jaxb-core>4.0.0</jaxb-core>
<activation>1.1.1</activation>
<easy-captcha>1.6.2</easy-captcha>
<aws.java.sdk.version>2.20.43</aws.java.sdk.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>bom</artifactId>
<version>${aws.java.sdk.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
<version>${security.jwt.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis.plus.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jjwt.version}</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.14.2</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>${jaxb-api}</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>${jaxb-impl}</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>${jaxb-core}</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>${activation}</version>
</dependency>
<dependency>
<groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId>
<version>${easy-captcha}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<!-- /**发送邮件**/-->
<!-- <dependency>-->
<!-- <groupId>com.tencentcloudapi</groupId>-->
<!-- <artifactId>tencentcloud-sdk-java-ses</artifactId>-->
<!-- <version>3.1.572</version>-->
<!-- </dependency>-->
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java</artifactId>
<version>3.1.572</version>
</dependency>
<!--minio-->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.0.3</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>9.2.1.jre8</version>
</dependency>
<!-- RabbitMQ -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!-- redis 连接池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!--支付宝 SDK-->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.22.57.ALL</version>
</dependency>
<!--PayPal SDK-->
<dependency>
<groupId>com.paypal.sdk</groupId>
<artifactId>checkout-sdk</artifactId>
<version>1.0.5</version>
</dependency>
<dependency>
<groupId>com.paypal.sdk</groupId>
<artifactId>rest-api-sdk</artifactId>
<version>LATEST</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20230618</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.1</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.1</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.1</version>
</dependency>
<dependency>
<groupId>com.stripe</groupId>
<artifactId>stripe-java</artifactId>
<version>26.2.0</version>
</dependency>
<!-- aws s3 -->
<!-- S3 dependency -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3-transfer-manager</artifactId>
<version>2.17.103-PREVIEW</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>kms</artifactId>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3control</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>com.google.auth</groupId>
<artifactId>google-auth-library-oauth2-http</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>com.google.api-client</groupId>
<artifactId>google-api-client</artifactId>
<version>1.32.1</version>
</dependency>
<dependency>
<groupId>com.google.oauth-client</groupId>
<artifactId>google-oauth-client</artifactId>
<version>1.32.1</version>
</dependency>
<dependency>
<groupId>com.google.http-client</groupId>
<artifactId>google-http-client-jackson2</artifactId>
<version>1.41.5</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<!-- 本地开发环境 -->
<id>dev</id>
<properties>
<profiles.active>dev</profiles.active>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<!-- 测试环境 -->
<id>test</id>
<properties>
<profiles.active>test</profiles.active>
</properties>
</profile>
<profile>
<!-- 生产环境 -->
<id>prod</id>
<properties>
<profiles.active>prod</profiles.active>
</properties>
</profile>
</profiles>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.aida</groupId>
<artifactId>aida</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>aida</name>
<description>ai da</description>
<properties>
<java.version>21</java.version>
<mybatis.plus.version>3.5.5</mybatis.plus.version>
<hutool.version>5.8.23</hutool.version>
<wx.java.version>4.2.7.B</wx.java.version>
<fastjson.version>2.0.43</fastjson.version>
<jjwt.version>0.12.3</jjwt.version>
<guava.version>32.1.3-jre</guava.version>
<easy-captcha>1.6.2</easy-captcha>
<aws.java.sdk.version>2.20.43</aws.java.sdk.version>
<javacv.version>1.5.5</javacv.version>
<system.windowsx64>windows-x86_64</system.windowsx64>
<javacpp.platform.linux-x86_64>linux-x86_64</javacpp.platform.linux-x86_64>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>bom</artifactId>
<version>${aws.java.sdk.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis.plus.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>${jjwt.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>${jjwt.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>${jjwt.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.14.2</version>
</dependency>
<!-- JAXB is included in Java 11+ but needs explicit dependency for Java 9-10 -->
<!-- For Java 21, these are not needed as JAXB is part of JDK -->
<dependency>
<groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId>
<version>${easy-captcha}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>4.4.0</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.3.0</version>
</dependency>
<!-- Swagger 2 annotations for backward compatibility -->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.6.14</version>
</dependency>
<!-- /**发送邮件**/-->
<!-- <dependency>-->
<!-- <groupId>com.tencentcloudapi</groupId>-->
<!-- <artifactId>tencentcloud-sdk-java-ses</artifactId>-->
<!-- <version>3.1.572</version>-->
<!-- </dependency>-->
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java-ses</artifactId>
<version>3.1.572</version>
</dependency>
<!--minio-->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.0.3</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>12.4.2.jre11</version>
</dependency>
<!-- RabbitMQ -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!-- redis 连接池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!--支付宝 SDK-->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.22.57.ALL</version>
</dependency>
<!--PayPal SDK-->
<dependency>
<groupId>com.paypal.sdk</groupId>
<artifactId>checkout-sdk</artifactId>
<version>1.0.5</version>
</dependency>
<dependency>
<groupId>com.paypal.sdk</groupId>
<artifactId>rest-api-sdk</artifactId>
<version>LATEST</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20230618</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.4</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.4</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.15.1</version>
</dependency>
<dependency>
<groupId>com.stripe</groupId>
<artifactId>stripe-java</artifactId>
<version>26.2.0</version>
</dependency>
<!-- aws s3 -->
<!-- S3 dependency -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3-transfer-manager</artifactId>
<version>2.17.103-PREVIEW</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>kms</artifactId>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3control</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>com.google.auth</groupId>
<artifactId>google-auth-library-oauth2-http</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>com.google.api-client</groupId>
<artifactId>google-api-client</artifactId>
<version>1.32.1</version>
</dependency>
<dependency>
<groupId>com.google.oauth-client</groupId>
<artifactId>google-oauth-client</artifactId>
<version>1.32.1</version>
</dependency>
<dependency>
<groupId>com.google.http-client</groupId>
<artifactId>google-http-client-jackson2</artifactId>
<version>1.41.5</version>
</dependency>
<!-- 邮件发送 -->
<!-- thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.3.3</version>
</dependency>
<!-- JSON 转义恢复 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.10.0</version> <!-- 使用最新版本 -->
</dependency>
<!-- 最新版本号https://mvnrepository.com/artifact/com.alibaba/dashscope-sdk-java -->
<!-- 万象SDK -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dashscope-sdk-java</artifactId>
<version>2.20.1</version>
</dependency>
<!-- FFmpeg封装JavaCV 视频转gif 全部依赖-->
<!--<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv-platform</artifactId>
<version>1.5.9</version>
</dependency>-->
<!-- javacv+javacpp核心库-->
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv</artifactId>
<version>${javacv.version}</version>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacpp-platform</artifactId>
<version>${javacv.version}</version>
</dependency>
<!-- 最小opencv依赖包 必须包含上面的javacv+javacpp -->
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>opencv</artifactId>
<version>4.5.1-${javacv.version}</version>
<!--<classifier>${system.windowsx64}</classifier>-->
<classifier>${javacpp.platform.linux-x86_64}</classifier>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>openblas</artifactId>
<version>0.3.13-${javacv.version}</version>
<!--<classifier>${system.windowsx64}</classifier>-->
<classifier>${javacpp.platform.linux-x86_64}</classifier>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>flycapture</artifactId>
<version>2.13.3.31-${javacv.version}</version>
<!--<classifier>${system.windowsx64}</classifier>-->
<classifier>${javacpp.platform.linux-x86_64}</classifier>
</dependency>
<!-- FFmpeg视频处理解决你的报错 -->
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>ffmpeg</artifactId>
<version>4.4-1.5.6</version>
<!--<classifier>${system.windowsx64}</classifier>-->
<classifier>${javacpp.platform.linux-x86_64}</classifier>
</dependency>
<dependency>
<groupId>com.volcengine</groupId>
<artifactId>volcengine-java-sdk-ark-runtime</artifactId>
<version>0.2.43</version>
</dependency>
<!-- Google 认证库 -->
<dependency>
<groupId>com.google.auth</groupId>
<artifactId>google-auth-library-oauth2-http</artifactId>
<version>1.38.0</version>
</dependency>
<!-- GIFEncoder 视频转gif-->
<dependency>
<groupId>com.madgag</groupId>
<artifactId>animated-gif-lib</artifactId>
<version>1.4</version>
</dependency>
<!-- Jakarta WebSocket API -->
<dependency>
<groupId>jakarta.websocket</groupId>
<artifactId>jakarta.websocket-api</artifactId>
<version>2.1.1</version>
</dependency>
<!-- Spring MockMultipartFile 等测试工具,生产代码中也有引用 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<!-- BouncyCastle 加密库 -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
<version>1.78.1</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
<version>1.78.1</version>
</dependency>
<!-- AOP -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<!-- 本地开发环境 -->
<id>dev</id>
<properties>
<profiles.active>dev</profiles.active>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<!-- 测试环境 -->
<id>test</id>
<properties>
<profiles.active>test</profiles.active>
</properties>
</profile>
<profile>
<!-- 生产环境 -->
<id>prod</id>
<properties>
<profiles.active>prod</profiles.active>
</properties>
</profile>
</profiles>
</project>

View File

@@ -3,11 +3,13 @@ package com.ai.da;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
@Slf4j
@SpringBootApplication
@EnableScheduling
@EnableAsync
public class AiDaApplication {
public static void main(String[] args) {

View File

@@ -0,0 +1,95 @@
package com.ai.da.common.RabbitMQ;
import com.ai.da.common.utils.MailUtil;
import com.ai.da.model.dto.BasicEmailParamDTO;
import com.ai.da.service.EmailService;
import com.alibaba.fastjson.JSONObject;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.core.io.InputStreamSource;
import org.springframework.stereotype.Component;
import software.amazon.awssdk.core.exception.RetryableException;
import org.springframework.amqp.core.Message;
import jakarta.annotation.Resource;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
@Slf4j
@Component
public class EmailRetryConsumer {
@Resource
private MailUtil mailUtil;
@Resource
private MQPublisher mqPublisher;
@Resource
private EmailService emailService;
// @RabbitListener(queues = "#{rabbitMQProperties.deadLetter.queue}")
public void handleRetry(Map<String, String> mailParams, Message message, Channel channel) throws IOException {
long tag = message.getMessageProperties().getDeliveryTag();
try {
log.info("死信队列收到消息:{}", message);
// 处理邮件发送参数
BasicEmailParamDTO basicEmailParamDTO = JSONObject.parseObject(mailParams.get("dto"), BasicEmailParamDTO.class);
String fileName = mailParams.get("filename");
InputStreamSource inputStreamSource = Objects.isNull(mailParams.get("source")) ?
null : JSONObject.parseObject(mailParams.get("source"), InputStreamSource.class);
JSONObject templateParams = JSONObject.parseObject(mailParams.get("templateParams"), JSONObject.class);
String templateName = mailParams.get("templatePath");
long logId = Long.parseLong(mailParams.get("logId"));
basicEmailParamDTO.setContent(mailUtil.setContent(templateParams, templateName));
// 发邮件
int lastReturnCode = mailUtil.sendMail(basicEmailParamDTO, fileName, inputStreamSource);
if (lastReturnCode == 250) {
log.info("邮件发送成功Subject : {}", basicEmailParamDTO.getSubject());
emailService.updateStatus(logId, EmailService.DELIVERED);
} else if (lastReturnCode == 450) {
log.info("目标邮箱 {} 暂时不可用,请稍后重试", (Object) basicEmailParamDTO.getMailTo());
// 重试
retry(mailParams, message, channel, tag, logId);
} else if (lastReturnCode == 550) {
log.info("目标邮箱 {} 不可用,邮件发送失败", (Object) basicEmailParamDTO.getMailTo());
emailService.updateStatus(logId, EmailService.FAILED);
} else {
log.info("邮件发送失败Subject : {}, 状态码: {}", basicEmailParamDTO.getSubject(), lastReturnCode);
retry(mailParams, message, channel, tag, logId);
emailService.updateStatus(logId, EmailService.FAILED);
}
channel.basicAck(tag, false);
} catch (RetryableException e) {
log.info("邮件重试发生异常:RetryableException -> {}", e.getMessage());
channel.basicAck(tag, false); // 确认原消息
} catch (Exception e) {
log.info("邮件重试发生异常:Exception -> {}", e.getMessage());
channel.basicAck(tag, false); // 确认原消息
}
}
private int getRetryAttempt(Message message) {
Integer attempt = message.getMessageProperties()
.getHeader("x-retry-attempt");
return attempt != null ? attempt : 1;
}
private void retry(Map<String, String> mailParams, Message message, Channel channel, long tag, long logId) throws IOException{
int attempt = getRetryAttempt(message);
if (attempt >= 3) { // 最大重试次数
channel.basicReject(tag, false);
emailService.updateStatus(logId, EmailService.FAILED);
log.error("重试结束,邮件最终发送失败: {}", mailParams);
} else {
log.info("重新将邮件信息发送到重试队列");
mqPublisher.sendEmailMsg(mailParams, attempt);
channel.basicAck(tag, false); // 确认原消息
// 更新数据库
emailService.updateRetryCount(logId, attempt + 1);
}
}
}

View File

@@ -5,42 +5,50 @@ import com.ai.da.common.constant.CommonConstant;
import com.ai.da.common.utils.RedisUtil;
import com.ai.da.model.dto.GenerateThroughImageTextDTO;
import com.ai.da.model.vo.GenerateResultVO;
import com.ai.da.service.GenerateService;
import com.ai.da.service.UserLikeGroupService;
import com.ai.da.model.vo.PoseTransformationVO;
import com.ai.da.service.*;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.rabbitmq.client.Channel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.jni.Time;
import org.apache.commons.text.StringEscapeUtils;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@Slf4j
@Component
@RequiredArgsConstructor
public class GenerateConsumer {
@Resource
private GenerateService generateService;
private final GenerateService generateService;
@Resource
private UserLikeGroupService userLikeGroupService;
private final UserLikeGroupService userLikeGroupService;
@Autowired
private RabbitMQProperties rabbitMQProperties;
private final DesignService designService;
@Resource
private RedisUtil redisUtil;
private final CloudTaskService cloudTaskService;
private final RabbitMQProperties rabbitMQProperties;
private final RedisUtil redisUtil;
private final MessageCenterService messageCenterService;
@Value("${redis.key.orderForGenerate}")
private String consumptionOrderKey;
@@ -61,9 +69,9 @@ public class GenerateConsumer {
public void generate(Message msg, Channel channel, String consumerName) {
log.info("============start listening==========");
long start = System.currentTimeMillis();
GenerateThroughImageTextDTO generateThroughImageTextDTO = JSONObject.parseObject(msg.getBody(), GenerateThroughImageTextDTO.class);
String uniqueId = generateThroughImageTextDTO.getUniqueId();
Map<String, String> resp = jsonBytesToMap(msg, channel);
String uniqueId = resp.get("tasks_id");
// String uniqueId = generateThroughImageTextDTO.getUniqueId();
log.info("From " + consumerName + " : " + uniqueId);
try {
@@ -77,6 +85,7 @@ public class GenerateConsumer {
log.error("手动确认,不返回队列重新消费");
}
} else {
GenerateThroughImageTextDTO generateThroughImageTextDTO = JSONObject.parseObject(msg.getBody(), GenerateThroughImageTextDTO.class);
generateService.generateThroughImageText(generateThroughImageTextDTO);
// 将消息从redis排队队列中删除,需保证被消费的消息存储到db之后再从redis删除
redisUtil.removeFromZSet(consumptionOrderKey, uniqueId);
@@ -91,13 +100,13 @@ public class GenerateConsumer {
// 将消息从redis排队队列中删除,需保证被消费的消息存储到db之后再从redis删除
redisUtil.removeFromZSet(consumptionOrderKey, uniqueId);
String key = generateResultKey + ":" + uniqueId;
GenerateResultVO generateResultVO = new GenerateResultVO(generateThroughImageTextDTO.getUniqueId(), null, null, "Fail");
GenerateResultVO generateResultVO = new GenerateResultVO(uniqueId, null, null, "Fail");
redisUtil.addToString(key, new Gson().toJson(generateResultVO), CommonConstant.GENERATE_RESULT_EXPIRE_TIME);
} catch (IOException exception) {
log.error("手动确认,取消返回队列,不再重新消费");
}
// 将入参和错误信息存入数据库
String exceptionMessage = JSONObject.toJSONString(generateThroughImageTextDTO) +
String exceptionMessage = JSONObject.toJSONString(resp) +
" Exception message " + e.getMessage();
HashMap<String, String> exceptionInfo = new HashMap<>();
exceptionInfo.put(String.valueOf(uniqueId), exceptionMessage);
@@ -114,7 +123,7 @@ public class GenerateConsumer {
log.info("============ProcessGenerateResult listening==========");
long start = System.currentTimeMillis();
Map<String, String> generateResult = JSONObject.parseObject(msg.getBody(), Map.class);
Map<String, String> generateResult = jsonBytesToMap(msg, channel);
log.info("generate response : {}", generateResult);
try {
@@ -162,7 +171,7 @@ public class GenerateConsumer {
log.info("============processToProductImageResult listening==========");
long start = System.currentTimeMillis();
Map<String, String> generateResult = JSONObject.parseObject(msg.getBody(), Map.class);
Map<String, String> generateResult = jsonBytesToMap(msg, channel);
log.info("toProductImage response : {}", generateResult);
try {
@@ -178,6 +187,7 @@ public class GenerateConsumer {
} else {
// 修改redis中的数据状态为exception
String key = toProductImageResultKey + ":" + generateResult.get("tasks_id");
generateService.updateToProductTaskStatus(generateResult.get("tasks_id"), "Fail");
redisUtil.addToString(key, new Gson().toJson(new GenerateResultVO(generateResult.get("tasks_id"), null, null, "Fail")), CommonConstant.GENERATE_RESULT_EXPIRE_TIME);
// 将异常信息存到exception中
HashMap<String, String> exceptionInfo = new HashMap<>();
@@ -212,7 +222,7 @@ public class GenerateConsumer {
log.info("============processRelightResult listening==========");
long start = System.currentTimeMillis();
Map<String, String> generateResult = JSONObject.parseObject(msg.getBody(), Map.class);
Map<String, String> generateResult = jsonBytesToMap(msg, channel);
log.info("toProductImage response : {}", generateResult);
try {
@@ -228,6 +238,7 @@ public class GenerateConsumer {
} else {
// 修改redis中的数据状态为exception
String key = relightResultKey + ":" + generateResult.get("tasks_id");
generateService.updateToProductTaskStatus(generateResult.get("tasks_id"), "Fail");
redisUtil.addToString(key, new Gson().toJson(new GenerateResultVO(generateResult.get("tasks_id"), null, null, "Fail")), CommonConstant.GENERATE_RESULT_EXPIRE_TIME);
// 将异常信息存到exception中
HashMap<String, String> exceptionInfo = new HashMap<>();
@@ -258,6 +269,296 @@ public class GenerateConsumer {
log.info("============ProcessRelightResult End listening==========");
}
public void processPoseTransformResult(Message msg, Channel channel) {
log.info("============ProcessPoseTransformResult listening==========");
long start = System.currentTimeMillis();
Map<String, String> generateResult = jsonBytesToMap(msg, channel);
log.info("PoseTransformation response : {}", generateResult);
try {
log.info("tasks_id : {} start ", generateResult.get("tasks_id"));
if (generateResult.get("status").equals("SUCCESS")) {
String gifUrl = generateResult.get("gif_url");
String taskId = generateResult.get("tasks_id");
String videoUrl = generateResult.get("video_url");
String imageUrl = generateResult.get("image_url");
generateService.processPoseTransformResult(taskId, gifUrl, videoUrl, imageUrl);
} else {
// 修改redis中的数据状态为exception
String key = generateResultKey + ":" + generateResult.get("tasks_id");
generateService.updatePoseTransferStatus(generateResult.get("tasks_id"), "Fail", null);
redisUtil.addToString(key, new Gson().toJson(new PoseTransformationVO(null, generateResult.get("tasks_id"),null, null, null, (byte)0, "Fail")), CommonConstant.GENERATE_RESULT_EXPIRE_TIME);
// 将异常信息存到exception中
HashMap<String, String> exceptionInfo = new HashMap<>();
exceptionInfo.put(generateResult.get("tasks_id"), generateResult.get("message"));
// 存redis
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
// 记录失败状态并向用户发送提示消息
generateService.processPTFailSituation(generateResult.get("tasks_id"));
}
} catch (Exception e) {
e.printStackTrace();
log.error(e.getMessage());
try {
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
// 将消息从redis排队队列中删除,需保证被消费的消息存储到db之后再从redis删除
redisUtil.removeFromZSet(consumptionOrderKey, generateResult.get("tasks_id"));
} catch (IOException exception) {
log.error("手动确认,取消返回队列,不再重新消费");
}
// 将入参和错误信息存入数据库
String exceptionMessage = JSONObject.toJSONString(generateResult) +
" Exception message " + e.getMessage();
HashMap<String, String> exceptionInfo = new HashMap<>();
exceptionInfo.put(String.valueOf(generateResult.get("tasks_id")), exceptionMessage);
// 存redis
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
// 记录失败状态并向用户发送提示消息
generateService.processPTFailSituation(generateResult.get("tasks_id"));
}
long end = System.currentTimeMillis();
log.info("tasks_id : {}, end , message : {}, 执行时长: {} 毫秒", generateResult.get("tasks_id"), generateResult.get("message"), (end - start));
log.info("============ProcessPoseTransformResult End listening==========");
}
public static Map<String, String> jsonBytesToMap(Message msg, Channel channel) {
try {
// 1. byte[] -> String
String jsonString = new String(msg.getBody(), StandardCharsets.UTF_8).trim();
// 2. 处理可能的双重转义
if (jsonString.startsWith("\"") && jsonString.endsWith("\"")) {
jsonString = jsonString.substring(1, jsonString.length() - 1);
// 使用 Apache Commons Text 将 JSON 字符串中的转义字符还原为原始字符
jsonString = StringEscapeUtils.unescapeJson(jsonString);
}
// 3. 验证 JSON 格式
if (!isValidJson(jsonString)) {
throw new IllegalArgumentException("Invalid JSON format");
}
// 4. 解析为 Map
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(jsonString, new TypeReference<Map<String, String>>() {});
} catch (Exception e) {
log.error("消息解析失败: {}", e.getMessage(), e);
try {
// 仅对不可恢复错误(如非 JSON 数据)进行 ACK
if (e instanceof JsonParseException || e instanceof IllegalArgumentException) {
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
log.warn("因消息格式错误,已确认并丢弃消息。原始消息为:{}", msg);
}
} catch (IOException ex) {
log.error("消息确认失败: {}", ex.getMessage(), ex);
}
throw new RuntimeException("Failed to parse JSON to Map", e);
}
}
// 辅助方法:验证字符串是否为合法 JSON
private static boolean isValidJson(String json) {
try {
new ObjectMapper().readTree(json);
return true;
} catch (Exception e) {
return false;
}
}
private void processDesignBatchResult(Message msg, Channel channel) {
log.info("============processDesignBatchResult listening==========");
long start = System.currentTimeMillis();
Map<String, Object> generateResult = JSONObject.parseObject(msg.getBody(), Map.class);
log.info("designBatch response : {}", generateResult);
designService.processDesignBatch(generateResult);
}
private void processToProductImageBatchResult(Message msg, Channel channel) {
log.info("============processToProductImageResultBatch listening==========");
long start = System.currentTimeMillis();
JSONObject generateResult = JSONObject.parseObject(msg.getBody(), JSONObject.class);
log.info("toProductImageBatch response : {}", generateResult);
try {
log.info("task_id : {} start ", generateResult.get("task_id"));
if (!StringUtils.isEmpty(generateResult.getString("progress"))) {
String progress = generateResult.getString("progress");
String url = null;
if (!progress.startsWith("0") && !progress.equals("OK")) {
JSONObject result = generateResult.getJSONObject("result");
if (Objects.nonNull(result)) {
url = result.getString("product_img");
String taskId = generateResult.getString("task_id");
userLikeGroupService.toProductBatch(taskId, url, progress);
}
} else if (progress.startsWith("0/")) {
String batchTaskId = generateResult.getString("task_id");
if (!StringUtils.isEmpty(batchTaskId)) {
cloudTaskService.startTask(batchTaskId);
}
} else if (progress.equals("OK")) {
String batchTaskId = generateResult.getString("task_id");
if (!StringUtils.isEmpty(batchTaskId)) {
cloudTaskService.completeTask(batchTaskId);
}
}
} else {
// 修改redis中的数据状态为exception
String key = toProductImageResultKey + ":" + generateResult.get("task_id");
generateService.updateToProductTaskStatus(generateResult.getString("task_id"), "Fail");
redisUtil.addToString(key, new Gson().toJson(new GenerateResultVO(generateResult.getString("tasks_id"), null, null, "Fail")), CommonConstant.GENERATE_RESULT_EXPIRE_TIME);
// 将异常信息存到exception中
HashMap<String, String> exceptionInfo = new HashMap<>();
exceptionInfo.put(generateResult.getString("task_id"), generateResult.getString("data"));
// 存redis
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
}
} catch (Exception e) {
log.error(e.getMessage());
try {
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
// 将消息从redis排队队列中删除,需保证被消费的消息存储到db之后再从redis删除
redisUtil.removeFromZSet(consumptionOrderKey, generateResult.getString("task_id"));
} catch (IOException exception) {
log.error("手动确认,取消返回队列,不再重新消费");
}
// 将入参和错误信息存入数据库
String exceptionMessage = JSONObject.toJSONString(generateResult) +
" Exception message " + e.getMessage();
HashMap<String, String> exceptionInfo = new HashMap<>();
exceptionInfo.put(String.valueOf(generateResult.get("task_id")), exceptionMessage);
// 存redis
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
}
long end = System.currentTimeMillis();
log.info("task_id : {}, end , message : {}, 执行时长: {} 毫秒", generateResult.get("task_id"), generateResult.get("message"), (end - start));
log.info("============ProcessToProductImageBatchResult End listening==========");
}
private void processRelightBatchResult(Message msg, Channel channel) {
log.info("============processRelightResult listening==========");
long start = System.currentTimeMillis();
JSONObject generateResult = JSONObject.parseObject(msg.getBody(), JSONObject.class);
log.info("relightBatch response : {}", generateResult);
try {
log.info("task_id : {} start ", generateResult.get("task_id"));
if (!StringUtils.isEmpty(generateResult.getString("progress"))) {
String progress = generateResult.getString("progress");
String url = null;
if (!progress.startsWith("0") && !progress.equals("OK")) {
JSONObject result = generateResult.getJSONObject("result");
if (Objects.nonNull(result)) {
url = result.getString("relight_img");
String taskId = generateResult.getString("task_id");
userLikeGroupService.relightBatch(taskId, url, progress);
}
} else if (progress.startsWith("0/")) {
String batchTaskId = generateResult.getString("task_id");
if (!StringUtils.isEmpty(batchTaskId)) {
cloudTaskService.startTask(batchTaskId);
}
} else if (progress.equals("OK")) {
String batchTaskId = generateResult.getString("task_id");
if (!StringUtils.isEmpty(batchTaskId)) {
cloudTaskService.completeTask(batchTaskId);
}
}
} else {
// 修改redis中的数据状态为exception
String key = relightResultKey + ":" + generateResult.get("task_id");
generateService.updateToProductTaskStatus(generateResult.getString("task_id"), "Fail");
redisUtil.addToString(key, new Gson().toJson(new GenerateResultVO(generateResult.getString("tasks_id"), null, null, "Fail")), CommonConstant.GENERATE_RESULT_EXPIRE_TIME);
// 将异常信息存到exception中
HashMap<String, String> exceptionInfo = new HashMap<>();
exceptionInfo.put(generateResult.getString("task_id"), generateResult.getString("data"));
// 存redis
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
}
} catch (Exception e) {
log.error(e.getMessage());
try {
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
// 将消息从redis排队队列中删除,需保证被消费的消息存储到db之后再从redis删除
redisUtil.removeFromZSet(consumptionOrderKey, generateResult.getString("task_id"));
} catch (IOException exception) {
log.error("手动确认,取消返回队列,不再重新消费");
}
// 将入参和错误信息存入数据库
String exceptionMessage = JSONObject.toJSONString(generateResult) +
" Exception message " + e.getMessage();
HashMap<String, String> exceptionInfo = new HashMap<>();
exceptionInfo.put(String.valueOf(generateResult.get("task_id")), exceptionMessage);
// 存redis
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
}
long end = System.currentTimeMillis();
log.info("task_id : {}, end , message : {}, 执行时长: {} 毫秒", generateResult.get("task_id"), generateResult.get("message"), (end - start));
log.info("============ProcessRelightBatchResult End listening==========");
}
private void processPoseTransformBatchResult(Message msg, Channel channel) {
log.info("============ProcessPoseTransformBatchResult listening==========");
long start = System.currentTimeMillis();
JSONObject generateResult = JSONObject.parseObject(msg.getBody(), JSONObject.class);
log.info("PoseTransformationBatch response : {}", generateResult);
try {
log.info("task_id : {} start ", generateResult.get("task_id"));
if (!StringUtils.isEmpty(generateResult.getString("progress"))) {
String progress = generateResult.getString("progress");
String taskId = generateResult.getString("task_id");
generateService.processPoseTransformResultBatch(progress, taskId);
JSONArray result = generateResult.getJSONArray("result");
if (!StringUtils.isEmpty(result)) {
JSONObject jsonObject = result.getJSONObject(0);
String gifUrl = jsonObject.getString("gif_url");
String videoUrl = jsonObject.getString("video_url");
String imageUrl = jsonObject.getString("first_image_url");
generateService.processPoseTransformResultBatch(taskId, gifUrl, videoUrl, imageUrl, progress);
}
} else {
// 修改redis中的数据状态为exception
String key = generateResultKey + ":" + generateResult.getString("task_id");
generateService.updatePoseTransferStatus(generateResult.getString("task_id"), "Fail", null);
redisUtil.addToString(key, new Gson().toJson(new PoseTransformationVO(null, generateResult.getString("task_id"),null, null, null, (byte)0, "Fail")), CommonConstant.GENERATE_RESULT_EXPIRE_TIME);
// 将异常信息存到exception中
HashMap<String, String> exceptionInfo = new HashMap<>();
exceptionInfo.put(generateResult.getString("task_id"), generateResult.getString("message"));
// 存redis
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
}
} catch (Exception e) {
log.error(e.getMessage());
try {
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
// 将消息从redis排队队列中删除,需保证被消费的消息存储到db之后再从redis删除
redisUtil.removeFromZSet(consumptionOrderKey, generateResult.getString("task_id"));
} catch (IOException exception) {
log.error("手动确认,取消返回队列,不再重新消费");
}
// 将入参和错误信息存入数据库
String exceptionMessage = JSONObject.toJSONString(generateResult) +
" Exception message " + e.getMessage();
HashMap<String, String> exceptionInfo = new HashMap<>();
exceptionInfo.put(generateResult.getString("task_id"), exceptionMessage);
// 存redis
redisUtil.addToMap(exceptionMapKey, exceptionInfo);
}
long end = System.currentTimeMillis();
log.info("tasks_id : {}, end , message : {}, 执行时长: {} 毫秒", generateResult.get("tasks_id"), generateResult.get("message"), (end - start));
log.info("============ProcessPoseTransformResult End listening==========");
}
@RabbitListener(queues = "#{rabbitMQProperties.queues.generate}")
@RabbitHandler
public void generateConsumer1(Message msg, Channel channel) {
@@ -329,4 +630,32 @@ public class GenerateConsumer {
public void getRelightResult(Message msg, Channel channel) {
processRelightResult(msg, channel);
}
@RabbitListener(queues = "#{rabbitMQProperties.queues.poseTransform}")
@RabbitHandler
public void getPoseTransformationResult(Message msg, Channel channel) {
processPoseTransformResult(msg, channel);
}
// @RabbitListener(queues = "#{rabbitMQProperties.queues.designBatch}")
// @RabbitHandler
// public void getDesignBatchResult(Message msg, Channel channel) {
// processDesignBatchResult(msg, channel);
// }
// @RabbitListener(queues = "#{rabbitMQProperties.queues.toProductImageBatch}")
// @RabbitHandler
// public void getToProductImageBatchResult(Message msg, Channel channel) {
// processToProductImageBatchResult(msg, channel);
// }
//
// @RabbitListener(queues = "#{rabbitMQProperties.queues.relightBatch}")
// @RabbitHandler
// public void getRelightBatchResult(Message msg, Channel channel) {
// processRelightBatchResult(msg, channel);
// }
//
// @RabbitListener(queues = "#{rabbitMQProperties.queues.poseTransformBatch}")
// @RabbitHandler
// public void getPoseTransformBatchResult(Message msg, Channel channel) {
// processPoseTransformBatchResult(msg, channel);
// }
}

View File

@@ -1,43 +1,82 @@
package com.ai.da.common.RabbitMQ;
import org.springframework.amqp.core.Queue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MQConfig {
@Autowired
private RabbitMQProperties rabbitMQProperties;
@Bean
public Queue generateQueue() {
return new Queue(rabbitMQProperties.getQueues().getGenerate());
}
@Bean
public Queue SRQueue() {
return new Queue(rabbitMQProperties.getQueues().getSr());
}
@Bean
public Queue SRResultQueue() {
return new Queue(rabbitMQProperties.getQueues().getSrResult());
}
@Bean
public Queue generateResultQueue() {
return new Queue(rabbitMQProperties.getQueues().getGenerateResult());
}
@Bean
public Queue toProductImageResultQueue() {
return new Queue(rabbitMQProperties.getQueues().getToProductImageResult());
}
@Bean
public Queue relightResultQueue() {
return new Queue(rabbitMQProperties.getQueues().getRelightResult());
}
}
package com.ai.da.common.RabbitMQ;
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MQConfig {
@Autowired
private RabbitMQProperties rabbitMQProperties;
@Bean
public Queue generateQueue() {
return new Queue(rabbitMQProperties.getQueues().getGenerate());
}
@Bean
public Queue SRQueue() {
return new Queue(rabbitMQProperties.getQueues().getSr());
}
@Bean
public Queue SRResultQueue() {
return new Queue(rabbitMQProperties.getQueues().getSrResult());
}
@Bean
public Queue generateResultQueue() {
return new Queue(rabbitMQProperties.getQueues().getGenerateResult());
}
@Bean
public Queue toProductImageResultQueue() {
return new Queue(rabbitMQProperties.getQueues().getToProductImageResult());
}
@Bean
public Queue relightResultQueue() {
return new Queue(rabbitMQProperties.getQueues().getRelightResult());
}
@Bean
public Queue poseTransformQueue() {
return new Queue(rabbitMQProperties.getQueues().getPoseTransform());
}
@Bean
public Queue mailRetryQueue() {
// 普通队列不绑定DLX首次失败后才进入MQ
// durable 持久化队列
return QueueBuilder.durable(rabbitMQProperties.getQueues().getEmailRetry())
// 关键参数:绑定死信交换机
.withArgument("x-dead-letter-exchange", rabbitMQProperties.getDeadLetter().getExchange())
// 可选:指定死信路由键(默认使用原消息的路由键)
.withArgument("x-dead-letter-routing-key", rabbitMQProperties.getDeadLetter().getRoutingKey())
.build();
}
// 新增死信交换机
@Bean
public DirectExchange deadLetterExchange() {
return new DirectExchange(rabbitMQProperties.getDeadLetter().getExchange());
}
// 新增死信队列
@Bean
public Queue deadLetterQueue() {
return QueueBuilder.durable(rabbitMQProperties.getDeadLetter().getQueue()).build();
}
// 绑定死信队列
@Bean
public Binding deadLetterBinding() {
return BindingBuilder.bind(deadLetterQueue())
.to(deadLetterExchange())
.with(rabbitMQProperties.getDeadLetter().getRoutingKey());
}
}

View File

@@ -1,29 +1,61 @@
package com.ai.da.common.RabbitMQ;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Slf4j
@Component
public class MQPublisher {
@Autowired
private RabbitMQProperties rabbitMQProperties;
@Autowired
private AmqpTemplate amqpTemplate;
public void sendGenerateMessage(String mm) {
log.info("send message: " + mm);
amqpTemplate.convertAndSend(rabbitMQProperties.getQueues().getGenerate(), mm);
}
public void sendSRMessage(String mm) {
log.info("send message: " + mm);
amqpTemplate.convertAndSend(rabbitMQProperties.getQueues().getSr(), mm);
}
}
package com.ai.da.common.RabbitMQ;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import jakarta.annotation.Resource;
import java.util.Map;
@Slf4j
@Component
public class MQPublisher {
@Autowired
private RabbitMQProperties rabbitMQProperties;
@Autowired
private AmqpTemplate amqpTemplate;
public void sendGenerateMessage(String mm) {
log.info("send generate message: {}", mm);
amqpTemplate.convertAndSend(rabbitMQProperties.getQueues().getGenerate(), mm);
}
public void sendSRMessage(String mm) {
log.info("send message: {}", mm);
amqpTemplate.convertAndSend(rabbitMQProperties.getQueues().getSr(), mm);
}
public void sendGenerateResultMessage(String mm) {
log.info("send generate result message: {}", mm);
amqpTemplate.convertAndSend(rabbitMQProperties.getQueues().getGenerateResult(), mm);
}
/**
*
* @param mailParams 含有的字段
* {"dto": basicEmailParamDTO, "filename": fileName, "source": inputStreamSource,
* "templateParams": jsonObject, "templatePath": path}
* 邮件发送参数,附件文件名,附件数据
* @param retryTimes 重试次数初始为0
*/
public void sendEmailMsg(Map<String, String> mailParams, int retryTimes){
log.info("send email MQ message: {} ", mailParams);
// // 重新入队(指数退避) 时间单位:毫秒
long newDelay = (long) (5000 * Math.pow(2, retryTimes + 1));
log.info("send email MQ delay: {} ms, retry attempt: {}", newDelay, retryTimes + 1);
amqpTemplate.convertAndSend(
rabbitMQProperties.getQueues().getEmailRetry(),
mailParams,
m -> {
m.getMessageProperties().setExpiration(String.valueOf(newDelay));
m.getMessageProperties().setHeader("x-retry-attempt", retryTimes + 1);
return m;
}
);
}
}

View File

@@ -1,30 +1,45 @@
package com.ai.da.common.RabbitMQ;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "rabbitmq")
@Data
public class RabbitMQProperties {
private Queues queues;
private Exchange exchange;
@Data
public static class Queues {
private String generate;
private String sr;
private String srResult;
private String generateResult;
private String toProductImageResult;
private String relightResult;
}
@Data
public static class Exchange {
private String generate;
}
}
package com.ai.da.common.RabbitMQ;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "rabbitmq")
@Data
public class RabbitMQProperties {
private Queues queues;
private Exchange exchange;
private DeadLetter deadLetter; // 新增死信配置
@Data
public static class Queues {
private String generate;
private String sr;
private String srResult;
private String generateResult;
private String toProductImageResult;
private String relightResult;
private String poseTransform;
private String emailRetry;
private String designBatch;
private String relightBatch;
private String toProductImageBatch;
private String poseTransformBatch;
}
@Data
public static class Exchange {
private String generate;
}
// 新增死信配置内部类
@Data
public static class DeadLetter {
private String exchange;
private String queue;
private String routingKey;
}
}

View File

@@ -19,7 +19,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import jakarta.annotation.Resource;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.HashMap;
@@ -208,7 +208,7 @@ public class SRConsumer {
redisUtil.removeFromZSet(consumptionOrderKey, uniqueId);
} catch (Exception exception) {
log.error("手动确认,取消返回队列,不再重新消费");
throw new BusinessException("发生错误,手动确认消息");
throw new BusinessException("message.confirm.fail");
}
// 将入参和错误信息存入redis
String exceptionMessage = JSONObject.toJSONString(superResolutionDTO) +

View File

@@ -0,0 +1,170 @@
package com.ai.da.common.aspect;
import com.ai.da.common.context.UserContext;
import com.ai.da.model.vo.AuthPrincipalVo;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import java.util.HashMap;
import java.util.Map;
/**
* Controller日志切面
* 记录所有Controller接口的请求参数和用户信息
*/
@Aspect
@Component
public class ControllerLoggingAspect {
private static final Logger logger = LoggerFactory.getLogger(ControllerLoggingAspect.class);
/**
* 定义切点所有Controller方法
*/
@Pointcut("execution(* com.ai.da.controller..*(..))")
public void controllerMethods() {
}
/**
* Controller方法执行前记录日志
*/
// @Before("controllerMethods()")
public void logControllerBefore(JoinPoint joinPoint) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
// 获取当前用户ID
Long userId = null;
AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder();
if (authPrincipalVo != null) {
userId = authPrincipalVo.getId();
}
// 获取请求参数
Map<String, Object> params = getRequestParams(joinPoint, request);
logger.info("=== 请求开始 ===");
logger.info("用户ID: {}", userId);
logger.info("请求URL: {}", request.getRequestURL().toString());
logger.info("请求方法: {}", request.getMethod());
logger.info("请求IP: {}", getClientIpAddress(request));
logger.info("调用方法: {}.{}", joinPoint.getSignature().getDeclaringType().getSimpleName(), joinPoint.getSignature().getName());
logger.info("请求参数: {}", params);
}
}
/**
* 获取请求参数
*/
private Map<String, Object> getRequestParams(JoinPoint joinPoint, HttpServletRequest request) {
Map<String, Object> params = new HashMap<>();
// 1. 获取Query String参数
String queryString = request.getQueryString();
if (queryString != null && !queryString.isEmpty()) {
params.put("queryString", queryString);
}
// 2. 获取方法参数(包含 @PathVariable, @RequestParam, @RequestBody 等)
Object[] args = joinPoint.getArgs();
if (args != null && args.length > 0) {
Map<String, Object> methodParams = new HashMap<>();
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
// 过滤掉不可序列化的参数
if (arg != null) {
if (isIgnorable(arg)) {
// 对于可忽略的类型,记录类型名
methodParams.put("arg" + i, "[" + arg.getClass().getSimpleName() + "]");
} else {
try {
methodParams.put("arg" + i, arg);
} catch (Exception e) {
methodParams.put("arg" + i, arg.toString());
}
}
}
}
if (!methodParams.isEmpty()) {
params.put("methodParams", methodParams);
}
}
return params;
}
/**
* 判断是否需要过滤的参数类型
*/
private boolean isIgnorable(Object obj) {
return obj instanceof HttpServletRequest
|| obj instanceof HttpServletResponse
|| obj instanceof MultipartFile
|| obj instanceof MultipartFile[];
}
/**
* Controller方法抛出异常时记录日志
*/
@AfterThrowing(pointcut = "controllerMethods()", throwing = "exception")
public void logControllerAfterThrowing(JoinPoint joinPoint, Throwable exception) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
Long userId = null;
AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder();
if (authPrincipalVo != null) {
userId = authPrincipalVo.getId();
}
// 获取请求参数
Map<String, Object> params = new HashMap<>();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
params = getRequestParams(joinPoint, request);
}
logger.error("=== 请求异常 ===");
logger.error("用户ID: {}", userId);
logger.error("调用方法: {}.{}", joinPoint.getSignature().getDeclaringType().getSimpleName(), joinPoint.getSignature().getName());
logger.error("请求参数: {}", params);
logger.error("异常信息: ", exception);
logger.error("=== 异常结束 ===");
}
/**
* 获取客户端真实IP地址
*/
private String getClientIpAddress(HttpServletRequest request) {
String xForwardedFor = request.getHeader("X-Forwarded-For");
if (xForwardedFor != null && !xForwardedFor.isEmpty() && !"unknown".equalsIgnoreCase(xForwardedFor)) {
return xForwardedFor.split(",")[0];
}
String xRealIp = request.getHeader("X-Real-IP");
if (xRealIp != null && !xRealIp.isEmpty() && !"unknown".equalsIgnoreCase(xRealIp)) {
return xRealIp;
}
String proxyClientIp = request.getHeader("Proxy-Client-IP");
if (proxyClientIp != null && !proxyClientIp.isEmpty() && !"unknown".equalsIgnoreCase(proxyClientIp)) {
return proxyClientIp;
}
String wlProxyClientIp = request.getHeader("WL-Proxy-Client-IP");
if (wlProxyClientIp != null && !wlProxyClientIp.isEmpty() && !"unknown".equalsIgnoreCase(wlProxyClientIp)) {
return wlProxyClientIp;
}
return request.getRemoteAddr();
}
}

View File

@@ -6,7 +6,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import javax.annotation.Resource;
import jakarta.annotation.Resource;
@Configuration
//加载配置文件

View File

@@ -0,0 +1,21 @@
package com.ai.da.common.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
@Configuration
public class AsyncConfig {
@Bean("asyncTaskExecutor")
public Executor asyncTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("Async-ImageToSketch-");
executor.initialize();
return executor;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,260 @@
package com.ai.da.common.config;
import com.ai.da.common.utils.MinioUtil;
import com.ai.da.mapper.primary.ThreeDDetailMapper;
import com.ai.da.mapper.primary.ThreeDLayoutMapper;
import com.ai.da.mapper.primary.ThreeDPatternLayoutMapper;
import com.ai.da.mapper.primary.ThreeDSimpleMapper;
import com.ai.da.mapper.primary.entity.ThreeDDetail;
import com.ai.da.mapper.primary.entity.ThreeDLayout;
import com.ai.da.mapper.primary.entity.ThreeDPatternLayout;
import com.ai.da.mapper.primary.entity.ThreeDSimple;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@Slf4j
@Component
public class ThreeDSave {
@Resource
private ThreeDDetailMapper threeDDetailMapper;
@Resource
private ThreeDSimpleMapper threeDSimpleMapper;
@Resource
private MinioUtil minioUtil;
@Resource
private ThreeDLayoutMapper threeDLayoutMapper;
@Resource
private ThreeDPatternLayoutMapper threeDPatternLayoutMapper;
@PostConstruct
public void test() {
// minioSave();
// frontBackDataCreate();
// patternDataCreate();
}
private void patternDataCreate() {
QueryWrapper<ThreeDSimple> qw = new QueryWrapper<>();
qw.lambda().eq(ThreeDSimple::getGender, "female");
qw.lambda().ne(ThreeDSimple::getId, 1);
List<ThreeDSimple> threeDSimpleList = threeDSimpleMapper.selectList(qw);
List<Integer> numbers = new ArrayList<>();
String patternPath = "C:\\workspace\\3D\\3D虚拟 1-7\\6.版文件、dxf文件\\女装系列(1)\\女装系列\\56款打版截图";
File directory = new File(patternPath);
if (directory.exists() && directory.isDirectory()) {
// 获取目录下的所有文件名,并建立编号 -> 文件名的映射
Map<Integer, String> fileMap = Arrays.stream(directory.listFiles())
.filter(File::isFile) // 只获取文件
.map(File::getName) // 获取文件名
.collect(Collectors.toMap(
name -> {
Matcher matcher = Pattern.compile("^\\d+").matcher(name);
return matcher.find() ? Integer.parseInt(matcher.group()) : -1;
},
name -> name,
(existing, replacement) -> existing // 处理重复情况,保留原有值
));
for (ThreeDSimple threeDSimple : threeDSimpleList) {
String name = threeDSimple.getName();
Pattern pattern = Pattern.compile("^\\d+"); // 匹配开头的数字
Matcher matcher = pattern.matcher(name);
if (matcher.find()) {
int number = Integer.parseInt(matcher.group());
numbers.add(number);
// 匹配对应文件夹,并获取文件
if (fileMap.containsKey(number)) {
String matchedFolder = fileMap.get(number);
File folder = new File(directory, matchedFolder);
ThreeDPatternLayout threeDPatternLayout = new ThreeDPatternLayout();
threeDPatternLayout.setThreeDSimpleId(threeDSimple.getId());
threeDPatternLayout.setName(matchedFolder);
String minioUrl = "aida-threed/female/pattern-layout/" + matchedFolder;
minioUtil.upload(minioUrl, folder);
threeDPatternLayout.setUrl(minioUrl);
// threeDPatternLayoutMapper.insert(threeDPatternLayout);
}
}
}
System.out.println("文件编号映射:" + fileMap);
}
}
private void frontBackDataCreate() {
QueryWrapper<ThreeDSimple> qw = new QueryWrapper<>();
qw.lambda().eq(ThreeDSimple::getGender, "female");
// qw.lambda().ne(ThreeDSimple::getId, 1);
List<ThreeDSimple> threeDSimpleList = threeDSimpleMapper.selectList(qw);
List<Integer> numbers = new ArrayList<>();
// 文件夹名列表
String path = "C:\\workspace\\3D\\3D虚拟 1-7\\3D服装真反面整理\\female"; // 目标路径
File directory = new File(path);
if (directory.exists() && directory.isDirectory()) {
// 获取文件夹名列表,并建立编号 -> 文件夹名的映射
Map<Integer, String> folderMap = Arrays.stream(directory.listFiles())
.filter(File::isDirectory)
.map(File::getName)
.collect(Collectors.toMap(
name -> {
Matcher matcher = Pattern.compile("^\\d+").matcher(name);
return matcher.find() ? Integer.parseInt(matcher.group()) : -1;
},
name -> name,
(existing, replacement) -> existing // 处理重复情况,保留原有值
));
System.out.println("文件夹编号映射:" + folderMap);
for (ThreeDSimple threeDSimple : threeDSimpleList) {
String name = threeDSimple.getName();
Pattern pattern = Pattern.compile("^\\d+"); // 匹配开头的数字
Matcher matcher = pattern.matcher(name);
if (matcher.find()) {
int number = Integer.parseInt(matcher.group());
numbers.add(number);
// 匹配对应文件夹,并获取文件
if (folderMap.containsKey(number)) {
String matchedFolder = folderMap.get(number);
File folder = new File(directory, matchedFolder);
if (folder.exists() && folder.isDirectory()) {
for (File file : folder.listFiles()) {
String fileName = file.getName(); // 去掉后缀
ThreeDLayout threeDLayout = new ThreeDLayout();
threeDLayout.setGender("female");
threeDLayout.setThreeDSimpleId(threeDSimple.getId());
threeDLayout.setName(file.getName());
if (fileName.startsWith("")) {
threeDLayout.setType("front");
}else if (fileName.startsWith("")) {
threeDLayout.setType("back");
}
String minioUrl = "aida-threed/female/layout/" + folderMap.get(number) + " " + file.getName();
minioUtil.upload(minioUrl, file);
threeDLayout.setUrl(minioUrl);
// threeDLayoutMapper.insert(threeDLayout);
}
}
}
}
}
System.out.println(numbers);
} else {
System.out.println("路径不存在或不是文件夹");
}
}
private void minioSave() {
// 指定目标文件夹路径
String folderPath = "C:\\workspace\\3D\\3D虚拟 1-7\\3D服装整理\\maleZip";
// 创建文件对象
File folder = new File(folderPath);
// 检查文件夹是否存在且是目录
if (folder.exists() && folder.isDirectory()) {
// 获取所有 .zip 文件
File[] zipFiles = folder.listFiles((dir, name) -> name.toLowerCase().endsWith(".zip"));
List<String> zipFileNameList = new ArrayList<>();
// 输出文件名
if (zipFiles != null) {
for (File file : zipFiles) {
String zipFileName = file.getName();
String[] split = zipFileName.split("_");
String zipName = split[0];
String sizeWithSuffix = split[1];
String[] sizeWithSuffixSplit = sizeWithSuffix.split("\\.");
String size = sizeWithSuffixSplit[0];
// 找到第一个字母的位置
int index = 0;
while (index < size.length() && Character.UnicodeBlock.of(size.charAt(index)) == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS) {
index++;
}
if (index > 0 && index < size.length()) {
String prefix = size.substring(0, index); // "亚码"
String suffix = size.substring(index); // "L"
ThreeDDetail threeDDetail = new ThreeDDetail();
threeDDetail.setName(zipFileName);
String url = "aida-threed/male/zip/" + zipFileName;
threeDDetail.setGender("male");
threeDDetail.setSizeType(prefix);
threeDDetail.setSize(suffix);
threeDDetail.setUrl(url);
// threeDDetailMapper.insert(threeDDetail);
minioUtil.upload(url, file);
QueryWrapper<ThreeDSimple> qw = new QueryWrapper<>();
qw.lambda().eq(ThreeDSimple::getName, zipName);
qw.lambda().eq(ThreeDSimple::getGender, "male");
List<ThreeDSimple> threeDSimples = threeDSimpleMapper.selectList(qw);
if (CollectionUtils.isEmpty(threeDSimples)) {
ThreeDSimple threeDSimple = new ThreeDSimple();
threeDSimple.setName(zipName);
threeDSimple.setGender("male");
String glbPath = "C:\\workspace\\3D\\3D虚拟 1-7\\3D服装整理\\male\\" + zipName + "\\" +"亚码L";
File glbFolder = new File(glbPath);
// 查找 .glb 文件
if (glbFolder.exists() && glbFolder.isDirectory()) {
File[] glbFiles = glbFolder.listFiles((dir, name) -> name.toLowerCase().endsWith(".glb"));
if (glbFiles != null && glbFiles.length > 0) {
for (File glbFile : glbFiles) {
String name = glbFile.getName();
String glbUrl = "aida-threed/male/glb/" + name;
threeDSimple.setUrl(glbUrl);
minioUtil.upload(glbUrl, glbFile);
}
} else {
System.out.println("未找到 GLB 文件。" + glbFolder);
}
} else {
System.out.println("GLB 文件夹不存在: " + glbPath);
}
// threeDSimpleMapper.insert(threeDSimple);
threeDDetail.setThreeDSimpleId(threeDSimple.getId());
threeDDetailMapper.updateById(threeDDetail);
}else {
Long id = threeDSimples.get(0).getId();
threeDDetail.setThreeDSimpleId(id);
threeDDetailMapper.updateById(threeDDetail);
}
} else {
}
}
} else {
System.out.println("未找到 ZIP 文件。");
}
log.info("aaa");
} else {
System.out.println("文件夹不存在或不是一个目录。");
}
}
}

View File

@@ -1,42 +1,42 @@
package com.ai.da.common.config;
import org.hibernate.validator.HibernateValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
static final String ORIGINS[] = new String[]{"GET", "POST", "PUT", "DELETE"};
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*").allowCredentials(true).allowedMethods(ORIGINS).maxAge(3600);
}
@Bean
public Validator validator() {
ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
.configure()
//failFast为true出现校验失败的情况立即结束校验不再进行后续的校验
.failFast(true)
.buildValidatorFactory();
return validatorFactory.getValidator();
}
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();
methodValidationPostProcessor.setValidator(validator());
return methodValidationPostProcessor;
}
}
package com.ai.da.common.config;
import org.hibernate.validator.HibernateValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;
@Configuration
public class WebConfig implements WebMvcConfigurer {
static final String ORIGINS[] = new String[]{"GET", "POST", "PUT", "DELETE"};
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOriginPatterns("*").allowCredentials(true).allowedMethods(ORIGINS).maxAge(3600);
}
@Bean
public Validator validator() {
ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
.configure()
//failFast为true出现校验失败的情况立即结束校验不再进行后续的校验
.failFast(true)
.buildValidatorFactory();
return validatorFactory.getValidator();
}
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();
methodValidationPostProcessor.setValidator(validator());
return methodValidationPostProcessor;
}
}

View File

@@ -5,6 +5,7 @@ import com.ai.da.common.response.ResultEnum;
import com.ai.da.model.enums.Language;
import com.ai.da.model.vo.AuthPrincipalVo;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -20,6 +21,7 @@ import java.util.ResourceBundle;
* @create: 2020-01-01 17:24
**/
@Data
@Slf4j
public class BusinessException extends RuntimeException {
private Integer code;

View File

@@ -1,37 +0,0 @@
package com.ai.da.common.config.swagger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
@Configuration
@EnableSwagger2WebMvc
public class AidaConfiguration {
@Bean(value = "IntelligentCurtainApis")
public Docket gxyd5aThemeApis() {
Contact contact = new Contact("Mr.Y", "", "136");
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.apiInfo(new ApiInfoBuilder()
.description("aida接口文档")
.contact(contact)
.termsOfServiceUrl("暂无")
.version("1.0")
.build())
//分组名称
.groupName("1.0")
.select()
//这里指定Controller扫描包路径
.apis(RequestHandlerSelectors.basePackage("com.ai.da.controller"))
.paths(PathSelectors.any())
.build();
return docket;
}
}

View File

@@ -0,0 +1,9 @@
package com.ai.da.common.constant;
public class AffiliateConstants {
public static final String STATUS_ACTIVE = "Active";
public static final String STATUS_INACTIVE = "Inactive";
public static final String STATUS_DELETE = "Delete";
public static final Integer DELETED = 1;
public static final Integer NOT_DELETED = 0;
}

View File

@@ -23,6 +23,7 @@ public class CommonConstant {
}
public static final String GENERATE_PATH = "/api/generate_image";
public static final String GENERATE_PATH_FLUX2_KLEIN = "/api/generate_image_flux2_klein";
public static final String GENERATE_SINGLE_LOGO = "/api/generate_single_logo";
@@ -32,6 +33,9 @@ public class CommonConstant {
public static final String GENERATE_LOGO_SINGLE_CANCEL = "/api/generate_single_logo_cancel/";
// public static final String POSE_TRANSFORMATION_CANCEL = "/api/pose_transform_cancel/";
public static final String POSE_TRANSFORMATION_CANCEL = "/api/comfyui_i_2_video_cancel/";
public static final String PYTHON_PORT_9996 = "9996";
public static final String PYTHON_PORT_9997 = "9997";
@@ -84,4 +88,11 @@ public class CommonConstant {
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=";
public static final String PARTIAL_DESIGN_FILENAME = "PartialDesign";
public static final String PARTIAL_DESIGN_PREVIEW_FILENAME = "Preview";
public static final String senderEmail = "info@aida.com.hk";
}

View File

@@ -0,0 +1,42 @@
package com.ai.da.common.constant;
/**
* 模型相关常量类
* 用于存放 chooseModelAndPrompt 方法中的字符串常量
*/
public class ModelConstants {
// 类型常量
public static final String PRINTBOARD = "Printboard";
public static final String MOODBOARD = "Moodboard";
public static final String SKETCHBOARD = "Sketchboard";
// 模型级别常量
public static final String ADVANCED = "advanced";
public static final String HIGH = "high";
public static final String NORMAL = "normal";
// 模型名称常量
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 PRINTBOARD_HIGH_T2I = "doubao-seedream-3-0-t2i-250415";
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 IMAGEN_MODEL = "imagen-4.0-generate-001";
public static final String NANO_BANANA = "gemini-2.5-flash-image";
public static final String LOCAL_MODEL = "local";
// 风格常量
public static final String PAINTING_STYLE = "Painting Style";
public static final String ILLUSTRATION_STYLE = "Illustration Style";
public static final String REAL_STYLE = "Real Style";
// 映射键
public static final String PROMPT = "prompt";
public static final String USE_MODEL = "UseModel";
// 防止实例化
private ModelConstants() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
}

View File

@@ -33,7 +33,11 @@ public enum AuthenticationOperationTypeEnum {
*/
UPDATE_USERINFO,
REGISTER;
REGISTER,
/**
* Global_Award 活动验证
*/
GLOBAL_AWARD;
public static AuthenticationOperationTypeEnum of(String name) {
return Stream.of(AuthenticationOperationTypeEnum.values()).filter(v -> v.name().equals(name)).findFirst().orElse(null);

View File

@@ -27,7 +27,9 @@ public enum CollectionLevel1TypeEnum {
/**
* 市场
*/
MARKETING_SKETCH("MarketingSketch");
MARKETING_SKETCH("MarketingSketch"),
MODEL("Models");
private String realName;

View File

@@ -68,4 +68,7 @@ public enum CollectionLevel2TypeEnum {
public static List<String> printType() {
return Arrays.asList(LOGO.getRealName(), SLOGAN.getRealName(), Pattern.getRealName());
}
public static CollectionLevel2TypeEnum ofWithLoweCase(String realName) {
return Stream.of(CollectionLevel2TypeEnum.values()).filter(v -> v.getRealName().toLowerCase().equals(realName)).findFirst().orElse(null);
}
}

View File

@@ -3,23 +3,32 @@ package com.ai.da.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
@AllArgsConstructor
@Getter
public enum CreditsEventsEnum {
PRICE("price","6"),
PRICE("price","10"),
// PRICE("price","1"),// for test
// PRICE("price","0.1"),
BUY_CREDITS("Buy Credits","60"),
BUY_CREDITS("Buy Credits","50"),
// BUY_CREDITS("Buy Credits","10"),// for test
REFUND("Refund","60"),
REFUND("Refund","50"),
// BUY_CREDITS("Buy Credits","10"),
// 每月更新
INIT_YEARLY("init_yearly", "6000"),
INIT_MONTHLY("init_monthly", "5000"),
INIT_YEARLY("init_yearly", "50000"),
INIT_MONTHLY("init_monthly", "3500"),
INIT_MONTHLY_ECO("init_monthly_eco", "500"),
INIT_QUARTERLY("init_quarterly", "12000"),
INIT_MONTHLY_EDU("init_monthly_edu", "3500"),
INIT_TRIAL("init_trial", "100"),
INIT_WEEKLY("init_weekly","6000"),
RESET_YEAR_CREDITS("reset_year_credits","6000"),
@@ -32,16 +41,51 @@ public enum CreditsEventsEnum {
MOOD_BOARD("MoodBoard","5"),
SKETCH_BOARD("SketchBoard","5"),
TO_PRODUCT_IMAGE("ToProductImage","5"),
TO_PRODUCT_IMAGE_ADVANCED("ToProductImageAdvanced","15"),
RELIGHT("Relight","5"),
RELIGHT_FLUX("RelightFlux","10"),
QUESTIONNAIRE("Questionnaire","100"),
IMAGE_TO_SKETCH("ImageToSketch","5"),
IMAGE_TO_SKETCH_FLUX("ImageToSketchFlux","10"),
POSE_TRANSFORMATION("PoseTransformation","10"),
OTHER("Other","5"),
OTHER("Other","5");
SCETCH_TEXT2IMG("SketchText2Image","10"),
SCETCH_IMG2IMG("SketchImg2Image","15"),
WX_TEXT2IMG("WX_Text2Image", "5"),
QWEN_TEXT2IMG("QWEN_Text2Image", "10"),
DOUBAO_TEXT2IMG("Doubao_Text2Image", "10"),
DOUBAO_IMG2IMG_ADVANCED("Doubao_img2image_advanced", "10"),
DOUBAO_IMG2IMG_HIGH("Doubao_img2image_high", "15"),
WX_ANIMATION("WX_Animation", "30"),
FREEPIK_IMG2IMG("Freepik_img2img", "20"),
FLUX_IMG2IMG("Flux_img2img","10"),
private String name;
LOCAL_TEXT2IMG("Local_text2img","1.25"),
LOCAL_IMG2IMG("Local_img2img","1.25"),
LOCAL_TEXT2IMG_HIGH("Local_text2img_high","5"),
LOCAL_IMG2IMG_HIGH("Local_img2img_high","5"),
LOCAL_ANIMATION("Local_Animation","15"),
LLM_CONVERSATION("LLM_Conversation", "0")
;
private final String name;
/**
* 对应事件需要消耗or获得的积分
*/
private String value;
private final String value;
public static List<String> generateFunctionNames() {
return Arrays.asList(SLOGAN.name, LOGO.name, PATTERN.name, MOOD_BOARD.name, SKETCH_BOARD.name,
TO_PRODUCT_IMAGE.name, RELIGHT.name, IMAGE_TO_SKETCH.name, POSE_TRANSFORMATION.name);
}
private static final Map<String, CreditsEventsEnum> BY_TASK_NAME = Arrays.stream(values())
.collect(Collectors.toMap(CreditsEventsEnum::getName, Function.identity()));
public static CreditsEventsEnum getByTaskName(String taskName){
return BY_TASK_NAME.get(taskName);
}
}

View File

@@ -0,0 +1,34 @@
package com.ai.da.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor
@Getter
public enum FluxTaskStatusEnum {
SUCCESS("Ready"),
TASK_NOT_FOUND("Task not found"),
REQUEST_MODERATED("Request Moderated"),
CONTENT_MODERATED("Content Moderated"),
ERROR("Error"),
PENDING_F("Pending");
private final String name;
public static FluxTaskStatusEnum fromName(String name) {
for (FluxTaskStatusEnum status : values()) {
if (status.name.equalsIgnoreCase(name)) {
return status;
}
}
// 或者返回默认值
return TASK_NOT_FOUND;
}
}

View File

@@ -28,7 +28,9 @@ public enum LibraryLevel1TypeEnum {
* 模特
*/
MODELS("Models"),
DESIGN_ELEMENTS("DesignElements");
DESIGN_ELEMENTS("DesignElements"),
BRAND_DNA("BrandDNA");
private String realName;

View File

@@ -0,0 +1,29 @@
package com.ai.da.common.enums;
import lombok.Getter;
import java.util.stream.Stream;
@Getter
public enum MotionModeEnum {
POSE_TO_VIDEO(1, "/api/comfyui_image_pose_2_video"),
PROMPT_TO_VIDEO(2, "/api/comfyui_image_2_video"),
FIRST_LAST_FRAME_TO_VIDEO(3, "/api/comfyui_flf_2_video")
;
private int code;
private String url;
MotionModeEnum(int code, String url) {
this.code = code;
this.url = url;
}
public static MotionModeEnum of(int code) {
return Stream.of(MotionModeEnum.values()).filter(v -> v.getCode()== code).findFirst().orElse(null);
}
}

View File

@@ -0,0 +1,81 @@
package com.ai.da.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@AllArgsConstructor
@Getter
public enum PoseEnum {
// POSE_1(1, "aida-sys-image/pose/pose-1.mp4", "aida-sys-image/pose/pose-1.gif", "aida-sys-image/pose/pose-1-first_frame.jpeg", "AACT.8090e67b.-E3pujumEfCbDTI_rjSH-A.LwIlGT3j"),
POSE_1(1, "aida-sys-image/pose/pose-1-1.mp4", "aida-sys-image/pose/pose-1-1.gif", "aida-sys-image/pose/pose-1-first_frame.jpeg", "AACT.8090e67b.qNMWJlyKEfCuORaRJeW4dg.x3wUteVO"),
// POSE_2(2, "aida-sys-image/pose/pose-2.mp4", "aida-sys-image/pose/pose-2.gif", "aida-sys-image/pose/pose-2-first_frame.jpeg", "AACT.8090e67b.TwJLxEv3EfCbDTI_rjSH-A.IOQZCYhf"),
POSE_2(2, "aida-sys-image/pose/pose-2-1.mp4", "aida-sys-image/pose/pose-2-1.gif", "aida-sys-image/pose/pose-2-first_frame.jpeg", "AACT.8090e67b.QpaGOlyLEfCuuJo8eQGF2Q.62EiJj-6"),
// POSE_3(3, "aida-sys-image/pose/pose-3.mp4", "aida-sys-image/pose/pose-3.gif", "aida-sys-image/pose/pose-3-first_frame.jpeg", "AACT.8090e67b.gd3OCkv4EfCxyZo8eQGF2Q.qMm-a1XI"),
POSE_3(3, "aida-sys-image/pose/pose-3-1.mp4", "aida-sys-image/pose/pose-3-1.gif", "aida-sys-image/pose/pose-3-first_frame.jpeg", "AACT.8090e67b.2q5qjFyLEfCImjI_rjSH-A.5cFMwOvi"),
// POSE_4(4, "aida-sys-image/pose/pose-4.mp4", "aida-sys-image/pose/pose-4.gif", "aida-sys-image/pose/pose-4-first_frame.jpeg", "AACT.8090e67b.AUDnuEwDEfCEHBaRJeW4dg.rlx36xEY"),
POSE_4(4, "aida-sys-image/pose/pose-4-1.mp4", "aida-sys-image/pose/pose-4-1.gif", "aida-sys-image/pose/pose-4-first_frame.jpeg", "AACT.8090e67b.KoYMplyPEfCuORaRJeW4dg.MuuBTG78"),
// POSE_5(5, "aida-sys-image/pose/pose-5.mp4", "aida-sys-image/pose/pose-5.gif", "aida-sys-image/pose/pose-5-first_frame.jpeg", "AACT.8090e67b.G8BvkEwEEfCxyZo8eQGF2Q.fo4ryrgR"),
POSE_5(5, "aida-sys-image/pose/pose-5-1.mp4", "aida-sys-image/pose/pose-5-1.gif", "aida-sys-image/pose/pose-5-first_frame.jpeg", "AACT.8090e67b.x54FNFyPEfCuuJo8eQGF2Q.P1egmEZ_"),
// POSE_6(6, "aida-sys-image/pose/pose-6.mp4", "aida-sys-image/pose/pose-6.gif", "aida-sys-image/pose/pose-6-first_frame.jpeg", "AACT.8090e67b.yBIPnEwEEfCxyZo8eQGF2Q.boSFwTG9");
POSE_6(6, "aida-sys-image/pose/pose-6-1.mp4", "aida-sys-image/pose/pose-6-1.gif", "aida-sys-image/pose/pose-6-first_frame.jpeg", "AACT.8090e67b.QSCvBlyQEfCImjI_rjSH-A.G9-Z5ffW");
private final Integer id;
private final String videoPath;
private final String gifPath;
private final String firstFramePath;
private final String templateId;
private static final List<Map<String, String>> PROPERTY_LIST;
static {
PROPERTY_LIST = Arrays.stream(values())
.map(PoseEnum::toMap)
.collect(Collectors.toList());
}
private static final Map<Integer, PoseEnum> BY_ID = Arrays.stream(values())
.collect(Collectors.toMap(PoseEnum::getId, Function.identity()));
private static final Map<String, PoseEnum> BY_VIDEO_PATH = Arrays.stream(values())
.collect(Collectors.toMap(PoseEnum::getVideoPath, Function.identity()));
private static final List<String> VIDEO_PATH = Arrays.stream(values())
.map(PoseEnum::getVideoPath).collect(Collectors.toList());
public static PoseEnum getById(Integer id) {
return BY_ID.get(id);
}
public static PoseEnum getByVideoPath(String videoPath) {
return BY_VIDEO_PATH.get(videoPath);
}
private Map<String, String> toMap() {
Map<String, String> map = new HashMap<>();
map.put("id", String.valueOf(id));
map.put("gif", gifPath);
map.put("video", videoPath);
map.put("firstFrame", firstFramePath);
return map;
}
public static List<Map<String, String>> getPropertyList() {
return PROPERTY_LIST.stream()
.map(HashMap::new) // 深拷贝每个 Map
.collect(Collectors.toList());
}
public static List<String> getVideoList() {
return new ArrayList<>(VIDEO_PATH); // 返回副本以保证不可变性
}
}

View File

@@ -7,13 +7,19 @@ import lombok.Getter;
@AllArgsConstructor
public enum ProductEnum {
// 积分购买
CreditsProduct("AiDA credits purchase", 6L),
CreditsProduct("AiDA credits purchase", 10L, 50L),
// 年度订阅
AnnualSubscription("AiDA Annual Subscription", 5000L),
// 月度订阅
MonthlySubscription("AiDA Monthly Subscription", 500L),
AnnualSubscription("AiDA Annual Subscription", 5000L, 50000L),
// 月度订阅订阅费500每月3500 积分)
MonthlySubscription("AiDA Monthly Subscription", 500L, 3500L),
// 月度订阅 -- 经济实惠版 订阅费100每月500 积分)
Eco_MonthlySubscription("AiDA Eco Monthly Subscription", 100L, 500L),
// 季度订阅
QuarterlySubscription("AiDA Quarterly Subscription", 1500L, 12000L),
// 月度订阅 -- 教育版
EDUMonthlySubscription("AiDA Edu Monthly Subscription", 200L, 3500L),
// 测试
DailySubscription("AiDA Daily Subscription", 10L),
DailySubscription("AiDA Daily Subscription", 5L, 100L),
;
/**
@@ -22,4 +28,6 @@ public enum ProductEnum {
private final String name;
private final Long price;
private final Long credits;
}

View File

@@ -0,0 +1,32 @@
package com.ai.da.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor
@Getter
public enum WangXiangTaskStatusEnum {
SUCCEEDED("SUCCEEDED"),
UNKNOWN_W("UNKNOWN"),
FAILED("FAILED"),
RUNNING("RUNNING"),
PENDING_W("PENDING");
private final String name;
// 通过name查找枚举的静态方法
public static WangXiangTaskStatusEnum fromName(String name) {
for (WangXiangTaskStatusEnum status : values()) {
if (status.name.equalsIgnoreCase(name)) {
return status;
}
}
// 或者返回默认值
return UNKNOWN_W;
}
}

View File

@@ -1,8 +1,7 @@
package com.ai.da.common.response;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.NoArgsConstructor;
@@ -16,17 +15,17 @@ import java.util.List;
*/
@Data
@NoArgsConstructor
@ApiModel("分页响应结果")
@Schema(description = "分页响应结果")
public class PageBaseResponse<T> {
@ApiModelProperty("页码")
@Schema(description = "页码")
private long page;
@ApiModelProperty("每页数量")
@Schema(description = "每页数量")
private long size;
@ApiModelProperty("总页数")
@Schema(description = "总页数")
private long pages;
@ApiModelProperty("总条数")
@Schema(description = "总条数")
private long total;
@ApiModelProperty("结果集")
@Schema(description = "结果集")
private List<T> content;

View File

@@ -1,8 +1,7 @@
package com.ai.da.common.response;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.NoArgsConstructor;
@@ -16,18 +15,18 @@ import java.util.List;
*/
@Data
@NoArgsConstructor
@ApiModel("分页响应结果")
@Schema(description = "分页响应结果")
public class PageResponse<T> extends Response<List<T>> {
@ApiModelProperty("页码")
@Schema(description = "页码")
private long page;
@ApiModelProperty("每页数量")
@Schema(description = "每页数量")
private long size;
@ApiModelProperty("总页数")
@Schema(description = "总页数")
private long pages;
@ApiModelProperty("总条数")
@Schema(description = "总条数")
private long total;
@ApiModelProperty("结果集")
@Schema(description = "结果集")
private List<T> content;

View File

@@ -1,7 +1,6 @@
package com.ai.da.common.response;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@@ -17,14 +16,14 @@ import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel("响应结果")
@Schema(description = "响应结果")
public class Response<T> implements Serializable {
@ApiModelProperty("响应状态码 0成功 -1失败")
@Schema(description = "响应状态码 0成功 -1失败")
private int errCode;
@ApiModelProperty("提示消息")
@Schema(description = "提示消息")
private String errMsg;
@ApiModelProperty("数据结果")
@Schema(description = "数据结果")
private T data;
public static <T> Response<T> success() {

View File

@@ -1,6 +1,6 @@
package com.ai.da.common.response;
import io.swagger.annotations.ApiModel;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.NoArgsConstructor;
@@ -8,7 +8,7 @@ import java.math.BigDecimal;
@Data
@NoArgsConstructor
@ApiModel("交易记录分页响应结果")
@Schema(description = "交易记录分页响应结果")
public class TransactionPageResponse<T> extends PageBaseResponse<T> {
private BigDecimal totalAmount;

View File

@@ -7,8 +7,8 @@ import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
/**

View File

@@ -7,9 +7,9 @@ import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
/**

View File

@@ -5,7 +5,7 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import jakarta.annotation.Resource;
/**
* @author: dangweijian

View File

@@ -10,9 +10,9 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
/**

View File

@@ -8,10 +8,10 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
/**

View File

@@ -1,84 +1,107 @@
package com.ai.da.common.security.config;
import com.ai.da.common.security.*;
import com.ai.da.common.security.filter.AuthenticationFilter;
import com.ai.da.common.security.filter.UserAuthenticationProcessingFilter;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import javax.annotation.Resource;
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableConfigurationProperties(SecurityProperties.class)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Resource
private SecurityProperties securityProperties;
@Resource
private UserLoginSuccessHandler userLoginSuccessHandler;
@Resource
private UserLoginFailureHandler userLoginFailureHandler;
@Resource
private UserAuthAccessDeniedHandler userAuthAccessDeniedHandler;
@Resource
private UserAuthenticationEntryPointHandler userAuthenticationEntryPointHandler;
@Resource
private UserAuthenticationManager userAuthenticationManager;
@Resource
private UserAuthenticationProcessingFilter userAuthenticationProcessingFilter;
/**
* 不通过注入spring管理 让Security来管理 这样自定义的Filter就不会走,.permitAll()才能起作用
*/
@Resource
private AuthenticationFilter authenticationFilter;
@Resource
private UserPermissionEvaluator userPermissionEvaluator;
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return this.userAuthenticationManager;
}
@Override
protected void configure(HttpSecurity httpSecurity/*, WebSecurity web*/) throws Exception {
// web.ignoring().antMatchers("/test/**");//禁止所有过滤器
httpSecurity.cors().disable()//禁用 CSRF
.authorizeRequests()//认证请求
.antMatchers(securityProperties.getIgnorePaths()).permitAll()//忽略的请求
.anyRequest().authenticated()//其余所有的请求都需要认证
.and().headers().frameOptions().disable()// 防止iframe 造成跨域
.and().exceptionHandling().authenticationEntryPoint(userAuthenticationEntryPointHandler)//未登录请求处理
.accessDeniedHandler(userAuthAccessDeniedHandler)//无权限访问处理类 (此配置可以忽略全局异常会先于Security框架处理异常全局异常已特殊处理)
.and().formLogin().loginProcessingUrl(securityProperties.getAuthApi())//指定认证接口
.successHandler(userLoginSuccessHandler)//登录成功处理器
.failureHandler(userLoginFailureHandler)//登录失败处理器
.and().cors().and().csrf().disable();//允许跨域
//自定义过滤器在登录时认证用户名、密码
httpSecurity.addFilterAt(userAuthenticationProcessingFilter, UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(authenticationFilter, BasicAuthenticationFilter.class);
//不创建session会话
httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
//取消头缓存控制
httpSecurity.headers().cacheControl();
}
@Bean
public DefaultWebSecurityExpressionHandler userSecurityExpressionHandler() {
DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
handler.setPermissionEvaluator(userPermissionEvaluator);
return handler;
}
}
package com.ai.da.common.security.config;
import com.ai.da.common.security.*;
import com.ai.da.common.security.filter.AuthenticationFilter;
import com.ai.da.common.security.filter.UserAuthenticationProcessingFilter;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import jakarta.annotation.Resource;
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true)
@EnableConfigurationProperties(SecurityProperties.class)
public class SecurityConfig {
@Resource
private SecurityProperties securityProperties;
@Resource
private UserLoginSuccessHandler userLoginSuccessHandler;
@Resource
private UserLoginFailureHandler userLoginFailureHandler;
@Resource
private UserAuthAccessDeniedHandler userAuthAccessDeniedHandler;
@Resource
private UserAuthenticationEntryPointHandler userAuthenticationEntryPointHandler;
@Resource
private UserAuthenticationManager userAuthenticationManager;
@Resource
private UserAuthenticationProcessingFilter userAuthenticationProcessingFilter;
/**
* 不通过注入spring管理 让Security来管理 这样自定义的Filter就不会走,.permitAll()才能起作用
*/
@Resource
private AuthenticationFilter authenticationFilter;
@Resource
private UserPermissionEvaluator userPermissionEvaluator;
@Bean
public AuthenticationManager authenticationManager() throws Exception {
return this.userAuthenticationManager;
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.cors(Customizer.withDefaults())
.authorizeHttpRequests(auth -> auth
.requestMatchers(
new AntPathRequestMatcher("/doc.html"),
new AntPathRequestMatcher("/swagger-ui.html"),
new AntPathRequestMatcher("/swagger-ui/**"),
new AntPathRequestMatcher("/swagger-resources/**"),
new AntPathRequestMatcher("/v2/api-docs"),
new AntPathRequestMatcher("/v3/api-docs/**"),
new AntPathRequestMatcher("/webjars/**")
).permitAll()
.requestMatchers(securityProperties.getIgnorePaths()).permitAll()
.anyRequest().authenticated()
)
.headers(headers -> headers
.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)
.cacheControl(cache -> cache.disable())
)
.exceptionHandling(exception -> exception
.authenticationEntryPoint(userAuthenticationEntryPointHandler)
.accessDeniedHandler(userAuthAccessDeniedHandler)
)
.formLogin(form -> form
.loginProcessingUrl(securityProperties.getAuthApi())
.successHandler(userLoginSuccessHandler)
.failureHandler(userLoginFailureHandler)
)
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
);
//自定义过滤器在登录时认证用户名、密码
httpSecurity.addFilterAt(userAuthenticationProcessingFilter, UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(authenticationFilter, BasicAuthenticationFilter.class);
return httpSecurity.build();
}
@Bean
public DefaultWebSecurityExpressionHandler userSecurityExpressionHandler() {
DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
handler.setPermissionEvaluator(userPermissionEvaluator);
return handler;
}
}

View File

@@ -6,6 +6,7 @@ import com.ai.da.common.context.UserContext;
import com.ai.da.common.security.config.SecurityProperties;
import com.ai.da.common.security.jwt.JWTTokenHelper;
import com.ai.da.common.utils.LocalCacheUtils;
import com.ai.da.common.utils.RedisUtil;
import com.ai.da.common.utils.MultiReadHttpServletRequest;
import com.ai.da.common.utils.MultiReadHttpServletResponse;
import com.ai.da.common.utils.RequestInfoUtil;
@@ -18,12 +19,11 @@ import org.springframework.util.StopWatch;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.annotation.Resource;
import javax.security.sasl.AuthenticationException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
@@ -41,10 +41,15 @@ public class AuthenticationFilter extends OncePerRequestFilter {
private JWTTokenHelper jwtTokenHelper;
@Resource
private SecurityProperties properties;
@Resource
private RedisUtil redisUtil;
private static final List<String> FILTER_URL =
Arrays.asList("/favicon.ico", "/doc.html", "api/account/login", "api/account/preLogin", "api/account/sendEmail","api/account/noLoginRequired",
"/webjars/", "/swagger-resources", "/v2/api-docs", "api/account/resetPwd",
Arrays.asList("/favicon.ico", "/doc.html", "/swagger-ui.html",
"/swagger-resources", "/swagger-resources/", "/swagger-resources/configuration/ui", "/swagger-resources/configuration/security",
"/webjars/", "/v2/api-docs", "/v3/api-docs", "/v3/api-docs/swagger-config",
"/api/account/login", "/api/account/preLogin", "api/account/sendEmail","api/account/noLoginRequired",
"/api/account/resetPwd",
"/api/python/saveGeneratePicture", "/api/python/getLibraryByUserId",
"/api/third/party/addUser","/api/third/party/addTrialUser", "/api/third/party/editUser", "/api/element/initDefaultSysFile",
"/api/third/party/addNoLoginRequiredNew","/api/third/party/deleteNoLoginRequiredNew","/api/third/party/updateNoLoginRequiredNew",
@@ -52,14 +57,21 @@ public class AuthenticationFilter extends OncePerRequestFilter {
"/api/python/flush","/api/account/healthy","/api/ali-pay/trade/notify","/api/paypal/ipn/back","/api/alipay-hk/trade/notify",
"/api/portfolio/page", "/api/portfolio/detail", "/api/portfolio/commentPage", "/api/portfolio/viewsIncrease",
"/api/account/designWorksRegister","/api/account/questionnaire","/api/stripe/trade/notify",
"/notification","/api/account/activateNewEmail","/api/third/party/auth/google_callback","/api/third/party/parseGoogleCredential","/api/third/party/receiveDesignResults","/api/third/party/parseWeChatCode"
"/notification","/api/account/activateNewEmail","/api/third/party/auth/google_callback","/api/third/party/parseGoogleCredential","/api/third/party/receiveDesignResults","/api/third/party/parseWeChatCode","/api/third/party/receiveDesignParams"
, "/api/account/schoolLogin", "/api/account/enterpriseLogin", "/api/account/organizationNameSearch",
"/api/llm/stream",
//GlobalAwardController
"/api/global-award/uploads/pdf/init", "/api/global-award/uploads/pdf/chunk", "/api/global-award/uploads/pdf/complete", "/api/global-award/uploads/pdf/status",
"/api/global-award/uploads/video/init", "/api/global-award/uploads/video/chunk", "/api/global-award/uploads/video/complete", "/api/global-award/uploads/video/status",
"/api/global-award/contestants/save", "/api/global-award/contestants/by-email", "/api/global-award/checkEmail", "/api/global-award/checkCode","/api/global-award/contestants/export",
"/api/global-award/contestants/export/files"
);
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, @NonNull HttpServletResponse httpServletResponse, @NonNull FilterChain filterChain) throws ServletException, IOException {
String requestURI = httpServletRequest.getRequestURI();
if (calculateUrl(requestURI) || hasAuthorizationToken(httpServletRequest)) {
if (calculateUrl(requestURI)/* || hasAuthorizationToken(httpServletRequest)*/) {
StopWatch stopWatch = new StopWatch();
HttpServletRequest wrappedRequest = httpServletRequest;
HttpServletResponse wrappedResponse = httpServletResponse;
@@ -72,7 +84,12 @@ public class AuthenticationFilter extends OncePerRequestFilter {
wrappedRequest = new MultiReadHttpServletRequest(httpServletRequest);
wrappedResponse = new MultiReadHttpServletResponse(httpServletResponse);
extracted(wrappedRequest);
filterChain.doFilter(wrappedRequest, wrappedResponse);
// excel导出使用原始response,不对响应做包装
if (requestURI.equals("/api/account/exportAccountsToExcel")) {
filterChain.doFilter(httpServletRequest, httpServletResponse); // 不包装
} else {
filterChain.doFilter(wrappedRequest, wrappedResponse);
}
}
} catch (Exception e) {
SecurityContextHolder.clearContext();
@@ -81,6 +98,8 @@ public class AuthenticationFilter extends OncePerRequestFilter {
stopWatch.stop();
}
} else {
//先清空当前线程变量,防止上一个线程遗留
UserContext.delete();
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}
@@ -95,7 +114,7 @@ public class AuthenticationFilter extends OncePerRequestFilter {
return authorizationHeader != null && authorizationHeader.startsWith("Bearer");
}
private void extracted(HttpServletRequest request) throws AuthenticationException {
private void extracted(HttpServletRequest request) {
String jwtToken = request.getHeader(properties.getJwtTokenHeader());
// log.debug("后台检查令牌:{}", jwtToken);
@@ -121,12 +140,19 @@ public class AuthenticationFilter extends OncePerRequestFilter {
UserContext.delete();
//存取用户信息到缓存
UserContext.setUserHolder(principal);
//校验token
String cacheToken = LocalCacheUtils.getTokenCache(String.valueOf(principal.getId()));
// 校验 token:先查本地缓存,再查 Redis保证服务重启后仍然有效
String userIdStr = String.valueOf(principal.getId());
String cacheToken = LocalCacheUtils.getTokenCache(userIdStr);
if(StringUtils.isEmpty(cacheToken)){
// throw new RuntimeException("TOKEN已过期请重新登录");
throw new TokenMissingOrExpiredException("TOKEN已过期请重新登录(local cache empty)");
if (StringUtils.isEmpty(cacheToken)) {
// 本地缓存为空时,尝试从 Redis 读取
cacheToken = redisUtil.getLoginToken(principal.getId());
if (StringUtils.isEmpty(cacheToken)) {
// throw new RuntimeException("TOKEN已过期请重新登录");
throw new TokenMissingOrExpiredException("TOKEN已过期请重新登录(cache & redis empty)");
}
// 将 Redis 中的 token 回填到本地缓存,减少后续 Redis 访问
LocalCacheUtils.setTokenCache(userIdStr, cacheToken);
}
if(!cacheToken.equals(jwtToken) ){
// throw new RuntimeException("TOKEN已过期请重新登录");

View File

@@ -1,69 +1,69 @@
package com.ai.da.common.security.filter;
import cn.hutool.core.util.StrUtil;
import com.ai.da.common.security.UserLoginSuccessHandler;
import com.ai.da.common.security.config.SecurityProperties;
import com.ai.da.common.utils.RedisCacheUtils;
import com.alibaba.fastjson.JSONObject;
import com.ai.da.common.security.UserAuthenticationManager;
import com.ai.da.common.security.UserLoginFailureHandler;
import com.ai.da.common.utils.MultiReadHttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author: dangweijian
* @description: 用户认证过滤器
* @create: 2020-07-10 15:58
**/
@Slf4j
@Component
public class UserAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {
/**
* @param securityProperties 配置从配置中读取登录url
* @param authenticationManager 认证管理器
* @param adminAuthenticationSuccessHandler 认证成功处理器
* @param adminAuthenticationFailureHandler 认证失败处理器
*/
public UserAuthenticationProcessingFilter(SecurityProperties securityProperties, UserAuthenticationManager authenticationManager, UserLoginSuccessHandler adminAuthenticationSuccessHandler, UserLoginFailureHandler adminAuthenticationFailureHandler) {
super(new AntPathRequestMatcher(securityProperties.getAuthApi(), HttpMethod.POST.name()));
this.setAuthenticationManager(authenticationManager);
this.setAuthenticationSuccessHandler(adminAuthenticationSuccessHandler);
this.setAuthenticationFailureHandler(adminAuthenticationFailureHandler);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (request.getContentType() == null || !request.getContentType().contains("application/json")) {
throw new AuthenticationServiceException("请求头类型不支持: " + request.getContentType());
}
UsernamePasswordAuthenticationToken authRequest;
try {
MultiReadHttpServletRequest wrappedRequest = new MultiReadHttpServletRequest(request);
// 将前端传递的数据转换成jsonBean数据格式
JSONObject jsonObject = JSONObject.parseObject(wrappedRequest.getBodyJsonStrByJson(wrappedRequest));
String code = jsonObject.getString("code");
String uuid = jsonObject.getString("uuid");
if (StrUtil.isEmpty(code) || StrUtil.isEmpty(uuid) || !code.equals(RedisCacheUtils.get("code-key-" + uuid, String.class))) {
throw new AuthenticationServiceException("验证码错误");
}
RedisCacheUtils.delete("code-key-" + uuid);
authRequest = new UsernamePasswordAuthenticationToken(jsonObject.get("username"), jsonObject.get("password"), null);
authRequest.setDetails(authenticationDetailsSource.buildDetails(wrappedRequest));
} catch (Exception e) {
throw new AuthenticationServiceException(e.getMessage());
}
return this.getAuthenticationManager().authenticate(authRequest);
}
}
package com.ai.da.common.security.filter;
import cn.hutool.core.util.StrUtil;
import com.ai.da.common.security.UserLoginSuccessHandler;
import com.ai.da.common.security.config.SecurityProperties;
import com.ai.da.common.utils.RedisCacheUtils;
import com.alibaba.fastjson.JSONObject;
import com.ai.da.common.security.UserAuthenticationManager;
import com.ai.da.common.security.UserLoginFailureHandler;
import com.ai.da.common.utils.MultiReadHttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
/**
* @author: dangweijian
* @description: 用户认证过滤器
* @create: 2020-07-10 15:58
**/
@Slf4j
@Component
public class UserAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {
/**
* @param securityProperties 配置从配置中读取登录url
* @param authenticationManager 认证管理器
* @param adminAuthenticationSuccessHandler 认证成功处理器
* @param adminAuthenticationFailureHandler 认证失败处理器
*/
public UserAuthenticationProcessingFilter(SecurityProperties securityProperties, UserAuthenticationManager authenticationManager, UserLoginSuccessHandler adminAuthenticationSuccessHandler, UserLoginFailureHandler adminAuthenticationFailureHandler) {
super(new AntPathRequestMatcher(securityProperties.getAuthApi(), HttpMethod.POST.name()));
this.setAuthenticationManager(authenticationManager);
this.setAuthenticationSuccessHandler(adminAuthenticationSuccessHandler);
this.setAuthenticationFailureHandler(adminAuthenticationFailureHandler);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (request.getContentType() == null || !request.getContentType().contains("application/json")) {
throw new AuthenticationServiceException("请求头类型不支持: " + request.getContentType());
}
UsernamePasswordAuthenticationToken authRequest;
try {
MultiReadHttpServletRequest wrappedRequest = new MultiReadHttpServletRequest(request);
// 将前端传递的数据转换成jsonBean数据格式
JSONObject jsonObject = JSONObject.parseObject(wrappedRequest.getBodyJsonStrByJson(wrappedRequest));
String code = jsonObject.getString("code");
String uuid = jsonObject.getString("uuid");
if (StrUtil.isEmpty(code) || StrUtil.isEmpty(uuid) || !code.equals(RedisCacheUtils.get("code-key-" + uuid, String.class))) {
throw new AuthenticationServiceException("验证码错误");
}
RedisCacheUtils.delete("code-key-" + uuid);
authRequest = new UsernamePasswordAuthenticationToken(jsonObject.get("username"), jsonObject.get("password"), null);
authRequest.setDetails(authenticationDetailsSource.buildDetails(wrappedRequest));
} catch (Exception e) {
throw new AuthenticationServiceException(e.getMessage());
}
return this.getAuthenticationManager().authenticate(authRequest);
}
}

View File

@@ -1,87 +1,108 @@
package com.ai.da.common.security.jwt;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.ai.da.common.constant.CommonConstant;
import com.ai.da.common.security.config.SecurityProperties;
import com.ai.da.model.vo.AuthPrincipalVo;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
/**
* @author: dangweijian
* @description: JWT工具
* @create: 2020-07-09 09:27
**/
@Slf4j
@Component
public class JWTTokenHelper {
@Resource
private SecurityProperties securityProperties;
private static final String ISSUER = "DWJ";
private static final String AUTHORITIES = "authorities";
private static final String CHANGE_MAILBOX = "changeMailbox";
public String createToken(AuthPrincipalVo principal) {
String token = Jwts.builder()
.setId(String.valueOf(principal.getId()))
.setSubject(JSONObject.toJSONString(principal))
.setIssuedAt(new Date())
.setIssuer(ISSUER)
.claim(AUTHORITIES, JSON.toJSONString(new ArrayList<>()))//自定义属性 权限
.setExpiration(new Date(System.currentTimeMillis() + securityProperties.getJwtExpiration()))
.signWith(SignatureAlgorithm.HS512, securityProperties.getJwtSecret())
.compact();
token = securityProperties.getJwtTokenPrefix() + token;
return token;
}
public boolean validateToken(String token) {
Claims claims = parser(token);
if (MapUtil.isEmpty(claims)) {
return false;
}
return true;
}
public AuthPrincipalVo parserToUser(String token) {
String subject = parser(token).getSubject();
if (StrUtil.isNotEmpty(subject)) {
return JSONObject.parseObject(subject, AuthPrincipalVo.class);
}
return null;
}
public Claims parser(String token) {
token = token.replaceAll(securityProperties.getJwtTokenPrefix(), "");
return Jwts.parser().setSigningKey(securityProperties.getJwtSecret()).parseClaimsJws(token).getBody();
}
public String createToken(Long userId, String userEmail){
String token = Jwts.builder()
.setId(String.valueOf(userId))
.setSubject(userEmail + "_" + userId)
.setIssuedAt(new Date())
.setIssuer(ISSUER)
.claim(CHANGE_MAILBOX, JSON.toJSONString(new ArrayList<>()))//自定义属性 权限
.setExpiration(new Date(System.currentTimeMillis() + CommonConstant.CHANGE_MAILBOX_LINK_VALIDITY))
.signWith(SignatureAlgorithm.HS256, securityProperties.getJwtSecret())
.compact();
return token;
}
public String parseToEmailAndId(String token) {
return parser(token).getSubject();
}
}
package com.ai.da.common.security.jwt;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.ai.da.common.constant.CommonConstant;
import com.ai.da.common.security.config.SecurityProperties;
import com.ai.da.model.vo.AuthPrincipalVo;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import jakarta.annotation.Resource;
import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
/**
* @author: dangweijian
* @description: JWT工具
* @create: 2020-07-09 09:27
**/
@Slf4j
@Component
public class JWTTokenHelper {
@Resource
private SecurityProperties securityProperties;
private static final String ISSUER = "DWJ";
private static final String AUTHORITIES = "authorities";
private static final String CHANGE_MAILBOX = "changeMailbox";
public String createToken(AuthPrincipalVo principal) {
SecretKey key = buildSigningKey();
String token = Jwts.builder()
.id(String.valueOf(principal.getId()))
.subject(JSONObject.toJSONString(principal))
.issuedAt(new Date())
.issuer(ISSUER)
.claim(AUTHORITIES, JSON.toJSONString(new ArrayList<>()))//自定义属性 权限
.expiration(new Date(System.currentTimeMillis() + securityProperties.getJwtExpiration()))
.signWith(key)
.compact();
token = securityProperties.getJwtTokenPrefix() + token;
return token;
}
public boolean validateToken(String token) {
Claims claims = parser(token);
if (MapUtil.isEmpty(claims)) {
return false;
}
return true;
}
public AuthPrincipalVo parserToUser(String token) {
String subject = parser(token).getSubject();
if (StrUtil.isNotEmpty(subject)) {
return JSONObject.parseObject(subject, AuthPrincipalVo.class);
}
return null;
}
public Claims parser(String token) {
token = token.replaceAll(securityProperties.getJwtTokenPrefix(), "");
SecretKey key = buildSigningKey();
return Jwts.parser()
.verifyWith(key)
.build()
.parseSignedClaims(token)
.getPayload();
}
public String createToken(Long userId, String userEmail){
SecretKey key = buildSigningKey();
String token = Jwts.builder()
.id(String.valueOf(userId))
.subject(userEmail + "_" + userId)
.issuedAt(new Date())
.issuer(ISSUER)
.claim(CHANGE_MAILBOX, JSON.toJSONString(new ArrayList<>()))//自定义属性 权限
.expiration(new Date(System.currentTimeMillis() + CommonConstant.CHANGE_MAILBOX_LINK_VALIDITY))
.signWith(key)
.compact();
return token;
}
public String parseToEmailAndId(String token) {
return parser(token).getSubject();
}
/**
* JWT 要求 HMAC-SHA 的密钥至少 256 bit这里统一扩展/哈希密钥长度避免 WeakKeyException。
*/
private SecretKey buildSigningKey() {
byte[] raw = securityProperties.getJwtSecret().getBytes(StandardCharsets.UTF_8);
if (raw.length < 32) {
raw = DigestUtil.sha256(raw);
}
return Keys.hmacShaKeyFor(raw);
}
}

View File

@@ -3,11 +3,12 @@ package com.ai.da.common.task;
import com.ai.da.common.utils.RedisUtil;
import com.ai.da.mapper.primary.entity.Account;
import com.ai.da.service.AccountService;
import com.ai.da.service.SubscriptionPlanService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import jakarta.annotation.Resource;
import java.util.List;
@Component
@@ -18,27 +19,29 @@ public class AccountTask {
private AccountService accountService;
@Resource
private RedisUtil redisUtil;
@Resource
private SubscriptionPlanService subscriptionPlanService;
/**
* 每周日晚上刷新 年付用户、月付用户的积分
* 替换为
* 每个月月初只刷新年付用户的积分
* 每个月月初只刷新教育子账号的积分
*/
// @Scheduled(cron = "59 59 23 * * ?")
// @Scheduled(cron = "0 25 14 * * ?")
@Scheduled(cron = "0 0 0 1 * ?")
public void refreshCreditsMonthly() {
log.info("每月1号0点 将年费用户积分重置为 6000");
accountService.refreshCreditsWeekly();
log.info("每月1号0点 重置教育版子账号为默认积分");
accountService.refreshCreditsMonthly();
}
@Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
@Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
public void getPaidUser() {
// 获取code-create 表中 指定日期之后 订单状态为wc-processing的订单
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);
@@ -48,7 +51,7 @@ public class AccountTask {
log.info("参与活动的用户{} : {} 于 {} 账号有效期到期,置为游客", account.getId(), account.getUserEmail(), account.getValidEndTime());
accountService.toVisitor(account);
}
}
}*/
// 每天检测正式用户到期情况每天凌晨0点执行
@Scheduled(cron = "0 0 0 * * ?")
@@ -80,4 +83,20 @@ public class AccountTask {
log.info("重置所有用户的用户名修改次数");
redisUtil.batchDeleteKeysWithSamePrefix(RedisUtil.NICKNAME_MODIFY_TIMES);
}
// @Scheduled(cron = "0 35 14 * * ?")
@Scheduled(cron = "0 5 0 * * ?")
public void checkEduAdminExpireStatus() {
accountService.checkEduAdminExpireStatus();
}
@Scheduled(cron = "0 5 0 * * ?")
public void activeSubscriptionPlan() {
subscriptionPlanService.activeSubscriptionPlan(null);
}
@Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
public void expireSubscription() {
subscriptionPlanService.expireSubscription();
}
}

View File

@@ -0,0 +1,140 @@
package com.ai.da.common.task;
import com.ai.da.common.config.exception.BusinessException;
import com.ai.da.common.utils.DateUtil;
import com.ai.da.mapper.primary.PoseTransformationMapper;
import com.ai.da.mapper.primary.ToProductImageResultMapper;
import com.ai.da.mapper.primary.entity.*;
import com.ai.da.model.vo.PoseTransformationVO;
import com.ai.da.service.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.netty.util.internal.StringUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import static com.ai.da.common.enums.CreditsEventsEnum.TO_PRODUCT_IMAGE;
@Slf4j
@Component
@RequiredArgsConstructor
public class GenerateTask {
private final APIGenerateService apiGenerateService;
private final CreditsService creditsService;
private final GenerateService generateService;
private final PoseTransformationMapper poseTransformationMapper;
private final ToProductImageResultMapper toProductImageResultMapper;
/*
* 对于使用了第三方api的允许异步获得结果的生成功能可能在第三方接口的结果Ready时没有及时存储结果导致第三方链接失效
* 万相 24h失效
* flux 10mins失效 使用了flux接口的功能 ToProductImage || Relight, Pattern这里不做补偿
* 故这里通过定时任务做补偿
* flux五分钟查询一次万相1小时查询一次
*/
@Scheduled(cron = "0 */4 * * * ?")
public void fluxCompensationMechanism(){
// 1、查所有 任务还没成功、还没失败正在等待或者执行中的任务id有哪些
// 由于获取结果的polling_url在redis中只存一天大部分结果超过一天之后就无法再找到任务小部分可以通过公共路径查到结果
List<APIGenerate> apiGenerates = apiGenerateService.getPendingTaskByStatus("flux");
if (apiGenerates != null && !apiGenerates.isEmpty()){
for (APIGenerate apiGenerate : apiGenerates){
String taskId = apiGenerate.getTaskId();
// 1. 根据taskId查toProductImageResult 判断当前任务状态与超时状态
ToProductImageResult toProductImageResult = toProductImageResultMapper.selectOne(new QueryWrapper<ToProductImageResult>().eq("task_id", taskId));
if (Objects.nonNull(toProductImageResult) && "Pending".equals(toProductImageResult.getStatus())){
// 判断当前任务的超时状态
if (!DateUtil.isMoreThanOneDayApart(toProductImageResult.getCreateTime())){
// 1. 未超时,获取当前任务结果
String fileName = toProductImageResult.getResultType().equals(TO_PRODUCT_IMAGE.getName()) ? "product_image" : "relight_image";
String objectName = apiGenerate.getAccountId() + "/" + fileName +"/" + taskId + ".png";
String fluxResult = generateService.getFluxResult(taskId, objectName);
// 2. 成功获取结果下载图片上传至minio,更新toProductImageResult表
if (StringUtil.isNullOrEmpty(fluxResult) || fluxResult.equals("Fail")){
toProductImageResult.setStatus("Fail");
toProductImageResultMapper.updateById(toProductImageResult);
apiGenerate.setStatus("Fail");
apiGenerate.setUpdateTime(LocalDateTime.now());
apiGenerateService.updateById(apiGenerate);
} else if (!fluxResult.equals("Pending")){
if (StringUtil.isNullOrEmpty(toProductImageResult.getUrl())){
toProductImageResult.setStatus("Success");
toProductImageResult.setUrl(fluxResult);
toProductImageResultMapper.updateById(toProductImageResult);
apiGenerate.setStatus("Success");
apiGenerate.setUpdateTime(LocalDateTime.now());
apiGenerateService.updateById(apiGenerate);
}
// 扣积分
Boolean flag = creditsService.taskCreditsDeduction(apiGenerate.getAccountId(), taskId);
if (flag) creditsService.updateChangedCredits(String.valueOf(apiGenerate.getAccountId()), taskId);
}
} else {
// 超时,设置状态为失败
toProductImageResult.setStatus("Fail");
toProductImageResultMapper.updateById(toProductImageResult);
apiGenerate.setStatus("Fail");
apiGenerate.setUpdateTime(LocalDateTime.now());
apiGenerateService.updateById(apiGenerate);
}
// 将积分暂扣区的积分移除
if (toProductImageResult.getStatus().equals("Fail")){
creditsService.deleteCreditsDeduction(apiGenerate.getAccountId(), taskId);
}
}
}
}
}
// 万相 -> pose transformation 补偿 当前任务执行完后5分钟再执行一次不会出现任务重叠的情况
@Scheduled(fixedDelay = 5 * 60 * 1000)
public void wxCompensationMechanism(){
List<APIGenerate> apiGenerates = apiGenerateService.getPendingTaskByStatus("wx");
if (apiGenerates != null && !apiGenerates.isEmpty()){
log.info("=====万相补偿获取结果开始=====");
for (APIGenerate apiGenerate : apiGenerates){
String taskId = apiGenerate.getTaskId();
PoseTransformation poseTransformation = poseTransformationMapper.selectOne(new QueryWrapper<PoseTransformation>().eq("unique_id", taskId));
if (Objects.nonNull(poseTransformation) && ("Pending".equals(poseTransformation.getTaskStatus()) || "Executing".equals(poseTransformation.getTaskStatus()))){
// 判断当前任务的超时状态
if (!DateUtil.isMoreThanOneDayApart(poseTransformation.getCreateTime())){
try {
// 方法中已经完成了pose_transformation和api_generate表的更新不用额外做处理
PoseTransformationVO animateResult = generateService.getAnimateResult(taskId);
if (animateResult.getStatus().equals("Success")){
log.info("补偿获取结果成功,发送系统消息");
}
} catch (BusinessException e){
log.warn("万相 animation 生成失败,原因:{}", e.getMessage());
}
}
} else {
poseTransformation.setTaskStatus("Fail");
poseTransformation.setUpdateTime(LocalDateTime.now());
poseTransformationMapper.updateById(poseTransformation);
apiGenerate.setStatus("Fail");
apiGenerate.setUpdateTime(LocalDateTime.now());
apiGenerateService.updateById(apiGenerate);
generateService.sendSysMsgForPT(poseTransformation);
}
}
}
}
}

View File

@@ -17,8 +17,8 @@
//import org.springframework.stereotype.Component;
//import org.springframework.util.CollectionUtils;
//
//import javax.annotation.PostConstruct;
//import javax.annotation.Resource;
//import jakarta.annotation.PostConstruct;
//import jakarta.annotation.Resource;
//import java.io.FileOutputStream;
//import java.io.IOException;
//import java.nio.file.Files;

View File

@@ -8,7 +8,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import jakarta.annotation.Resource;
import java.time.LocalDate;
import java.util.List;
@@ -45,7 +45,7 @@ public class PaymentTask {
@Resource
private PayPalCheckoutService payPalCheckoutService;
@Scheduled(cron = "0/30 * * * * ?")
@Scheduled(cron = "0/30 * * * * ?")
public void orderConfirmForPaypal() throws SerializeException {
// log.info("PayPal orderConfirm 被执行......");
@@ -87,9 +87,9 @@ public class PaymentTask {
// !!关闭此定时器,改为提前三天站内信提醒!!
// 提前7天向用户发送提醒邮件,每天早上8点执行
// @Scheduled(cron = "0 0 8 * * ?")
public void subscriptionReminder(){
stripeService.subscriptionReminder();
}
// public void subscriptionReminder(){
// stripeService.subscriptionReminder();
// }
// 如果有订阅已创建,但是没有发邮件通知的,需要主动获取回调信息并向用户发送邮件
@@ -97,13 +97,19 @@ public class PaymentTask {
//
}
@Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
@Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
public void updateAffiliateInfoWithPayment(){
// log.info("佣金计算定时器");
affiliateService.updateAffiliateInfoWithPayment();
}
@Scheduled(cron = "0 0 8 28-31 * ?")
// 定时同步(每分钟一次)
@Scheduled(fixedRate = 60000)
public void syncLinkViewCountToDB(){
affiliateService.syncLinkViewCountToDB();
}
@Scheduled(cron = "0 0 8 28-31 * ?")
public void commissionSummaryReminder(){
// 每个月末的最后一天的早上八点执行
LocalDate today = LocalDate.now();

View File

@@ -0,0 +1,144 @@
package com.ai.da.common.task;
import com.ai.da.common.utils.SendEmailUtil;
import com.ai.da.mapper.primary.AccountMapper;
import com.ai.da.mapper.primary.SubscriptionInfoMapper;
import com.ai.da.mapper.primary.entity.Account;
import com.ai.da.mapper.primary.entity.SubscriptionInfo;
import com.ai.da.service.StripeService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.netty.util.internal.StringUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
@Component
@RequiredArgsConstructor
public class SubscriptionReminderTask {
public final AccountMapper accountMapper;
public final SubscriptionInfoMapper subscriptionInfoMapper;
public final StripeService stripeService;
// 订阅类型与提前天数的映射配置
private static final Map<String, Integer> REMINDER_DAYS_CONFIG = new HashMap<>();
static {
REMINDER_DAYS_CONFIG.put("month", 7);
REMINDER_DAYS_CONFIG.put("year", 14);
}
@Scheduled(cron = "0 0 9 * * ?")
public void subscriptionReminder() {
// 获取所有需要通知的订阅
List<SubscriptionInfo> subscriptionInfos = getDueSubscriptions();
for (SubscriptionInfo subscriptionInfo : subscriptionInfos) {
Integer daysBefore = REMINDER_DAYS_CONFIG.get(subscriptionInfo.getType());
if (daysBefore == null) {
log.warn("未知的订阅类型: {}", subscriptionInfo.getType());
continue;
}
String emailType = subscriptionInfo.getStatus().equals("active") ? "reminder_subscriber" : subscriptionInfo.getStatus().equals("canceled") ? "reminder_expire" : null;
if (StringUtil.isNullOrEmpty(emailType)) {
log.warn("未知订阅状态:{}", subscriptionInfo.getStatus());
continue;
}
boolean success = stripeService.sendEmail(subscriptionInfo.getSubscriptionId(), emailType, subscriptionInfo.getOrderNo());
if (success) {
log.info("提前{}天向用户 {} 发送续订通知邮件,订阅类型: {}",
daysBefore, subscriptionInfo.getAccountId(), subscriptionInfo.getType());
}
}
}
private List<SubscriptionInfo> getDueSubscriptions() {
List<SubscriptionInfo> results = new ArrayList<>();
for (Map.Entry<String, Integer> entry : REMINDER_DAYS_CONFIG.entrySet()) {
String subscriptionType = entry.getKey();
int daysBefore = entry.getValue();
results.addAll(getSubscriptionsDueInDays(subscriptionType, daysBefore));
}
return results;
}
private List<SubscriptionInfo> getSubscriptionsDueInDays(String subscriptionType, int daysBefore) {
LocalDateTime targetDate = LocalDateTime.now().plusDays(daysBefore);
LocalDateTime startOfDay = targetDate.toLocalDate().atStartOfDay();
LocalDateTime endOfDay = targetDate.toLocalDate().atTime(23, 59, 59);
// 使用系统默认时区
ZoneId zoneId = ZoneId.systemDefault();
long startTimestamp = startOfDay.atZone(zoneId).toEpochSecond();
long endTimestamp = endOfDay.atZone(zoneId).toEpochSecond();
QueryWrapper<SubscriptionInfo> qw = new QueryWrapper<>();
qw.lambda().ge(SubscriptionInfo::getCurrentPeriodEnd, startTimestamp);
qw.lambda().lt(SubscriptionInfo::getCurrentPeriodEnd, endTimestamp);
// qw.eq("status", "active");
qw.lambda().eq(SubscriptionInfo::getType, subscriptionType);
return subscriptionInfoMapper.selectList(qw);
}
@Scheduled(cron = "0 0 9 * * ?")
public void trialReminder() {
// 今天的 00:00:00 和 23:59:59
LocalDateTime startOfDay = LocalDateTime.now().toLocalDate().atStartOfDay();
LocalDateTime endOfDay = LocalDateTime.now().toLocalDate().atTime(23, 59, 59);
// 使用系统默认时区
ZoneId zoneId = ZoneId.systemDefault();
long startTimestamp = startOfDay.atZone(zoneId).toEpochSecond() * 1000;
long endTimestamp = endOfDay.atZone(zoneId).toEpochSecond() * 1000;
QueryWrapper<Account> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().gt(Account::getValidEndTime, startTimestamp)
.lt(Account::getValidEndTime, endTimestamp)
.eq(Account::getSystemUser, 3);
List<Account> accounts = accountMapper.selectList(queryWrapper);
for (Account account : accounts) {
String language = stripeService.getLanguage(account.getLanguage(), account.getCountry(), "reminder_trial");
SendEmailUtil.subscriptionEmailReminder("reminder_trial", null, language, account.getUserEmail());
}
}
/* public void subscriptionReminder(){
// 提前7天的 00:00:00 和 23:59:59
LocalDateTime startOfDay = LocalDateTime.now().plusDays(7).toLocalDate().atStartOfDay();
LocalDateTime endOfDay = LocalDateTime.now().plusDays(7).toLocalDate().atTime(23, 59, 59);
// 转为时间戳
long startTimestamp = startOfDay.toEpochSecond(ZoneOffset.UTC);
long endTimestamp = endOfDay.toEpochSecond(ZoneOffset.UTC);
QueryWrapper<SubscriptionInfo> qw = new QueryWrapper<>();
qw.ge("current_period_end", startTimestamp);
qw.lt("current_period_end", endTimestamp);
qw.eq("status", "active");
List<SubscriptionInfo> subscriptionInfos = subscriptionInfoMapper.selectList(qw);
for (SubscriptionInfo subscriptionInfo : subscriptionInfos) {
boolean b = sendEmail(subscriptionInfo.getSubscriptionId(), "reminder", null);
if (b) log.info("提前7天向用户 {} 发送续订通知邮件", subscriptionInfo.getAccountId());
}
}*/
}

View File

@@ -5,10 +5,7 @@ import lombok.extern.slf4j.Slf4j;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Locale;
@@ -101,4 +98,10 @@ public class DateUtil {
return localDate.format(DateTimeFormatter.ofPattern(CommonConstant.TIME_FORMAT_MMM_dd_yyyy_EEEE, Locale.US));
}
public static boolean isMoreThanOneDayApart(LocalDateTime givenDateTime) {
LocalDateTime now = LocalDateTime.now();
Duration duration = Duration.between(givenDateTime, now);
return duration.toHours() >= 24;
}
}

View File

@@ -1,313 +1,325 @@
package com.ai.da.common.utils;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.ai.da.common.config.exception.BusinessException;
import com.ai.da.model.vo.FileVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
public class FileUtil extends cn.hutool.core.io.FileUtil {
private static final Logger log = LoggerFactory.getLogger(com.ai.da.common.utils.FileUtil.class);
/**
* 系统临时目录
* <br>
* windows 包含路径分割符但Linux 不包含,
* 在windows \\==\ 前提下,
* 为安全起见 同意拼装 路径分割符,
* <pre>
* java.io.tmpdir
* windows : C:\Users/xxx\AppData\Local\Temp\
* linux: /temp
* </pre>
*/
public static final String SYS_TEM_DIR = System.getProperty("java.io.tmpdir") + File.separator;
/**
* 定义GB的计算常量
*/
private static final int GB = 1024 * 1024 * 1024;
/**
* 定义MB的计算常量
*/
private static final int MB = 1024 * 1024;
/**
* 定义KB的计算常量
*/
private static final int KB = 1024;
/**
* 格式化小数
*/
private static final DecimalFormat DF = new DecimalFormat("0.00");
public static final String IMAGE = "图片";
public static final String TXT = "文档";
public static final String MUSIC = "音乐";
public static final String VIDEO = "视频";
public static final String OTHER = "其他";
/**
* MultipartFile转File
*/
public static File toFile(MultipartFile multipartFile) {
// 获取文件名
String fileName = multipartFile.getOriginalFilename();
// 获取文件后缀
String prefix = "." + getExtensionName(fileName);
File file = null;
try {
// 用uuid作为文件名防止生成的临时文件重复
file = new File(SYS_TEM_DIR + IdUtil.simpleUUID() + prefix);
// MultipartFile to File
multipartFile.transferTo(file);
} catch (IOException e) {
log.error(e.getMessage(), e);
}
return file;
}
// public static void main(String[] args) {
// File file = new File(
// "http://18.162.111.141:5568/download/202211/userFile/collection/Printboard/1/a3c9838c-2171-44d7-af54-c94ee6affcd9print_2.jpg.png");
// FileUtil.getFileSize()
// }
/**
* 获取文件扩展名,不带 .
*/
public static String getExtensionName(String filename) {
if ((filename != null) && (filename.length() > 0)) {
int dot = filename.lastIndexOf('.');
if ((dot > -1) && (dot < (filename.length() - 1))) {
return filename.substring(dot + 1);
}
}
return filename;
}
/**
* inputStream 转 File
*/
static File inputStreamToFile(InputStream ins, String name) {
File file = new File(SYS_TEM_DIR + name);
if (file.exists()) {
return file;
}
OutputStream os = null;
try {
os = new FileOutputStream(file);
int bytesRead;
int len = 8192;
byte[] buffer = new byte[len];
while ((bytesRead = ins.read(buffer, 0, len)) != -1) {
os.write(buffer, 0, bytesRead);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
CloseUtil.close(os);
CloseUtil.close(ins);
}
return file;
}
/**
* 获取文件尺寸
*/
public static FileVO getFileSize(MultipartFile file) {
int width = 0;
int height = 0;
try {
// 图片对象
BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
// 宽度
width = bufferedImage.getWidth();
// 高度
height = bufferedImage.getHeight();
} catch (IOException ioException) {
log.error("获取文件尺寸异常###{}", ExceptionUtil.stacktraceToString(ioException));
}
return new FileVO(height, width);
}
/**
* 获取文件尺寸
*/
public static FileVO getFileSize(InputStream inputStream) {
int width = 0;
int height = 0;
try {
// 图片对象
BufferedImage bufferedImage = ImageIO.read(inputStream);
// 宽度
width = bufferedImage.getWidth();
// 高度
height = bufferedImage.getHeight();
} catch (IOException ioException) {
log.error("获取文件尺寸异常###{}", ExceptionUtil.stacktraceToString(ioException));
}
return new FileVO(height, width);
}
/**
* 获取远程文件流
*/
public static InputStream getOriginFile(String path) {
try {
//远程
URL url = new URL(path);
return url.openStream();
} catch (IOException ioException) {
log.error("获取文件尺寸异常###{}###path##{}", ExceptionUtil.stacktraceToString(ioException), path);
throw new BusinessException("get.file.failed");
}
}
/**
* 将文件名解析成文件的上传路径
*/
public static File upload(MultipartFile file, String filePath) {
Date date = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmssS");
String suffix = getExtensionName(file.getOriginalFilename());
String nowStr = format.format(date) + "-";
try {
String fileName = file.getOriginalFilename();
String fileSuffix = fileName.substring(fileName.lastIndexOf("."));
String path = filePath + fileSuffix;
// getCanonicalFile 可解析正确各种路径
File dest = new File(path).getCanonicalFile();
// 检测是否存在目录
if (!dest.getParentFile().exists()) {
if (!dest.getParentFile().mkdirs()) {
System.out.println("was not successful.");
}
}
// 文件写入
file.transferTo(dest);
return dest;
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return null;
}
/**
* 将文件名解析成文件的上传路径
*/
public static File upload2(MultipartFile file, String filePath) {
Date date = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmssS");
String suffix = getExtensionName(file.getOriginalFilename());
String nowStr = format.format(date) + "-";
try {
String fileName = file.getOriginalFilename();
String path = filePath + fileName;
// getCanonicalFile 可解析正确各种路径
File dest = new File(path).getCanonicalFile();
// 检测是否存在目录
if (!dest.getParentFile().exists()) {
if (!dest.getParentFile().mkdirs()) {
System.out.println("was not successful.");
}
}
// 文件写入
file.transferTo(dest);
return dest;
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return null;
}
/**
* 删除文件
*/
public static boolean delete(String path) {
File file = new File(path);
if (file.exists()) {
return file.delete();
}
return false;
}
/**
* 获取指定文件夹下所有文件,不含文件夹里的文件
*
* @param dirFilePath 文件夹路径
* @return
*/
public static List<File> getAllFile(String dirFilePath) {
if (StrUtil.isBlank(dirFilePath)) {
return null;
}
return getAllFile(new File(dirFilePath));
}
/**
* 获取指定文件夹下所有文件,不含文件夹里的文件
*
* @param dirFile 文件夹
* @return
*/
public static List<File> getAllFile(File dirFile) {
// 如果文件夹不存在或着不是文件夹,则返回 null
if (Objects.isNull(dirFile) || !dirFile.exists() || dirFile.isFile()) {
return null;
}
File[] childrenFiles = dirFile.listFiles();
if (Objects.isNull(childrenFiles) || childrenFiles.length == 0) {
return null;
}
List<File> files = new ArrayList<>();
for (File childFile : childrenFiles) {
// 如果是文件,直接添加到结果集合
if (childFile.isFile()) {
files.add(childFile);
}
//以下几行代码取消注释后可以将所有子文件夹里的文件也获取到列表里
else {
// 如果是文件夹,则将其内部文件添加进结果集合
List<File> cFiles = getAllFile(childFile);
if (Objects.isNull(cFiles) || cFiles.isEmpty()) {
continue;
}
files.addAll(cFiles);
}
}
return files;
}
// 判断文件是否存在
public static boolean isFileExists(String filePath) {
File file = new File(filePath);
return file.exists() && file.isFile();
}
// 根据路径获取文件
public static File getFile(String filePath) {
File file = new File(filePath);
if (file.exists() && file.isFile()) {
return file;
} else {
return null;
}
}
}
package com.ai.da.common.utils;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.ai.da.common.config.exception.BusinessException;
import com.ai.da.model.vo.FileVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
public class FileUtil extends cn.hutool.core.io.FileUtil {
private static final Logger log = LoggerFactory.getLogger(com.ai.da.common.utils.FileUtil.class);
/**
* 系统临时目录
* <br>
* windows 包含路径分割符但Linux 不包含,
* 在windows \\==\ 前提下,
* 为安全起见 同意拼装 路径分割符,
* <pre>
* java.io.tmpdir
* windows : C:\Users/xxx\AppData\Local\Temp\
* linux: /temp
* </pre>
*/
public static final String SYS_TEM_DIR = System.getProperty("java.io.tmpdir") + File.separator;
/**
* 定义GB的计算常量
*/
private static final int GB = 1024 * 1024 * 1024;
/**
* 定义MB的计算常量
*/
private static final int MB = 1024 * 1024;
/**
* 定义KB的计算常量
*/
private static final int KB = 1024;
/**
* 格式化小数
*/
private static final DecimalFormat DF = new DecimalFormat("0.00");
public static final String IMAGE = "图片";
public static final String TXT = "文档";
public static final String MUSIC = "音乐";
public static final String VIDEO = "视频";
public static final String OTHER = "其他";
/**
* MultipartFile转File
*/
public static File toFile(MultipartFile multipartFile) {
// 获取文件名
String fileName = multipartFile.getOriginalFilename();
// 获取文件后缀
String prefix = "." + getExtensionName(fileName);
File file = null;
try {
// 用uuid作为文件名防止生成的临时文件重复
file = new File(SYS_TEM_DIR + IdUtil.simpleUUID() + prefix);
// MultipartFile to File
multipartFile.transferTo(file);
} catch (IOException e) {
log.error(e.getMessage(), e);
}
return file;
}
// public static void main(String[] args) {
// File file = new File(
// "http://18.162.111.141:5568/download/202211/userFile/collection/Printboard/1/a3c9838c-2171-44d7-af54-c94ee6affcd9print_2.jpg.png");
// FileUtil.getFileSize()
// }
/**
* 获取文件扩展名,不带 .
*/
public static String getExtensionName(String filename) {
if ((filename != null) && (filename.length() > 0)) {
int dot = filename.lastIndexOf('.');
if ((dot > -1) && (dot < (filename.length() - 1))) {
return filename.substring(dot + 1);
}
}
return filename;
}
/**
* inputStream 转 File
*/
static File inputStreamToFile(InputStream ins, String name) {
File file = new File(SYS_TEM_DIR + name);
if (file.exists()) {
return file;
}
OutputStream os = null;
try {
os = new FileOutputStream(file);
int bytesRead;
int len = 8192;
byte[] buffer = new byte[len];
while ((bytesRead = ins.read(buffer, 0, len)) != -1) {
os.write(buffer, 0, bytesRead);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
CloseUtil.close(os);
CloseUtil.close(ins);
}
return file;
}
/**
* 获取文件尺寸
*/
public static FileVO getFileSize(MultipartFile file) {
int width = 0;
int height = 0;
try {
// 图片对象
BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
// 宽度
width = bufferedImage.getWidth();
// 高度
height = bufferedImage.getHeight();
} catch (IOException ioException) {
log.error("获取文件尺寸异常###{}", ExceptionUtil.stacktraceToString(ioException));
}
return new FileVO(height, width);
}
/**
* 获取文件尺寸
*/
public static FileVO getFileSize(InputStream inputStream) {
int width = 0;
int height = 0;
try {
// 图片对象
BufferedImage bufferedImage = ImageIO.read(inputStream);
// 宽度
width = bufferedImage.getWidth();
// 高度
height = bufferedImage.getHeight();
} catch (IOException ioException) {
log.error("获取文件尺寸异常###{}", ExceptionUtil.stacktraceToString(ioException));
}
return new FileVO(height, width);
}
/**
* 获取远程文件流
*/
public static InputStream getOriginFile(String path) {
try {
//远程
URL url = new URL(path);
return url.openStream();
} catch (IOException ioException) {
log.error("获取文件异常###{}###path##{}", ExceptionUtil.stacktraceToString(ioException), path);
throw new BusinessException("get.file.failed");
}
}
/**
* 将文件名解析成文件的上传路径
*/
public static File upload(MultipartFile file, String filePath) {
Date date = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmssS");
String suffix = getExtensionName(file.getOriginalFilename());
String nowStr = format.format(date) + "-";
try {
String fileName = file.getOriginalFilename();
String fileSuffix = fileName.substring(fileName.lastIndexOf("."));
String path = filePath + fileSuffix;
// getCanonicalFile 可解析正确各种路径
File dest = new File(path).getCanonicalFile();
// 检测是否存在目录
if (!dest.getParentFile().exists()) {
if (!dest.getParentFile().mkdirs()) {
System.out.println("was not successful.");
}
}
// 文件写入
file.transferTo(dest);
return dest;
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return null;
}
/**
* 将文件名解析成文件的上传路径
*/
public static File upload2(MultipartFile file, String filePath) {
Date date = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmssS");
String suffix = getExtensionName(file.getOriginalFilename());
String nowStr = format.format(date) + "-";
try {
String fileName = file.getOriginalFilename();
String path = filePath + fileName;
// getCanonicalFile 可解析正确各种路径
File dest = new File(path).getCanonicalFile();
// 检测是否存在目录
if (!dest.getParentFile().exists()) {
if (!dest.getParentFile().mkdirs()) {
System.out.println("was not successful.");
}
}
// 文件写入
file.transferTo(dest);
return dest;
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return null;
}
/**
* 删除文件
*/
public static boolean delete(String path) {
File file = new File(path);
if (file.exists()) {
return file.delete();
}
return false;
}
/**
* 获取指定文件夹下所有文件,不含文件夹里的文件
*
* @param dirFilePath 文件夹路径
* @return
*/
public static List<File> getAllFile(String dirFilePath) {
if (StrUtil.isBlank(dirFilePath)) {
return null;
}
return getAllFile(new File(dirFilePath));
}
/**
* 获取指定文件夹下所有文件,不含文件夹里的文件
*
* @param dirFile 文件夹
* @return
*/
public static List<File> getAllFile(File dirFile) {
// 如果文件夹不存在或着不是文件夹,则返回 null
if (Objects.isNull(dirFile) || !dirFile.exists() || dirFile.isFile()) {
return null;
}
File[] childrenFiles = dirFile.listFiles();
if (Objects.isNull(childrenFiles) || childrenFiles.length == 0) {
return null;
}
List<File> files = new ArrayList<>();
for (File childFile : childrenFiles) {
// 如果是文件,直接添加到结果集合
if (childFile.isFile()) {
files.add(childFile);
}
//以下几行代码取消注释后可以将所有子文件夹里的文件也获取到列表里
else {
// 如果是文件夹,则将其内部文件添加进结果集合
List<File> cFiles = getAllFile(childFile);
if (Objects.isNull(cFiles) || cFiles.isEmpty()) {
continue;
}
files.addAll(cFiles);
}
}
return files;
}
// 判断文件是否存在
public static boolean isFileExists(String filePath) {
File file = new File(filePath);
return file.exists() && file.isFile();
}
// 根据路径获取文件
public static File getFile(String filePath) {
File file = new File(filePath);
if (file.exists() && file.isFile()) {
return file;
} else {
return null;
}
}
/**
* 将 FileItem 转换为 MultipartFile
* 用于 Spring Boot 3.x 兼容性CommonsMultipartFile 已移除)
*/
public static MultipartFile fileItemToMultipartFile(org.apache.commons.fileupload.FileItem fileItem) {
String fieldName = fileItem.getFieldName();
String fileName = fileItem.getName();
String contentType = fileItem.getContentType();
byte[] content = fileItem.get();
return new MockMultipartFile(fieldName, fileName, contentType, content);
}
}

View File

@@ -4,7 +4,7 @@ import com.alibaba.fastjson.JSON;
import com.ai.da.common.response.Response;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.ServletResponse;
import jakarta.servlet.ServletResponse;
import java.io.PrintWriter;

View File

@@ -28,7 +28,7 @@ public final class LocalCacheUtils {
private static LoadingCache<String, String> loadTokenCache() {
LoadingCache<String, String> tokenCache = CacheBuilder.newBuilder()
.concurrencyLevel(10)
.expireAfterWrite(24 * (7 - 1), TimeUnit.HOURS)
.expireAfterWrite(24 * 7 - 1, TimeUnit.HOURS)
.initialCapacity(100)
.maximumSize(10000)
.recordStats()

View File

@@ -0,0 +1,178 @@
package com.ai.da.common.utils;
import com.ai.da.common.constant.CommonConstant;
import com.ai.da.model.dto.BasicEmailParamDTO;
import com.alibaba.fastjson.JSONObject;
import com.sun.mail.smtp.SMTPTransport;
import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.InputStreamSource;
import org.springframework.mail.MailException;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import jakarta.annotation.Resource;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.*;
import java.util.List;
import java.util.Objects;
@Slf4j
@Component
public class MailUtil {
@Resource
private JavaMailSender javaMailSender;
@Resource
private TemplateEngine templateEngine;
/**
* 发送邮件 - 默认发件人
*
* @param basicEmailParamDTO 发送邮件所需参数
* @param inputStreamSource 附件(如果有)
*/
public int sendMail(BasicEmailParamDTO basicEmailParamDTO, String fileName, InputStreamSource inputStreamSource) throws MessagingException {
MimeMessage mimeMessage = createSimpleMail(basicEmailParamDTO, fileName, inputStreamSource);
// 提取配置
String host;
String username;
String password;
if (StringUtil.isNullOrEmpty(basicEmailParamDTO.getServiceAddress())) {
host = ((JavaMailSenderImpl) javaMailSender).getHost();
} else {
host = basicEmailParamDTO.getServiceAddress();
}
if (StringUtil.isNullOrEmpty(basicEmailParamDTO.getSenderUser())) {
username = ((JavaMailSenderImpl) javaMailSender).getUsername();
} else {
username = basicEmailParamDTO.getSenderUser();
}
if (StringUtil.isNullOrEmpty(basicEmailParamDTO.getServiceAddress())) {
password = ((JavaMailSenderImpl) javaMailSender).getPassword();
} else {
password = basicEmailParamDTO.getPassword();
}
return sendMail(mimeMessage, host, username, password);
}
private int sendMail(MimeMessage mimeMessage, String host, String username, String password) throws MessagingException {
SMTPTransport transport = null;
try {
// 获取 SMTPTransport
transport = (SMTPTransport) mimeMessage.getSession().getTransport("smtp");
// 连接到 SMTP 服务器
transport.connect(host, username, password);
// 发送邮件
transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
// 获取 SMTP 服务器的响应
String lastServerResponse = transport.getLastServerResponse();
int lastReturnCode = transport.getLastReturnCode();
log.info("SMTP 状态码: {}, SMTP 服务器响应: {}", lastReturnCode, lastServerResponse);
return lastReturnCode;
} catch (MailException | MessagingException e) {
// 记录日志或执行其他补偿逻辑
log.info("邮件发送失败:{}", e.getMessage());
} finally {
// 关闭连接
assert transport != null;
transport.close();
}
return 0;
}
/**
* 创建一封邮件
*
* @param basicEmailParamDTO 创建邮件需要的参数
* @param inputStreamSource 附件(如果有)
* @return 一封邮件
*/
private MimeMessage createSimpleMail(BasicEmailParamDTO basicEmailParamDTO, String fileName, InputStreamSource inputStreamSource) throws MessagingException {
// 创建邮件对象
MimeMessage message = javaMailSender.createMimeMessage();
// 使用 MimeMessageHelper 简化邮件内容和附件的设置
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(message, true);
// 设置发件人
mimeMessageHelper.setFrom(new InternetAddress(basicEmailParamDTO.getSenderUserMail()));
// 设置收件人
mimeMessageHelper.setTo(basicEmailParamDTO.getMailTo());
// 设置抄送人
if (basicEmailParamDTO.getCc() != null && basicEmailParamDTO.getCc().length > 0) {
mimeMessageHelper.setCc(basicEmailParamDTO.getCc());
}
// 设置暗送人
if (basicEmailParamDTO.getBcc() != null && basicEmailParamDTO.getBcc().length > 0) {
mimeMessageHelper.setBcc(basicEmailParamDTO.getBcc());
}
// 设置邮件主题
mimeMessageHelper.setSubject(basicEmailParamDTO.getSubject());
// 设置邮件内容HTML 格式)
mimeMessageHelper.setText(basicEmailParamDTO.getContent(), true);
// 设置附件
if (inputStreamSource != null) {
mimeMessageHelper.addAttachment(fileName, inputStreamSource);
}
return message;
}
/**
* 设置实体参数
*
* @param mailTo 接收邮件的邮箱地址
* @param jsonObject 模板中变量的值
* @return 返回一个MailEntity
* @throws AddressException 邮箱地址值异常
*/
public BasicEmailParamDTO setBasicEmailParams(List<String> mailTo, JSONObject jsonObject, String templatePath, String title) throws AddressException {
BasicEmailParamDTO basicEmailParamDTO = new BasicEmailParamDTO();
// basicEmailParamDTO.setSenderUserMail("info@aida.com.hk");
basicEmailParamDTO.setSenderUserMail(CommonConstant.senderEmail);
basicEmailParamDTO.setMailTo(getInternetAddressList(mailTo));
basicEmailParamDTO.setSubject(title);
// todo 邮件模板不存在的报错与重试机制
basicEmailParamDTO.setContent(setContent(jsonObject, templatePath));
return basicEmailParamDTO;
}
public BasicEmailParamDTO setBasicEmailParams(List<String> mailTo, String title) throws AddressException {
BasicEmailParamDTO basicEmailParamDTO = new BasicEmailParamDTO();
basicEmailParamDTO.setSenderUserMail("info@aida.com.hk");
basicEmailParamDTO.setMailTo(getInternetAddressList(mailTo));
basicEmailParamDTO.setSubject(title);
return basicEmailParamDTO;
}
/**
* 将地址转换为InternetAddress类型
*
* @param addressList 普通的地址字符串列表
* @return InternetAddress类型的地址列表
* @throws AddressException 地址异常
*/
public InternetAddress[] getInternetAddressList(List<String> addressList) throws AddressException {
InternetAddress[] toAddress = new InternetAddress[addressList.size()];
for (String address : addressList) {
toAddress[addressList.indexOf(address)] = new InternetAddress(address);
}
return toAddress;
}
public String setContent(JSONObject jsonObject, String templatePath) {
Context context = new Context();
if (Objects.nonNull(jsonObject)) {
for (String key : jsonObject.keySet()) {
context.setVariable(key, jsonObject.get(key));
}
}
return templateEngine.process(templatePath, context);
}
}

View File

@@ -1,25 +1,33 @@
package com.ai.da.common.utils;
import com.ai.da.common.config.exception.BusinessException;
import com.ai.da.common.constant.CommonConstant;
import com.ai.da.common.response.ResultEnum;
import com.ai.da.mapper.primary.entity.ObjectItem;
import io.minio.*;
import io.minio.errors.MinioException;
import io.minio.errors.*;
import io.minio.http.Method;
import io.minio.messages.DeleteError;
import io.minio.messages.DeleteObject;
import io.minio.messages.Item;
import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.io.*;
import java.net.URL;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -33,6 +41,13 @@ public class MinioUtil {
@Autowired
private MinioClient minioClient;
/**
* 获取MinIO客户端实例
*/
public MinioClient getMinioClient() {
return minioClient;
}
/**
* description: 判断bucket是否存在不存在则创建
*
@@ -356,7 +371,7 @@ public class MinioUtil {
public void deleteObject(String path) {
if (!path.contains("/")) {
throw new BusinessException("The path is error!");
throw new BusinessException("the.path.is.error");
}
int index = path.indexOf("/");
String bucketName = path.substring(0, index);
@@ -374,16 +389,38 @@ public class MinioUtil {
*/
public String getPreSignedUrl(String bucketName, String fileName, int expiry) {
try {
return minioClient.getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder()
.bucket(bucketName)
.object(fileName)
.expiry(expiry, TimeUnit.MINUTES)
.method(Method.GET)
.build()
);
} catch (MinioException | InvalidKeyException | IOException | NoSuchAlgorithmException e) {
String lowerName = fileName.toLowerCase();
boolean isImage = lowerName.endsWith(".jpg") || lowerName.endsWith(".jpeg")
|| lowerName.endsWith(".png") || lowerName.endsWith(".gif");
GetPresignedObjectUrlArgs.Builder builder = GetPresignedObjectUrlArgs.builder()
.bucket(bucketName)
.object(fileName)
.expiry(expiry, TimeUnit.MINUTES)
.method(Method.GET);
if (isImage) {
// 根据后缀名设置正确的 content-type
String contentType = "image/jpeg";
if (lowerName.endsWith(".png")) {
contentType = "image/png";
} else if (lowerName.endsWith(".gif")) { // 新增 GIF
contentType = "image/gif";
}
Map<String, String> queryParams = new HashMap<>();
queryParams.put("response-content-type", contentType);
queryParams.put("response-content-disposition", "inline");
builder.extraQueryParams(queryParams);
}
return minioClient.getPresignedObjectUrl(builder.build());
} catch (MinioException | InvalidKeyException
| IOException | NoSuchAlgorithmException | IllegalArgumentException e) {
e.printStackTrace();
log.error("bucket: {}, object:{}", bucketName, fileName);
throw new BusinessException(e.getMessage());
}
}
@@ -393,7 +430,7 @@ public class MinioUtil {
return LocalCacheUtils.getPresignedUrlCache(path);
} else {
if (!path.contains("/")) {
throw new BusinessException("The path is error!");
throw new BusinessException("the.path.is.error");
}
int index = path.indexOf("/");
String bucketName = path.substring(0, index);
@@ -407,7 +444,7 @@ public class MinioUtil {
public String getPreSignedUrl(String path, int expiry, boolean resetCache) {
if (resetCache || LocalCacheUtils.getPresignedUrlCache(path) == null) {
if (!path.contains("/")) {
throw new BusinessException("The path is error!");
throw new BusinessException("the.path.is.error");
}
int index = path.indexOf("/");
String bucketName = path.substring(0, index);
@@ -489,6 +526,7 @@ public class MinioUtil {
return bucketName + "/" + fileName;
} catch (Exception e) {
log.info("base64上传minio失败:{}",e.getMessage());
log.error(e.getMessage());
return null; // or throw an exception
}
@@ -570,6 +608,356 @@ public class MinioUtil {
throw new BusinessException(e.getMessage());
}
}
public void upload(String url, File file) {
try {
// 分割桶名和对象路径
int firstSlashIndex = url.indexOf("/");
if (firstSlashIndex == -1) {
throw new IllegalArgumentException("URL 格式不正确,无法解析桶名和对象路径");
}
String bucketName = url.substring(0, firstSlashIndex);
String objectName = url.substring(firstSlashIndex + 1);
// 读取文件流
try (FileInputStream fileInputStream = new FileInputStream(file)) {
// 上传到 MinIO
minioClient.putObject(
PutObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.stream(fileInputStream, file.length(), -1)
.contentType("application/zip")
.build()
);
System.out.println("文件上传成功: " + url);
}
} catch (Exception e) {
e.printStackTrace();
System.err.println("文件上传失败: " + e.getMessage());
}
}
public String getImageAsBase64(String path) throws IOException {
int index = path.indexOf("/");
String bucketName = path.substring(0, index);
String fileName = path.substring(index + 1);
// 检查桶是否存在
boolean found = doesObjectExist(bucketName, fileName);
if (!found) {
throw new IOException("Bucket " + bucketName + " does not exist");
}
try (InputStream stream = minioClient.getObject(
GetObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.build())) {
byte[] bytes = IOUtils.toByteArray(stream);
return Base64.getEncoder().encodeToString(bytes);
} catch (ServerException e) {
throw new RuntimeException(e);
} catch (InsufficientDataException e) {
throw new RuntimeException(e);
} catch (ErrorResponseException e) {
throw new RuntimeException(e);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
} catch (InvalidKeyException e) {
throw new RuntimeException(e);
} catch (InvalidResponseException e) {
throw new RuntimeException(e);
} catch (XmlParserException e) {
throw new RuntimeException(e);
} catch (InternalException e) {
throw new RuntimeException(e);
}
}
/**
* 获取压缩后的图片Base64编码
* @param path 图片的minio路径
* @param targetWidth 目标宽度
* @param targetHeight 目标高度
* @return 压缩后的图片Base64编码
* @throws IOException
*/
public String getCompressedImageAsBase64(String path, int targetWidth, int targetHeight) throws IOException {
int index = path.indexOf("/");
String bucketName = path.substring(0, index);
String fileName = path.substring(index + 1);
// 检查桶是否存在
boolean found = doesObjectExist(bucketName, fileName);
if (!found) {
throw new IOException("Bucket " + bucketName + " does not exist");
}
try (InputStream stream = minioClient.getObject(
GetObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.build())) {
// 读取原始图片
BufferedImage originalImage = ImageIO.read(stream);
if (originalImage == null) {
throw new IOException("无法读取图片: " + path);
}
// 计算压缩比例,保持宽高比
int originalWidth = originalImage.getWidth();
int originalHeight = originalImage.getHeight();
double scaleX = (double) targetWidth / originalWidth;
double scaleY = (double) targetHeight / originalHeight;
double scale = Math.min(scaleX, scaleY); // 选择较小的缩放比例以保持宽高比
int newWidth = (int) (originalWidth * scale);
int newHeight = (int) (originalHeight * scale);
// 创建压缩后的图片
BufferedImage compressedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = compressedImage.createGraphics();
// 设置高质量渲染
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// 绘制压缩后的图片
g2d.drawImage(originalImage, 0, 0, newWidth, newHeight, null);
g2d.dispose();
// 转换为Base64
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(compressedImage, "JPEG", baos); // 使用JPEG格式以减小文件大小
byte[] imageBytes = baos.toByteArray();
log.info("图片压缩完成: {} -> {}x{} (原始: {}x{})", path, newWidth, newHeight, originalWidth, originalHeight);
return Base64.getEncoder().encodeToString(imageBytes);
} catch (ServerException e) {
throw new RuntimeException(e);
} catch (InsufficientDataException e) {
throw new RuntimeException(e);
} catch (ErrorResponseException e) {
throw new RuntimeException(e);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
} catch (InvalidKeyException e) {
throw new RuntimeException(e);
} catch (InvalidResponseException e) {
throw new RuntimeException(e);
} catch (XmlParserException e) {
throw new RuntimeException(e);
} catch (InternalException e) {
throw new RuntimeException(e);
}
}
/**
* 压缩base64格式的图片
* @param base64Image 包含前缀的base64图片字符串 (如: "data:image/png;base64,...")
* @param targetWidth 目标宽度
* @param targetHeight 目标高度
* @return 压缩后的base64图片字符串保持原有前缀格式
*/
public String compressBase64Image(String base64Image, int targetWidth, int targetHeight) {
if (base64Image == null || base64Image.isEmpty()) {
return base64Image;
}
try {
// 解析base64字符串
String[] parts = base64Image.split(",");
if (parts.length != 2) {
log.warn("无效的base64图片格式: {}", base64Image.substring(0, Math.min(50, base64Image.length())));
return base64Image;
}
String prefix = parts[0] + ","; // 保留前缀,如 "data:image/png;base64,"
String base64Data = parts[1];
// 解码base64数据
byte[] imageBytes = Base64.getDecoder().decode(base64Data);
// 读取图片
BufferedImage originalImage = ImageIO.read(new ByteArrayInputStream(imageBytes));
if (originalImage == null) {
log.warn("无法读取base64图片数据");
return base64Image;
}
// 计算压缩比例,保持宽高比
int originalWidth = originalImage.getWidth();
int originalHeight = originalImage.getHeight();
double scaleX = (double) targetWidth / originalWidth;
double scaleY = (double) targetHeight / originalHeight;
double scale = Math.min(scaleX, scaleY); // 选择较小的缩放比例以保持宽高比
int newWidth = (int) (originalWidth * scale);
int newHeight = (int) (originalHeight * scale);
// 如果图片已经比目标尺寸小,则不进行压缩
if (scale >= 1.0) {
log.info("图片尺寸 {}x{} 已小于目标尺寸 {}x{},无需压缩", originalWidth, originalHeight, targetWidth, targetHeight);
return base64Image;
}
// 创建压缩后的图片
BufferedImage compressedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = compressedImage.createGraphics();
// 设置高质量渲染
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// 绘制压缩后的图片
g2d.drawImage(originalImage, 0, 0, newWidth, newHeight, null);
g2d.dispose();
// 转换为Base64
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(compressedImage, "PNG", baos); // 保持PNG格式以支持透明度
byte[] compressedBytes = baos.toByteArray();
String compressedBase64 = Base64.getEncoder().encodeToString(compressedBytes);
log.info("Base64图片压缩完成: {}x{} -> {}x{} (压缩比: {:.2f})",
originalWidth, originalHeight, newWidth, newHeight, scale);
return prefix + compressedBase64;
} catch (Exception e) {
log.error("压缩base64图片失败", e);
return base64Image; // 出错时返回原图
}
}
public void uploadToMinio(byte[] data, String bucket, String objectName, String contentType) /*throws Exception*/ {
try {
minioClient.putObject(PutObjectArgs.builder()
.bucket(bucket)
.object(objectName)
.stream(new ByteArrayInputStream(data), data.length, -1)
.contentType(contentType)
.build());
} catch (MinioException | IOException | NoSuchAlgorithmException | InvalidKeyException e){
log.error("图片上传到minio出错{}", e.getMessage());
throw new BusinessException("file.upload.fail");
}
}
public String changeToWhiteBackground(String minioPath){
try {
// 1. 使用URL读取远程图片
BufferedImage originalImage = ImageIO.read(new URL(getPreSignedUrl(minioPath, CommonConstant.MINIO_IMAGE_EXPIRE_TIME)));
// 2. 透明图检查(新增核心逻辑)
if (!hasTransparency(originalImage)) {
log.info("图片 {} 无透明通道,无需添加白底", minioPath);
return null; // 返回空
}
// 3. 处理图片(例如:转换为白底)
BufferedImage newImage = new BufferedImage(
originalImage.getWidth(),
originalImage.getHeight(),
BufferedImage.TYPE_INT_RGB
);
// 4. 填充白色背景
java.awt.Graphics2D g = newImage.createGraphics();
g.setColor(java.awt.Color.WHITE);
g.fillRect(0, 0, newImage.getWidth(), newImage.getHeight());
g.drawImage(originalImage, 0, 0, null);
g.dispose();
// 5. 输出为Base64
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(newImage, "PNG", baos);
String base64Image = java.util.Base64.getEncoder().encodeToString(baos.toByteArray());
log.info("为图片 {} 添加白色背景", minioPath);
// System.out.println("data:image/png;base64," + base64Image);
return "data:image/png;base64," + base64Image;
// return base64Image;
} catch (Exception e) {
log.error(e.getMessage());
throw new BusinessException("white.bg.add.fail", ResultEnum.PROMPT.getCode());
}
}
/**
* 检测图片是否包含透明通道
*/
private boolean hasTransparency(BufferedImage image) {
// 情况1图像本身支持透明如TYPE_INT_ARGB
if (image.getTransparency() == Transparency.TRANSLUCENT) {
return true;
}
// 情况2检查像素级透明度适用于TYPE_INT_RGB等格式
if (image.getColorModel().hasAlpha()) {
// 抽样检查前100x100像素避免全图扫描的性能问题
int width = Math.min(image.getWidth(), 100);
int height = Math.min(image.getHeight(), 100);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
if ((image.getRGB(x, y) >> 24) == 0x00) {
return true; // 发现透明像素
}
}
}
}
return false;
}
/**
* 将A桶中的对象复制到B桶中
* @return
*/
public void copyObject(String sourceBucket, String sourceObject, String targetBucket, String targetObject) {
// 检查目标桶是否存在
boolean found;
try {
found = minioClient.bucketExists(BucketExistsArgs.builder()
.bucket(targetBucket)
.build());
} catch (Exception e) {
log.error("目标桶{},不存在", targetBucket);
throw new BusinessException("Copy object failed");
}
if (found) {
// 复制对象
try {
minioClient.copyObject(
CopyObjectArgs.builder()
.bucket(targetBucket)
.object(targetObject)
.source(
CopySource.builder()
.bucket(sourceBucket)
.object(sourceObject)
.build()
)
.build()
);
} catch (Exception e) {
log.error("对象复制失败");
throw new BusinessException("Copy object failed");
}
log.info("对象复制成功");
} else {
log.error("目标桶{},不存在", targetBucket);
throw new BusinessException("Copy object failed");
}
}
}

View File

@@ -3,11 +3,11 @@ package com.ai.da.common.utils;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;

View File

@@ -3,10 +3,10 @@ package com.ai.da.common.utils;
import lombok.AllArgsConstructor;
import lombok.Data;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.WriteListener;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletResponseWrapper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

View File

@@ -1,13 +1,27 @@
package com.ai.da.common.utils;
import com.ai.da.model.dto.ProgressDTO;
import com.ai.da.python.vo.DesignPythonObject;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.HashOperations;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import jakarta.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -19,6 +33,13 @@ public class RedisUtil {
@Resource
private RedisTemplate<String, String> redisTemplate;
public final static String FLUX_POLLING_URL = "Flux:";
/**
* 登录 token 在 Redis 中的前缀:
* 最终 key 结构为 login:token:{userId}
*/
public final static String LOGIN_TOKEN_KEY = "login:token:";
public Boolean hasKey(String key){
return redisTemplate.hasKey(key);
}
@@ -81,6 +102,8 @@ public class RedisUtil {
//- - - - - - - - - - - - - - - - - - - - - set类型 - - - - - - - - - - - - - - - - - - - -
public final static String VIDEO_FINISHED_TASKS = "VideoFinishedTasks";
/**
* 将数据放入set缓存
*/
@@ -168,6 +191,40 @@ public class RedisUtil {
redisTemplate.delete(key);
}
/**
* 保存登录 token
*
* @param userId 用户 ID
* @param token token 字符串
* @param expireMillis 过期时间(毫秒,通常与 JWT 保持一致)
*/
public void setLoginToken(Long userId, String token, long expireMillis) {
if (expireMillis <= 0) {
// 不设置过期时间,直到手动删除(不推荐)
addToString(LOGIN_TOKEN_KEY + userId, token);
return;
}
long expireSeconds = expireMillis / 1000;
if (expireSeconds <= 0) {
expireSeconds = 1;
}
addToString(LOGIN_TOKEN_KEY + userId, token, expireSeconds);
}
/**
* 获取登录 token
*/
public String getLoginToken(Long userId) {
return getFromString(LOGIN_TOKEN_KEY + userId);
}
/**
* 删除登录 token
*/
public void deleteLoginToken(Long userId) {
removeFromString(LOGIN_TOKEN_KEY + userId);
}
public final static String PORTFOLIO_LIKE_KEY = "portfolio:like:";
public void likePost(Long portfolioId, Long userId) {
@@ -253,8 +310,9 @@ public class RedisUtil {
return getFromString(MOODBOARD_POSITION_KEY + id);
}
public final static String NICKNAME_MODIFY_TIMES = "NicknameModifyTimes:";
public void increaseCount(String key) {
redisTemplate.opsForValue().increment(key);
public final static String UNNAMED_PROJECT_SEQ = "Project:UnnamedProjectSeq:";
public Long increaseCount(String key) {
return redisTemplate.opsForValue().increment(key);
}
public Long getIncrementCount(String key) {
@@ -281,6 +339,77 @@ public class RedisUtil {
redisTemplate.expire(redisKey, 5, TimeUnit.MINUTES);
}
public void addPathToCache(Long collectionId, Long userId, String path) {
// Redis 中的键,唯一标识由 collectionId 和 userId 组成
String redisKey = "path:cache:" + collectionId + ":" + userId;
// 增加路径的计数
redisTemplate.opsForHash().increment(redisKey, path, 1);
// 设置过期时间为 2 小时7200 秒)
redisTemplate.expire(redisKey, 8, TimeUnit.HOURS);
}
public int getPathUsageCount(Long collectionId, Long userId, String path) {
String redisKey = "path:cache:" + collectionId + ":" + userId;
// 获取路径的使用次数
Object count = redisTemplate.opsForHash().get(redisKey, path);
return count != null ? Integer.parseInt(count.toString()) : 0;
}
public void addAssembledObjects(Long collectionId, Set<DesignPythonObject> assembledObjects) {
// Redis 中的键,使用 collectionId 来唯一标识
String redisKey = "collection:assembledObjects:" + collectionId;
// 将 assembledObjects 转换为 JSON 格式存储,避免直接存储对象
String assembledObjectsJson = convertToJson(assembledObjects);
// 使用 Redis 的 set 操作更新集合
redisTemplate.opsForValue().set(redisKey, assembledObjectsJson);
// 设置过期时间为 5 分钟300 秒)
redisTemplate.expire(redisKey, 30, TimeUnit.MINUTES);
}
// 将 Set<DesignPythonObject> 转换为 JSON 格式
private String convertToJson(Set<DesignPythonObject> assembledObjects) {
try {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(assembledObjects);
} catch (JsonProcessingException e) {
e.printStackTrace();
return null;
}
}
public Set<DesignPythonObject> getAssembledObjects(Long collectionId) {
// Redis 中的键,使用 collectionId 来唯一标识
String redisKey = "collection:assembledObjects:" + collectionId;
// 从 Redis 获取存储的 JSON 字符串
String assembledObjectsJson = (String) redisTemplate.opsForValue().get(redisKey);
if (assembledObjectsJson == null) {
return new HashSet<>(); // 如果没有找到数据,返回一个空的 Set
}
// 将 JSON 字符串转换为 Set<DesignPythonObject>
return convertFromJson(assembledObjectsJson);
}
// 将 JSON 字符串转换为 Set<DesignPythonObject>
private Set<DesignPythonObject> convertFromJson(String json) {
try {
ObjectMapper objectMapper = new ObjectMapper();
// 使用 TypeReference 来指定目标类型是 Set<DesignPythonObject>
return objectMapper.readValue(json, new TypeReference<Set<DesignPythonObject>>() {});
} catch (JsonProcessingException e) {
e.printStackTrace();
return new HashSet<>(); // 如果转换失败,返回空的 Set
}
}
public final static String PAYMENT_INFO_LAST_SCAN_TIME = "PaymentInfoLastScanTime";
public final static String AFFILIATE_LINK_VIEW_KEY = "AffiliateLink:view:";
@@ -295,6 +424,131 @@ public class RedisUtil {
return redisTemplate.opsForValue().increment(key, 0);
}
/**
* 记录任务的耗时到Redis
* @param taskKey 任务标识,如 "taskA"
* @param elapsedTime 本次耗时,单位为毫秒
*/
public void recordTaskElapsedTime(String taskKey, long elapsedTime) {
String hashKey = "task:stats";
// 累加总耗时
redisTemplate.opsForHash().increment(hashKey, taskKey + ":totalTime", elapsedTime);
// 增加计数器
redisTemplate.opsForHash().increment(hashKey, taskKey + ":count", 1);
}
/**
* 获取任务的平均耗时
* @param taskKey 任务标识,如 "taskA"
* @return 平均耗时(毫秒)
*/
public double getTaskAverageTime(String taskKey) {
String hashKey = "task:stats";
// 获取总耗时和计数
Object totalTime = redisTemplate.opsForHash().get(hashKey, taskKey + ":totalTime");
Object count = redisTemplate.opsForHash().get(hashKey, taskKey + ":count");
// 计算平均值
if (totalTime == null || count == null) {
return 0;
}
return Double.parseDouble(totalTime.toString()) / Long.parseLong(count.toString());
}
/**
* 清除指定任务的统计数据
* @param taskKey 任务标识,如 "taskA"
*/
public void clearTaskStats(String taskKey) {
String hashKey = "task:stats";
// 删除总耗时和计数器
redisTemplate.opsForHash().delete(hashKey, taskKey + ":totalTime", taskKey + ":count");
}
public void recordTaskElapsedTime(String taskKey, double elapsedTimeInSeconds) {
// 将耗时转换为 BigDecimal并四舍五入保留四位小数
BigDecimal elapsedTime = new BigDecimal(elapsedTimeInSeconds).setScale(4, RoundingMode.HALF_UP);
// 累加总耗时(以毫秒为单位)
redisTemplate.opsForHash().increment("task:stats", taskKey + ":totalTime", elapsedTime.doubleValue());
// 增加计数器
redisTemplate.opsForHash().increment("task:stats", taskKey + ":count", 1);
}
// 获取第一部分Sketch耗时
public double getFirstSketchTime() {
// 获取 "firstSketchTime:totalTime" 对应的值,并返回(单位为秒)
Object time = redisTemplate.opsForHash().get("task:stats", "firstSketchTime:totalTime");
return time != null ? (double) time : 0.0;
}
// 获取第二部分(获取特征值)耗时
public double getGetAttributeRecognitionTime() {
// 获取 "getAttributeRecognitionTime:totalTime" 对应的值,并返回(单位为秒)
Object time = redisTemplate.opsForHash().get("task:stats", "getAttributeRecognitionTime:totalTime");
return time != null ? (double) time : 0.0;
}
// 获取第三部分(搭配 Sketch耗时
public double getOtherSketchTime() {
// 获取 "otherSketchTime:totalTime" 对应的值,并返回(单位为秒)
Object time = redisTemplate.opsForHash().get("task:stats", "otherSketchTime:totalTime");
return time != null ? (double) time : 0.0;
}
// 清理三部分的缓存
public void clearTaskElapsedTimeCache() {
// 删除第一部分的缓存
redisTemplate.opsForHash().delete("task:stats", "firstSketchTime:totalTime");
redisTemplate.opsForHash().delete("task:stats", "firstSketchTime:count");
// 删除第二部分的缓存
redisTemplate.opsForHash().delete("task:stats", "getAttributeRecognitionTime:totalTime");
redisTemplate.opsForHash().delete("task:stats", "getAttributeRecognitionTime:count");
// 删除第三部分的缓存
redisTemplate.opsForHash().delete("task:stats", "otherSketchTime:totalTime");
redisTemplate.opsForHash().delete("task:stats", "otherSketchTime:count");
}
public boolean incrementLikeCount(Long userId, String sketchPath) {
String redisKey = "user_like_count:" + userId;
try {
redisTemplate.opsForHash().increment(redisKey, sketchPath, 1);
return true;
} catch (Exception e) {
log.error("Error incrementing like count for userId {} and sketchPath {}: {}", userId, sketchPath, e.getMessage());
return false;
}
}
public int getLikeCount(Long userId, String sketchPath) {
String redisKey = "user_like_count:" + userId;
Object count = redisTemplate.opsForHash().get(redisKey, sketchPath);
return count != null ? Integer.parseInt(count.toString()) : 0;
}
public void storeMaxLikeCount(Long userId, int maxLikeCount) {
String redisKey = "user_max_like_count:" + userId;
redisTemplate.opsForValue().set(redisKey, String.valueOf(maxLikeCount));
}
public int getMaxLikeCount(Long userId) {
String redisKey = "user_max_like_count:" + userId;
String maxLikeCount = redisTemplate.opsForValue().get(redisKey);
return maxLikeCount != null ? Integer.parseInt(maxLikeCount) : 0;
}
public final static String IMAGE_SEGMENTATION = "ImageSegmentation:";
public final static String STRIPE_EXCEPTION_LOG = "StripeException:";
public final static String SUBSCRIPTION_SENT_EMAIL_TYPE = "SubscriptionEmailSentType:";
public void batchDeleteKeysWithSamePrefix(String prefix){
Set<String> keys = redisTemplate.keys(prefix + "*");
assert keys != null;
@@ -303,6 +557,103 @@ public class RedisUtil {
}
}
public final static String STRIPE_EXCEPTION_LOG = "StripeException:";
public final static String SUBSCRIPTION_SENT_EMAIL_TYPE = "SubscriptionEmailSentType:";
}
public void setTaskProgressDTO(String taskId, ProgressDTO dto) {
String key = "task:progress:" + taskId;
redisTemplate.opsForValue().set(key, JSON.toJSONString(dto), Duration.ofDays(1));
}
public ProgressDTO getTaskProgressDTO(String taskId) {
String key = "task:progress:" + taskId;
String json = redisTemplate.opsForValue().get(key);
if (StringUtils.isBlank(json)) {
// return new ProgressDTO(0, 0, false);
return null;
}
try {
return JSON.parseObject(json, ProgressDTO.class);
} catch (Exception e) {
log.warn("任务进度解析失败 key={}, json={}", key, json);
return new ProgressDTO(0, 0, false, null);
}
}
// Lua脚本原子化操作
/*private static final String RATE_LIMIT_SCRIPT =
"local current = redis.call('INCR', KEYS[1])\n" +
"if tonumber(current) == 1 then\n" +
" redis.call('EXPIRE', KEYS[1], ARGV[1])\n" +
"end\n" +
"return tonumber(current) <= tonumber(ARGV[2])";*/
private static final String RATE_LIMIT_SCRIPT =
"local current = redis.call('INCR', KEYS[1])\n" +
"local ttl = redis.call('TTL', KEYS[1])\n" +
"if tonumber(current) == 1 or tonumber(ttl) == -1 then\n" +
" redis.call('EXPIRE', KEYS[1], ARGV[1])\n" +
"end\n" +
"return tonumber(current) <= tonumber(ARGV[2])";
/**
* 检查是否允许发送
* @param userId 用户ID
* @return true-允许发送false-已超限
*/
public boolean allowSend(Long userId) {
String hourKey = getCurrentHourKey(userId);
// 执行Lua脚本
List<String> keys = Collections.singletonList(hourKey);
List<Long> args = Arrays.asList(
3600L, // 1小时过期
10L // 限制数量 一小时只能向普通用户发10封
);
Boolean result = redisTemplate.execute(
new DefaultRedisScript<>(RATE_LIMIT_SCRIPT, Boolean.class),
keys,
args.toArray()
);
return Boolean.TRUE.equals(result);
}
/**
* 获取当前小时的Key
* 格式email_limit:{userId}:{yyyyMMddHH}
*/
private String getCurrentHourKey(Long userId) {
String hour = LocalDateTime.now()
.format(DateTimeFormatter.ofPattern("yyyyMMddHH"));
return String.format("email_limit:%s:%s", userId, hour);
}
/**
* 获取当前已发送数量
*/
public int getCurrentCount(Long userId) {
String key = getCurrentHourKey(userId);
String val = redisTemplate.opsForValue().get(key);
int count;
if (StringUtils.isBlank(val)){
count = 0;
}else {
count = Integer.parseInt(val);
}
return count;
}
public boolean allowRequest(String apiKey) {
String key = "rate_limit:" + apiKey;
ValueOperations<String, String> ops = redisTemplate.opsForValue();
// 使用Redis的INCR命令
Long count = ops.increment(key, 1);
if (count == 1) {
// 第一次调用,设置过期时间
redisTemplate.expire(key, 1, TimeUnit.MINUTES);
}
return count <= 3;
}
}

View File

@@ -0,0 +1,743 @@
package com.ai.da.common.utils;
import com.ai.da.model.dto.ProgressDTO;
import com.ai.da.python.vo.DesignPythonObject;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import jakarta.annotation.PostConstruct;
import jakarta.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.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Slf4j
@Component
public class RedisUtilEnhance {
@Resource
private RedisTemplate<String, Object> redisTemplate;
private ValueOperations<String, Object> valueOperations;
private SetOperations<String, Object> setOperations;
private HashOperations<String, Object, Object> hashOperations;
private ZSetOperations<String, Object> zSetOperations;
@PostConstruct
public void init() {
this.valueOperations = redisTemplate.opsForValue();
this.setOperations = redisTemplate.opsForSet();
this.hashOperations = redisTemplate.opsForHash();
this.zSetOperations = redisTemplate.opsForZSet();
}
public final static String FLUX_POLLING_URL = "Flux:";
public Boolean hasKey(String key) {
return redisTemplate.hasKey(key);
}
//- - - - - - - - - - - - - - - - - - - - - ZSet类型 - - - - - - - - - - - - - - - - - - - -
/**
* 向ZSet中添加元素
*/
public void addToZSet(String key, Object value, Double score) {
zSetOperations.add(key, value, score);
}
/**
* 从ZSet中删除元素
*/
public void removeFromZSet(String key, Object value) {
zSetOperations.remove(key, value);
}
/**
* 获取指定元素的当前排列顺序
*/
public Long getRank(String key, Object value) {
return zSetOperations.rank(key, value);
}
/**
* 获取当前ZSet中的最大score
*/
public Double getMaxScore(String key) {
Set<ZSetOperations.TypedTuple<Object>> set = zSetOperations.reverseRangeWithScores(key, 0, 0);
if (!CollectionUtils.isEmpty(set)) {
Iterator<ZSetOperations.TypedTuple<Object>> iterator = set.iterator();
if (iterator.hasNext()) {
Double score = iterator.next().getScore();
return score != null ? score + 1.0 : 1.0;
}
}
return 1.0;
}
/**
* 判断元素是否存在
*/
public Boolean isElementExistsInZSet(String key, Object value) {
return zSetOperations.score(key, value) != null;
}
/**
* 获取当前ZSet中数据量的总和
*/
public Long getZSetTotalCount(String key) {
return zSetOperations.zCard(key);
}
public Set<Object> getZSetTotalData(String key) {
return zSetOperations.range(key, 0, -1);
}
//- - - - - - - - - - - - - - - - - - - - - set类型 - - - - - - - - - - - - - - - - - - - -
/**
* 将数据放入set缓存
*/
public void addToSet(String key, Object value) {
setOperations.add(key, value);
}
/**
* 弹出变量中的元素
*/
public void removeFromSet(String key, Object value) {
setOperations.remove(key, value);
}
/**
* 检查给定的元素是否在变量中。
*/
public Boolean isElementExistsInSet(String key, Object obj) {
return setOperations.isMember(key, obj);
}
//- - - - - - - - - - - - - - - - - - - - - hash类型 - - - - - - - - - - - - - - - - - - - -
/**
* 加入缓存
*/
public void addToMap(String key, Map<String, String> map) {
hashOperations.putAll(key, map);
}
/**
* 验证指定 key 下 有没有指定的 hashkey
*/
public Boolean isElementExistsInMap(String key, Object hashKey) {
return hashOperations.hasKey(key, hashKey);
}
/**
* 获取指定key的值string
*/
public String getMapValue(String key1, Object key2) {
Object value = hashOperations.get(key1, key2);
return value != null ? value.toString() : null;
}
/**
* 删除指定 hash 的 HashKey
*
* @return 删除成功的 数量
*/
public Long removeFromMap(String key, Object hashKeys) {
return hashOperations.delete(key, hashKeys);
}
//- - - - - - - - - - - - - - - - - - - - - String/Long/Integer类型支持 - - - - - - - - - - - - - - - - - - - -
/**
* 设置字符串值
*/
public void setString(String key, String value) {
valueOperations.set(key, value);
}
/**
* 设置字符串值并设置过期时间
*/
public void setString(String key, String value, long timeout, TimeUnit unit) {
valueOperations.set(key, value, timeout, unit);
}
/**
* 设置Long值
*/
public void setLong(String key, Long value) {
valueOperations.set(key, value);
}
/**
* 设置Long值并设置过期时间
*/
public void setLong(String key, Long value, long timeout, TimeUnit unit) {
valueOperations.set(key, value, timeout, unit);
}
/**
* 设置Integer值
*/
public void setInteger(String key, Integer value) {
valueOperations.set(key, value);
}
/**
* 设置Integer值并设置过期时间
*/
public void setInteger(String key, Integer value, long timeout, TimeUnit unit) {
valueOperations.set(key, value, timeout, unit);
}
/**
* 设置对象值
*/
public void setObject(String key, Object value, long timeout, TimeUnit unit) {
valueOperations.set(key, value, timeout, unit);
}
/**
* 获取字符串值
*/
public String getString(String key) {
Object value = valueOperations.get(key);
return value != null ? value.toString() : null;
}
/**
* 获取Long值
*/
public Long getLong(String key) {
Object value = valueOperations.get(key);
if (value instanceof Long) {
return (Long) value;
} else if (value instanceof Integer) {
return ((Integer) value).longValue();
} else if (value instanceof String) {
try {
return Long.parseLong((String) value);
} catch (NumberFormatException e) {
log.warn("无法将字符串转换为Long: key={}, value={}", key, value);
return null;
}
} else if (value != null) {
log.warn("不支持的类型转换到Long: key={}, type={}", key, value.getClass().getName());
}
return null;
}
/**
* 获取Long值带默认值
*/
public Long getLong(String key, Long defaultValue) {
try {
Long value = getLong(key);
return value != null ? value : defaultValue;
} catch (Exception e) {
log.warn("获取Long值失败: key={}", key, e);
return defaultValue;
}
}
/**
* 获取Integer值
*/
public Integer getInteger(String key) {
Object value = valueOperations.get(key);
if (value instanceof Integer) {
return (Integer) value;
} else if (value instanceof Long) {
return ((Long) value).intValue();
} else if (value instanceof String) {
try {
return Integer.parseInt((String) value);
} catch (NumberFormatException e) {
log.warn("无法将字符串转换为Integer: key={}, value={}", key, value);
return null;
}
} else if (value != null) {
log.warn("不支持的类型转换到Integer: key={}, type={}", key, value.getClass().getName());
}
return null;
}
/**
* 获取Integer值带默认值
*/
public Integer getInteger(String key, Integer defaultValue) {
try {
Integer value = getInteger(key);
return value != null ? value : defaultValue;
} catch (Exception e) {
log.warn("获取Integer值失败: key={}", key, e);
return defaultValue;
}
}
/**
* 递增操作
*/
public Long increment(String key, long delta) {
return valueOperations.increment(key, delta);
}
/**
* 递增操作double
*/
public Double increment(String key, double delta) {
return valueOperations.increment(key, delta);
}
//- - - - - - - - - - - - - - - - - - - - - 原有方法适配 - - - - - - - - - - - - - - - - - - - -
public void addToString(String key, String value) {
setString(key, value);
}
public void addToString(String key, String value, Long expiresIn) {
setString(key, value, expiresIn, TimeUnit.SECONDS);
}
public String getFromString(String key) {
return getString(key);
}
public Set<String> getKeysFromString(String pattern) {
Set<String> keys = redisTemplate.keys(pattern);
return keys != null ? keys : Collections.emptySet();
}
public Long getSize(String key) {
return setOperations.size(key);
}
public List<Object> getMultiValue(Set<String> keys) {
return valueOperations.multiGet(keys);
}
public Long getExpire(String key) {
return redisTemplate.getExpire(key);
}
public void removeFromString(String key) {
redisTemplate.delete(key);
}
public final static String PORTFOLIO_LIKE_KEY = "portfolio:like:";
public void likePost(Long portfolioId, Long userId) {
setOperations.add(PORTFOLIO_LIKE_KEY + portfolioId, userId.toString());
}
public Long getLikeCount(Long portfolioId) {
String key = PORTFOLIO_LIKE_KEY + portfolioId;
return setOperations.size(key);
}
public List<Long> getLikedPortfolios(Long userId) {
// 获取所有包含PORTFOLIO_LIKE_KEY的键
Set<String> likedPortfolios = redisTemplate.keys(PORTFOLIO_LIKE_KEY + "*");
// 如果没有喜欢的,返回空列表
if (likedPortfolios == null || likedPortfolios.isEmpty()) {
return new ArrayList<>();
}
// 过滤出包含指定用户ID的键并提取投资组合ID
return likedPortfolios.stream()
.filter(key -> setOperations.isMember(key, userId.toString()))
.map(key -> Long.valueOf(key.replace(PORTFOLIO_LIKE_KEY, "")))
.collect(Collectors.toList());
}
public void unLikePost(Long portfolioId, Long userId) {
setOperations.remove(PORTFOLIO_LIKE_KEY + portfolioId, userId.toString());
}
// 检查用户是否喜欢某个作品
public boolean isPostLikedByUser(Long portfolioId, Long userId) {
String key = PORTFOLIO_LIKE_KEY + portfolioId;
Boolean isMember = setOperations.isMember(key, userId.toString());
return isMember != null && isMember;
}
public final static String PORTFOLIO_VIEW_KEY = "portfolio:view:";
public void increaseViewCount(Long portfolioId) {
String key = PORTFOLIO_VIEW_KEY + portfolioId;
increment(key, 1);
}
public Long getViewCount(Long portfolioId) {
String key = PORTFOLIO_VIEW_KEY + portfolioId;
return getLong(key, 0L);
}
public Long getViewCount(String key) {
return getLong(key, 0L);
}
public final static String PERSONAL_HOMEPAGE_VIEW_KEY = "PersonalHomepage:view:";
public void increasePersonalHomepageViewCount(Long accountId) {
String key = PERSONAL_HOMEPAGE_VIEW_KEY + accountId;
increment(key, 1);
}
public Long getPersonalHomepageViewCount(Long accountId) {
String key = PERSONAL_HOMEPAGE_VIEW_KEY + accountId;
return getLong(key, 0L);
}
public final static String MOODBOARD_POSITION_KEY = "moodboard:position:";
public void saveMoodboardPosition(Long id, String moodboardPosition) {
setString(MOODBOARD_POSITION_KEY + id, moodboardPosition);
}
public String getMoodboardPosition(Long id) {
return getString(MOODBOARD_POSITION_KEY + id);
}
public final static String NICKNAME_MODIFY_TIMES = "NicknameModifyTimes:";
public void increaseCount(String key) {
increment(key, 1);
}
public Long getIncrementCount(String key) {
return getLong(key, 0L);
}
public void setKeyExpire(String key, Long expire) {
redisTemplate.expire(key, expire, TimeUnit.DAYS);
}
public final static String CHANGE_MAILBOX = "ChangeMailbox:";
// 每天允许通知3次
public final static String UPLOAD_TIMEOUT_REMINDER_COUNTER = "UploadTimeoutReminderCounter";
public void addProcessId(String processId, int progress) {
// Redis 中的键,可以通过 processId 来唯一标识
String redisKey = "process:progress:" + processId;
setInteger(redisKey, progress);
redisTemplate.expire(redisKey, 5, TimeUnit.MINUTES);
}
public void addPathToCache(Long collectionId, Long userId, String path) {
// Redis 中的键,唯一标识由 collectionId 和 userId 组成
String redisKey = "path:cache:" + collectionId + ":" + userId;
// 增加路径的计数
hashOperations.increment(redisKey, path, 1);
// 设置过期时间为 2 小时7200 秒)
redisTemplate.expire(redisKey, 2, TimeUnit.HOURS);
}
public int getPathUsageCount(Long collectionId, Long userId, String path) {
String redisKey = "path:cache:" + collectionId + ":" + userId;
// 获取路径的使用次数
Object count = hashOperations.get(redisKey, path);
return count != null ? ((Number) count).intValue() : 0;
}
public void addAssembledObjects(Long collectionId, Set<DesignPythonObject> assembledObjects) {
// Redis 中的键,使用 collectionId 来唯一标识
String redisKey = "collection:assembledObjects:" + collectionId;
// 将 assembledObjects 转换为 JSON 格式存储,避免直接存储对象
String assembledObjectsJson = convertToJson(assembledObjects);
if (assembledObjectsJson != null) {
// 使用 Redis 的 set 操作更新集合
setString(redisKey, assembledObjectsJson);
// 设置过期时间为 5 分钟300 秒)
redisTemplate.expire(redisKey, 30, TimeUnit.MINUTES);
}
}
private String convertToJson(Set<DesignPythonObject> assembledObjects) {
try {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(assembledObjects);
} catch (JsonProcessingException e) {
log.error("JSON转换失败", e);
return null;
}
}
public Set<DesignPythonObject> getAssembledObjects(Long collectionId) {
String redisKey = "collection:assembledObjects:" + collectionId;
String assembledObjectsJson = getString(redisKey);
if (assembledObjectsJson == null) {
return new HashSet<>();
}
return convertFromJson(assembledObjectsJson);
}
private Set<DesignPythonObject> convertFromJson(String json) {
try {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(json, new TypeReference<Set<DesignPythonObject>>() {});
} catch (JsonProcessingException e) {
log.error("JSON解析失败", e);
return new HashSet<>();
}
}
public final static String PAYMENT_INFO_LAST_SCAN_TIME = "PaymentInfoLastScanTime";
public final static String AFFILIATE_LINK_VIEW_KEY = "AffiliateLink:view:";
public void increaseAffiliateLinkViewCount(Long accountId) {
String key = AFFILIATE_LINK_VIEW_KEY + accountId;
increment(key, 1);
}
public Long getAffiliateLinkViewCount(Long accountId) {
String key = AFFILIATE_LINK_VIEW_KEY + accountId;
return getLong(key, 0L);
}
public Long getAndSetKey(String key, Long count) {
Object oldValue = valueOperations.getAndSet(key, count);
if (oldValue instanceof Long) {
return (Long) oldValue;
} else if (oldValue instanceof Integer) {
return ((Integer) oldValue).longValue();
} else if (oldValue instanceof String) {
try {
return Long.parseLong((String) oldValue);
} catch (NumberFormatException e) {
log.warn("无法将字符串转换为Long: key={}, value={}", key, oldValue);
return 0L;
}
}
return 0L;
}
/**
* 记录任务的耗时到Redis
*/
public void recordTaskElapsedTime(String taskKey, long elapsedTime) {
String hashKey = "task:stats";
hashOperations.increment(hashKey, taskKey + ":totalTime", elapsedTime);
hashOperations.increment(hashKey, taskKey + ":count", 1);
}
/**
* 获取任务的平均耗时
*/
public double getTaskAverageTime(String taskKey) {
String hashKey = "task:stats";
Object totalTime = hashOperations.get(hashKey, taskKey + ":totalTime");
Object count = hashOperations.get(hashKey, taskKey + ":count");
if (totalTime == null || count == null) {
return 0;
}
try {
double total = ((Number) totalTime).doubleValue();
long cnt = ((Number) count).longValue();
return cnt > 0 ? total / cnt : 0;
} catch (Exception e) {
log.warn("计算平均耗时失败: taskKey={}", taskKey, e);
return 0;
}
}
/**
* 清除指定任务的统计数据
* @param taskKey 任务标识,如 "taskA"
*/
public void clearTaskStats(String taskKey) {
String hashKey = "task:stats";
// 删除总耗时和计数器
hashOperations.delete(hashKey, taskKey + ":totalTime", taskKey + ":count");
}
public void recordTaskElapsedTime(String taskKey, double elapsedTimeInSeconds) {
// 将耗时转换为 BigDecimal并四舍五入保留四位小数
BigDecimal elapsedTime = new BigDecimal(elapsedTimeInSeconds).setScale(4, RoundingMode.HALF_UP);
hashOperations.increment("task:stats", taskKey + ":totalTime", elapsedTime.doubleValue());
hashOperations.increment("task:stats", taskKey + ":count", 1);
}
// 获取第一部分Sketch耗时
public double getFirstSketchTime() {
Object time = hashOperations.get("task:stats", "firstSketchTime:totalTime");
return time != null ? ((Number) time).doubleValue() : 0.0;
}
// 获取第二部分(获取特征值)耗时
public double getGetAttributeRecognitionTime() {
Object time = hashOperations.get("task:stats", "getAttributeRecognitionTime:totalTime");
return time != null ? ((Number) time).doubleValue() : 0.0;
}
// 获取第三部分(搭配 Sketch耗时
public double getOtherSketchTime() {
Object time = hashOperations.get("task:stats", "otherSketchTime:totalTime");
return time != null ? ((Number) time).doubleValue() : 0.0;
}
// 清理三部分的缓存
public void clearTaskElapsedTimeCache() {
String hashKey = "task:stats";
Object[] keysToDelete = {
"firstSketchTime:totalTime", "firstSketchTime:count",
"getAttributeRecognitionTime:totalTime", "getAttributeRecognitionTime:count",
"otherSketchTime:totalTime", "otherSketchTime:count"
};
hashOperations.delete(hashKey, keysToDelete);
}
public boolean incrementLikeCount(Long userId, String sketchPath) {
String redisKey = "user_like_count:" + userId;
try {
hashOperations.increment(redisKey, sketchPath, 1);
return true;
} catch (Exception e) {
log.error("Error incrementing like count for userId {} and sketchPath {}: {}", userId, sketchPath, e.getMessage());
return false;
}
}
public int getLikeCount(Long userId, String sketchPath) {
String redisKey = "user_like_count:" + userId;
Object count = hashOperations.get(redisKey, sketchPath);
return count != null ? ((Number) count).intValue() : 0;
}
public void storeMaxLikeCount(Long userId, int maxLikeCount) {
String redisKey = "user_max_like_count:" + userId;
setInteger(redisKey, maxLikeCount);
}
public int getMaxLikeCount(Long userId) {
String redisKey = "user_max_like_count:" + userId;
return getInteger(redisKey, 0);
}
public final static String IMAGE_SEGMENTATION = "ImageSegmentation:";
public final static String STRIPE_EXCEPTION_LOG = "StripeException:";
public void batchDeleteKeysWithSamePrefix(String prefix) {
Set<String> keys = redisTemplate.keys(prefix + "*");
if (keys != null && !keys.isEmpty()) {
redisTemplate.delete(keys);
}
}
public void setTaskProgressDTO(String taskId, ProgressDTO dto) {
String key = "task:progress:" + taskId;
setString(key, JSON.toJSONString(dto));
redisTemplate.expire(key, 1, TimeUnit.DAYS);
}
public ProgressDTO getTaskProgressDTO(String taskId) {
String key = "task:progress:" + taskId;
String json = getString(key);
if (StringUtils.isBlank(json)) {
return null;
}
try {
return JSON.parseObject(json, ProgressDTO.class);
} catch (Exception e) {
log.warn("任务进度解析失败 key={}, json={}", key, json);
return new ProgressDTO(0, 0, false, null);
}
}
// Lua脚本
private static final String RATE_LIMIT_SCRIPT =
"local current = redis.call('INCR', KEYS[1])\n" +
"local ttl = redis.call('TTL', KEYS[1])\n" +
"if tonumber(current) == 1 or tonumber(ttl) == -1 then\n" +
" redis.call('EXPIRE', KEYS[1], ARGV[1])\n" +
"end\n" +
"return tonumber(current) <= tonumber(ARGV[2])";
/**
* 检查是否允许发送
* @param userId 用户ID
* @return true-允许发送false-已超限
*/
public boolean allowSend(Long userId) {
String hourKey = getCurrentHourKey(userId);
// 执行Lua脚本
List<String> keys = Collections.singletonList(hourKey);
// 1小时过期限制数量 一小时只能向普通用户发10封
String[] args = new String[]{"3600", "10"};
Boolean result = redisTemplate.execute(
new DefaultRedisScript<>(RATE_LIMIT_SCRIPT, Boolean.class),
keys,
args
);
return Boolean.TRUE.equals(result);
}
/**
* 获取当前小时的Key
*/
private String getCurrentHourKey(Long userId) {
String hour = LocalDateTime.now()
.format(DateTimeFormatter.ofPattern("yyyyMMddHH"));
return String.format("email_limit:%s:%s", userId, hour);
}
/**
* 获取当前已发送数量
*/
public int getCurrentCount(Long userId) {
String key = getCurrentHourKey(userId);
return getInteger(key, 0);
}
public boolean allowRequest(String apiKey) {
String key = "rate_limit:" + apiKey;
// 使用Redis的INCR命令
Long count = increment(key, 1);
if (count == 1) {
redisTemplate.expire(key, 1, TimeUnit.MINUTES);
}
return count <= 3;
}
// 新增方法安全删除key
public boolean safeDelete(String key) {
try {
return Boolean.TRUE.equals(redisTemplate.delete(key));
} catch (Exception e) {
log.error("删除Redis key失败: {}", key, e);
return false;
}
}
// 新增方法:批量设置过期时间
public void batchExpire(Set<String> keys, long timeout, TimeUnit unit) {
if (keys != null && !keys.isEmpty()) {
for (String key : keys) {
redisTemplate.expire(key, timeout, unit);
}
}
}
}

View File

@@ -3,7 +3,7 @@ package com.ai.da.common.utils;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;

View File

@@ -19,7 +19,7 @@ import software.amazon.awssdk.services.s3.presigner.S3Presigner;
import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest;
import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest;
import javax.annotation.PostConstruct;
import jakarta.annotation.PostConstruct;
import java.io.*;
import java.time.Duration;
import java.util.*;
@@ -215,7 +215,7 @@ public class S3Util {
public void deleteObject(String path) {
if (!path.contains("/")) {
throw new BusinessException("The path is error!");
throw new BusinessException("the.path.is.error");
}
int index = path.indexOf("/");
String bucketName = path.substring(0, index);
@@ -244,7 +244,7 @@ public class S3Util {
return LocalCacheUtils.getPresignedUrlCache(path);
} else {
if (!path.contains("/")) {
throw new BusinessException("The path is error!");
throw new BusinessException("the.path.is.error");
}
int index = path.indexOf("/");
String bucketName = path.substring(0, index);
@@ -258,7 +258,7 @@ public class S3Util {
public String getPreSignedUrl(String path, int expiry, boolean resetCache) {
if (resetCache || LocalCacheUtils.getPresignedUrlCache(path) == null) {
if (!path.contains("/")) {
throw new BusinessException("The path is error!");
throw new BusinessException("the.path.is.error");
}
int index = path.indexOf("/");
String bucketName = path.substring(0, index);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,207 @@
package com.ai.da.common.utils;
import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Map;
@Slf4j
@Component
public class SendRequestUtil {
@Value("${ALIYUN_API_KEY}")
private String ALIYUN_API_KEY;
@Value("${FREEPIK_API_KEY}")
private String FREEPIK_API_KEY;
public String sendAliYunPostAsync(String apiUrl, String requestBody){
// 发送POST请求 todo 异常处理
HttpResponse execute = HttpRequest.post(apiUrl)
.header(Header.AUTHORIZATION, "Bearer " + ALIYUN_API_KEY)
.header("X-DashScope-Async", "enable")
.header(Header.CONTENT_TYPE, "application/json")
.body(requestBody)
.timeout(20000) // 设置超时时间20秒
.execute();
int status = execute.getStatus();
if (status == 200){
String body = execute.body();
JSONObject bodyJson = JSONUtil.parseObj(body);
return body;
}
log.warn("请求失败,状态码为 {}", status);
return null;
}
public String sendAliYunPost(String apiUrl, String requestBody){
// 发送POST请求 todo 异常处理
HttpResponse execute = HttpRequest.post(apiUrl)
.header(Header.AUTHORIZATION, "Bearer " + ALIYUN_API_KEY)
.header(Header.CONTENT_TYPE, "application/json")
.body(requestBody)
.timeout(20000) // 设置超时时间20秒
.execute();
int status = execute.getStatus();
if (status == 200){
String body = execute.body();
JSONObject bodyJson = JSONUtil.parseObj(body);
return body;
}
log.warn("请求失败,状态码为 {}", status);
return null;
}
public static final String FREE_PIK = "https://api.freepik.com/v1/ai/beta/text-to-image/reimagine-flux";
public String sendFreepikPost( String requestBody){
// 发送POST请求 todo 异常处理
HttpResponse execute = HttpRequest.post(FREE_PIK)
.header(Header.CONTENT_TYPE, "application/json")
.header("x-freepik-api-key", FREEPIK_API_KEY)
.body(requestBody)
.timeout(20000) // 设置超时时间20秒
.execute();
int status = execute.getStatus();
if (status == 200){
return execute.body();
}
log.warn("请求失败,状态码为 {}", status);
return null;
}
public String sendAliYunGet(String fullUrl){
// 发送GET请求 todo 异常处理
HttpResponse httpResponse = HttpRequest.get(fullUrl)
.header(Header.AUTHORIZATION, "Bearer " + ALIYUN_API_KEY)
.timeout(20000) // 设置超时时间20秒
.execute();
int status = httpResponse.getStatus();
if (status == 200){
return httpResponse.body();
}else {
return null;
}
}
/*public String sendFluxPost(String url, String requestBodyStr){
int status;
String body;
try (HttpResponse execute = HttpRequest.post(url)
.header(Header.CONTENT_TYPE, "application/json")
.header("x-key", "d447a0ac-2291-4f1c-9a36-f7614c385989")
.body(requestBodyStr) // Hutool 会自动处理 JSON 序列化
.timeout(180000) // 设置超时(毫秒)
.execute()) {
status = execute.getStatus();
body = execute.body();
if (status == 200) {
return body;
}
if (status == 402 || status == 403) {
SendEmailUtil.commonExceptionReminder("Flux账户积分不足flux生成任务",
new String[]{"xupei3360@163.com, fangjianliao@aidlab.hk, investigation@aidlab.hk"});
}
}
log.warn("请求失败,状态码为 {}", status);
return null;
}*/
public String sendFluxPost(String url, String requestBodyStr) {
// 尝试两个API key
String[] apiKeys = {"84e8f5d5-b0b3-49aa-b244-ab7ba27e7ae7",
"d447a0ac-2291-4f1c-9a36-f7614c385989"};
boolean[] notified = {false, false}; // 记录是否已发送过不足提醒
for (int i = 0; i < apiKeys.length; i++) {
int status;
String body;
try (HttpResponse execute = HttpRequest.post(url)
.header(Header.CONTENT_TYPE, "application/json")
.header("x-key", apiKeys[i])
.body(requestBodyStr)
.timeout(180000)
.execute()) {
status = execute.getStatus();
body = execute.body();
if (status == 200) {
return body;
}
// 余额不足处理
if (status == 402 || status == 403) {
if (!notified[i]) {
SendEmailUtil.commonExceptionReminder(
"Flux账户积分不足flux生成任务失败。key:" + apiKeys[i],
new String[]{"xupei3360@163.com", "fangjianliao@aidlab.hk", "investigation@aidlab.hk"}
);
notified[i] = true;
}
continue; // 尝试下一个key
}
// 其他错误直接返回null
log.warn("请求失败,状态码为:{}使用key{}", status, apiKeys[i]);
return null;
} catch (Exception e) {
log.error("请求异常使用key{}", apiKeys[i], e);
if (i == apiKeys.length - 1) return null; // 最后一个key也失败则返回null
}
}
log.warn("所有API key均余额不足");
return null;
}
public String sendPost(String url, String requestBodyStr){
int status;
String body;
try (HttpResponse execute = HttpRequest.post(url)
.header("Content-Type", "application/json") // 必须设置 Content-Type
.body(requestBodyStr) // Hutool 会自动处理 JSON 序列化
.timeout(180000) // 设置超时(毫秒)
.execute()) {
status = execute.getStatus();
body = execute.body();
if (status == 200) {
return body;
}
}
log.warn("请求失败,状态码为 {}, body: {}", status, body);
return null;
}
public String sendGet(String url, Map<String, Object> params) {
int status;
String body;
try (HttpResponse execute = HttpRequest.get(url)
.form(params) // 直接传入MapHutool会正确处理
.timeout(180000)
.execute()) {
status = execute.getStatus();
body = execute.body();
if (status == 200) {
return body;
}
} catch (Exception e) {
log.error("请求发生异常: {}", e.getMessage(), e);
return null;
}
log.warn("请求失败,状态码为: {}, body: {}", status, body);
return body;
}
}

View File

@@ -4,11 +4,10 @@ import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestParam;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -58,7 +57,7 @@ public class NotificationConnection {
//收到了客户端消息执行的操作
@OnMessage
public void onMessage(@RequestParam String text){
public void onMessage(String text){
Map<String, String> textMap = JSONObject.parseObject(text, Map.class);
log.info("收到了一条来自 {} 的消息:{} sessionId{}", this.userId, textMap.get("text"), this.session.getId());
// return "已收到你的消息";

View File

@@ -1,5 +1,7 @@
package com.ai.da.common.websocket.config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@@ -8,6 +10,8 @@ import org.springframework.web.socket.server.standard.ServerEndpointExporter;
* Configuration of WebSocket
*/
@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnProperty(name = "websocket.enabled", havingValue = "true", matchIfMissing = true)
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {

View File

@@ -1,6 +1,7 @@
package com.ai.da.controller;
import com.ai.da.common.config.exception.BusinessException;
import com.ai.da.common.context.UserContext;
import com.ai.da.common.response.PageBaseResponse;
import com.ai.da.common.response.Response;
import com.ai.da.mapper.primary.entity.Account;
@@ -12,23 +13,25 @@ import com.ai.da.model.vo.AccountPreLoginVO;
import com.ai.da.model.vo.BindEmailVO;
import com.ai.da.model.vo.PersonalHomepageVO;
import com.ai.da.service.AccountService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@Api(tags = "Account模块")
@Tag(name = "Account模块")
@Slf4j
@RestController
@RequestMapping("/api/account")
@@ -37,172 +40,174 @@ public class AccountController {
@Resource
private AccountService accountService;
@ApiOperation(value = "预先登入")
@Operation(summary = "预先登入")
@PostMapping("/preLogin")
public Response<AccountPreLoginVO> preLogin(@Valid @RequestBody AccountPreLoginDTO accountDTO) {
return Response.success(accountService.preLogin(accountDTO));
}
@ApiOperation(value = "登入")
@Operation(summary = "登入")
@PostMapping("/login")
public Response<AccountLoginVO> login(@Valid @RequestBody AccountLoginDTO accountDTO, HttpServletRequest request) {
return Response.success(accountService.login(accountDTO, request));
}
@ApiOperation(value = "绑定邮箱")
@Operation(summary = "绑定邮箱")
@PostMapping("/bindEmail")
public Response<BindEmailVO> bindEmail(@Valid @RequestBody AccountBindEmailDTO accountBindEmailDTO, HttpServletRequest request) {
return Response.success(accountService.bindEmail(accountBindEmailDTO, request));
}
@ApiOperation(value = "忘记密码")
@Operation(summary = "忘记密码")
@PostMapping("/resetPwd")
public Response<Boolean> resetPwd(@Valid @RequestBody AccountRegisterDTO accountRegisterDTO) {
return Response.success(accountService.forgetPwd(accountRegisterDTO));
}
@ApiOperation(value = "发送邮件")
@Operation(summary = "发送邮件")
@PostMapping("/sendEmail")
public Response<Boolean> sendEmail(@Valid @RequestBody EmailSendDTO emailSendDTO) {
return Response.success(accountService.sendEmail(emailSendDTO));
}
@ApiOperation(value = "登出")
@Operation(summary = "登出")
@PostMapping("/logout")
public Response<Boolean> logout(@Valid @RequestBody AccountLogoutDTO accountLogoutDTO) {
return Response.success(accountService.logout(accountLogoutDTO));
}
@ApiOperation(value = "是否登入")
@Operation(summary = "是否登入")
@PostMapping("/isLogin")
public Response<Boolean> isLogin(@Valid @RequestBody AccountLogoutDTO accountLogoutDTO) {
return Response.success(accountService.isLogin(accountLogoutDTO));
}
@ApiOperation(value = "获取当前用户语言")
@Operation(summary = "获取当前用户语言")
@PostMapping("/getUserLanguage")
public Response<String> getUserLanguage() {
return Response.success(accountService.getUserLanguage());
}
@ApiOperation(value = "切换当前用户语言")
@Operation(summary = "切换当前用户语言")
@GetMapping("/changeUserLanguage")
public Response<String> changeUserLanguage(String language) {
return Response.success(accountService.changeUserLanguage(language));
}
@ApiOperation(value = "试用用户退出登录")
@Operation(summary = "试用用户退出登录")
@GetMapping("/trialUserLogout")
public Response<Boolean> trialUserLogout() {
return Response.success(accountService.trialUserLogout());
}
@ApiOperation(value = "完成新手教程")
@Operation(summary = "完成新手教程")
@PostMapping("/completeGuidance")
public Response<Boolean> completeGuidance() {
return Response.success(accountService.completeGuidance());
}
@ApiOperation(value = "试用订单列表")
@Operation(summary = "试用订单列表")
@PostMapping("/trialOrderList")
public Response<PageBaseResponse<TrialOrder>> trialOrderList(@Valid @RequestBody TrialOrderDTO trialOrderDTO) {
return Response.success(PageBaseResponse.success(accountService.trialOrderList(trialOrderDTO)));
}
@ApiOperation(value = "通过试用订单审批")
@Operation(summary = "通过试用订单审批")
@PostMapping("/trialOrderApproval")
public Response<Boolean> trialOrderApproval(@RequestParam("ids") List<Long> ids) {
return Response.success(accountService.trialOrderApproval(ids));
}
@ApiOperation(value = "拒绝试用订单审批")
@Operation(summary = "拒绝试用订单审批")
@PostMapping("/trialOrderRefuse")
public Response<Boolean> trialOrderRefuse(@RequestParam("ids") List<Long> ids) {
return Response.success(accountService.trialOrderRefuse(ids));
}
@ApiOperation(value = "获取是否自动审评")
@Operation(summary = "获取是否自动审评")
@PostMapping("/getIsAutoApproval")
public Response<Boolean> getIsAutoApproval() {
return Response.success(accountService.getIsAutoApproval());
}
@ApiOperation(value = "切换是否自动审评")
@Operation(summary = "切换是否自动审评")
@PostMapping("/switchIsAutoApproval")
public Response<Boolean> switchIsAutoApproval() {
return Response.success(accountService.switchIsAutoApproval());
}
@ApiOperation(value = "aws状态检测")
@Operation(summary = "aws状态检测")
@GetMapping("/healthy")
@ResponseStatus(HttpStatus.OK)
public Response<Map<String,Integer>> checkStatus(){
Map<String,Integer> returnMap = new HashMap<>();
returnMap.put("code",200);
public Response<Map<String, Integer>> checkStatus() {
Map<String, Integer> returnMap = new HashMap<>();
returnMap.put("code", 200);
return Response.success(returnMap);
}
@ApiOperation(value = "查询账号到期时间")
@Operation(summary = "查询账号到期时间")
@PostMapping("/getExpiredTime")
public Response<Long> getExpiredTime(){
public Response<Long> getExpiredTime() {
return Response.success(accountService.getExpiredTime());
}
@ApiOperation(value = "免密登录")
@Operation(summary = "免密登录")
@PostMapping("/noLoginRequired")
public Response<AccountLoginVO> noLoginRequired(@RequestBody NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request){
public Response<AccountLoginVO> noLoginRequired(@RequestBody NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request) {
return Response.success(accountService.noLoginRequired(noLoginRequiredDTO, request));
}
@PostMapping("upgradeNotification")
@ApiOperation(value = "升级邮件通知")
@Operation(summary = "升级邮件通知")
public Response<Boolean> upgradeNotification() {
accountService.upgradeNotification();
return Response.success(true);
}
@CrossOrigin
@ApiOperation(value = "广场用户注册")
@Operation(summary = "广场用户注册")
@PostMapping("/designWorksRegister")
public Response<Boolean> designWorksRegister(@Valid @RequestBody AccountDesignWorksRegisterDTO accountDesignWorksRegisterDTO) {
return Response.success(accountService.designWorksRegister(accountDesignWorksRegisterDTO));
}
@CrossOrigin
@ApiOperation(value = "广场用户注册")
@Operation(summary = "广场用户注册")
@PostMapping("/designWorksRegisterCode")
public Response<AccountLoginVO> designWorksRegisterCode(@Valid @RequestBody AccountDesignWorksRegisterDTO accountDesignWorksRegisterDTO) {
return Response.success(accountService.designWorksRegisterCode(accountDesignWorksRegisterDTO));
public Response<AccountLoginVO> designWorksRegisterCode(@Valid @RequestBody AccountDesignWorksRegisterDTO accountDesignWorksRegisterDTO,
HttpServletRequest request) {
return Response.success(accountService.designWorksRegisterCode(accountDesignWorksRegisterDTO, request));
}
/**
* 填写调查问卷
* @return
*/
@ApiOperation(value = "填写调查问卷")
/* @Operation(summary = "填写调查问卷")
@PostMapping("/questionnaire")
public Response<Boolean> questionnaire(@Valid @RequestBody String questionnaireInfo){
return Response.success(accountService.collectQuestionnaires(questionnaireInfo));
}
}*/
/**
* 参与活动 获取福利
*
* @return
*/
@ApiOperation(value = "参与活动 获取福利")
/* @Operation(summary = "参与活动 获取福利")
@GetMapping("/activity")
public Response<String> getActivityBenefits(){
return Response.success(accountService.getActivityBenefits());
}
}*/
@ApiOperation(value = "将用户账号过期时间设置为过期当天的235959")
@Operation(summary = "将用户账号过期时间设置为过期当天的235959")
@GetMapping("/setUserValidToDayEnd")
public Response<List<Long>> setUserValidToDayEnd(){
public Response<List<Long>> setUserValidToDayEnd() {
return Response.success(accountService.setUserValidToDayEnd());
}
// 用户上传头像
@ApiOperation(value = "上传头像")
@Operation(summary = "上传头像")
@PostMapping(path = "/uploadAvatar")
public Response<String> uploadAvatar(@RequestParam("file") MultipartFile file) {
if (null == file || StringUtils.isEmpty(file.getOriginalFilename())) {
@@ -211,27 +216,27 @@ public class AccountController {
return Response.success(accountService.uploadAvatar(file));
}
@ApiOperation(value = "个人主页浏览量增加")
@Operation(summary = "个人主页浏览量增加")
@GetMapping("/viewsIncrease")
public Response<Boolean> viewsGet(@RequestParam("id") Long id) {
return Response.success(accountService.viewsIncrease(id));
}
@ApiOperation(value = "获取个人主页信息")
@Operation(summary = "获取个人主页信息")
@GetMapping("/personalHomepage")
public Response<PersonalHomepageVO> getPersonalHomepage(@RequestParam("id") Long id){
public Response<PersonalHomepageVO> getPersonalHomepage(@RequestParam("id") Long id) {
return Response.success(accountService.getPersonalHomepage(id));
}
@ApiOperation(value = "getUsernameModifyTimes")
@Operation(summary = "getUsernameModifyTimes")
@GetMapping("/getNicknameModifyTimes")
public Response<Long> getNicknameModifyTimes(){
public Response<Long> getNicknameModifyTimes() {
return Response.success(accountService.getNicknameModifyTimes());
}
@ApiOperation(value = "editUserName")
@Operation(summary = "editUserName")
@GetMapping("/editUserName")
public Response<String> editUserName(@RequestParam("newUserName") String newUserName){
public Response<String> editUserName(@RequestParam("newUserName") String newUserName) {
accountService.editUserName(newUserName);
return Response.success("success");
}
@@ -243,14 +248,14 @@ public class AccountController {
return Response.success("success");
}
@ApiOperation(value = "changeUserEmail")
@Operation(summary = "changeUserEmail")
@GetMapping("/changeUserEmail")
public Response<String> changeUserEmail(@RequestParam("newMailbox") String newMailbox){
accountService.changeUserEmail(newMailbox);
return Response.success("success");
}
@ApiOperation(value = "activateNewEmail")
@Operation(summary = "activateNewEmail")
@GetMapping("/activateNewEmail")
public Response<String> activateNewEmail(@RequestParam("token") String token){
accountService.activateNewEmail(token);
@@ -258,94 +263,140 @@ public class AccountController {
}*/
@PostMapping("halfPricePromotion")
@ApiOperation(value = "十月半价活动")
@Operation(summary = "十月半价活动")
public Response<Boolean> halfPricePromotion() {
accountService.halfPricePromotion();
return Response.success(true);
}
@PostMapping("temporaryUpgrade")
@ApiOperation(value = "临时升级")
@Operation(summary = "临时升级")
public Response<Boolean> temporaryUpgrade() {
accountService.temporaryUpgrade();
return Response.success(true);
}
@PostMapping("enterpriseLogin")
@ApiOperation(value = "企业登录")
public Response<AccountLoginVO> enterpriseLogin(@Valid @RequestBody AccountLoginDTO accountDTO) {
@Operation(summary = "企业登录")
public Response<AccountPreLoginVO> enterpriseLogin(@Valid @RequestBody AccountLoginDTO accountDTO) {
return Response.success(accountService.enterpriseLogin(accountDTO));
}
@PostMapping("schoolLogin")
@ApiOperation(value = "学校登录")
public Response<AccountLoginVO> schoolLogin(@Valid @RequestBody AccountLoginDTO accountDTO) {
@Operation(summary = "学校登录")
public Response<AccountPreLoginVO> schoolLogin(@Valid @RequestBody AccountLoginDTO accountDTO) {
return Response.success(accountService.schoolLogin(accountDTO));
}
@PostMapping("organizationNameSearch")
@Operation(summary = "组织名模糊查询")
public Response<Set<String>> organizationNameSearch(@RequestParam("type") String type, @RequestParam(value = "name", required = false) String name) {
return Response.success(accountService.organizationNameSearch(type, name));
}
@PostMapping("addOrUpdateSubAccount")
@ApiOperation(value = "子账号新增")
@Operation(summary = "子账号新增")
public Response<Boolean> addSubAccount(@Valid @RequestBody AddSubAccountDTO addSubAccountDTO) {
return Response.success(accountService.addSubAccount(addSubAccountDTO));
}
@PostMapping("deleteSubAccount")
@ApiOperation(value = "子账号删除")
@Operation(summary = "子账号删除")
public Response<Boolean> deleteSubAccount(@Valid @RequestBody AddSubAccountDTO addSubAccountDTO) {
return Response.success(accountService.deleteSubAccount(addSubAccountDTO));
// return Response.success(accountService.deleteSubAccount(addSubAccountDTO));
accountService.removeSubAccount(addSubAccountDTO, UserContext.getUserHolder().getId());
return Response.success();
}
@PostMapping("subAccountList")
@ApiOperation(value = "子账号查询")
@Operation(summary = "子账号查询")
public Response<PageBaseResponse<Account>> subAccountList(@Valid @RequestBody SubAccountPageDTO subAccountPageDTO) {
return Response.success(accountService.subAccountList(subAccountPageDTO));
}
@GetMapping("accountDetail")
@ApiOperation(value = "账号详情")
@Operation(summary = "账号详情")
public Response<Account> accountDetail(@RequestParam("id") Long id) {
return Response.success(accountService.accountDetail(id));
}
@PostMapping("getAccountDetail")
@ApiOperation(value = "获取账户信息")
@Operation(summary = "获取账户信息")
public Response<AccountLoginVO> getAccountDetail() {
return Response.success(accountService.getAccountDetail());
}
@GetMapping("/bindGoogle")
@ApiOperation(value = "绑定谷歌")
@Operation(summary = "绑定谷歌")
public Response<AccountExtend> bindGoogle(@RequestParam("credential") String credential) {
return Response.success(accountService.bindGoogle(credential));
}
@GetMapping("/bindWeChat")
@ApiOperation(value = "绑定微信")
@Operation(summary = "绑定微信")
public Response<AccountExtend> bindWeChat(@RequestParam("code") String code) {
return Response.success(accountService.bindWeChat(code));
}
@GetMapping("/bindEmail")
@ApiOperation(value = "绑定邮箱")
@Operation(summary = "绑定邮箱")
public Response<BindEmailVO> bindEmail(@RequestParam("email") String email) {
return Response.success(accountService.bindEmail(email));
}
@GetMapping("/unbindWeChat")
@ApiOperation(value = "解除绑定微信")
@Operation(summary = "解除绑定微信")
public Response<Boolean> unbindWeChat() {
return Response.success(accountService.unbindWeChat());
}
@GetMapping("/unbindGoogle")
@ApiOperation(value = "解除绑定谷歌")
@Operation(summary = "解除绑定谷歌")
public Response<Boolean> unbindGoogle() {
return Response.success(accountService.unbindGoogle());
}
@PostMapping("/updateUserInfo")
@ApiOperation(value = "更新用户国家、职业信息")
@Operation(summary = "更新用户国家、职业信息")
public Response<Boolean> updateUserInfo(@Valid @RequestBody UpdateUserInfoDTO updateUserInfoDTO) {
return Response.success(accountService.updateUserInfo(updateUserInfoDTO));
}
@GetMapping("/subAccountImportExcelDownload")
@Operation(summary = "模板下载")
public void subAccountImportExcelDownload(HttpServletResponse response) {
accountService.subAccountImportExcelDownload(response);
}
@GetMapping("/exportAccountsToExcel")
@Operation(summary = "下载子账号信息")
public void exportAccountsToExcel(HttpServletResponse response) {
accountService.exportAccountsToExcel(response);
}
@PostMapping("/subAccountImport")
@Operation(summary = "模板导入")
public Response<Boolean> subAccountImport(@RequestParam("file") MultipartFile file) {
return Response.success(accountService.subAccountImport(file));
}
/*@GetMapping("/send618Email")
@Operation(summary = "618邮件发送")
public Response<String> send618PromotionEmailTemp() {
accountService.send618PromotionEmailTemp();
return Response.success("success");
}*/
/*@GetMapping("/refreshCreditsMonthly")
@Operation(summary = "刷新子账号积分")
public void refreshCreditsMonthly() {
accountService.refreshCreditsMonthly();
}*/
/*@GetMapping("/checkEduAdminExpireStatus")
@Operation(summary = "检查教育管理员账号到期情况")
public void checkEduAdminExpireStatus() {
accountService.checkEduAdminExpireStatus();
}*/
}

View File

@@ -4,63 +4,80 @@ package com.ai.da.controller;
import com.ai.da.common.response.PageBaseResponse;
import com.ai.da.common.response.Response;
import com.ai.da.model.dto.AffiliateQueryDTO;
import com.ai.da.model.dto.EditReferralDTO;
import com.ai.da.model.dto.ReferralPageQueryDTO;
import com.ai.da.model.vo.AffiliateInvitationDetailsVO;
import com.ai.da.model.vo.AffiliateVO;
import com.ai.da.model.vo.ReferralPageQueryVO;
import com.ai.da.service.AffiliateService;
import com.ai.da.service.ReferralService;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import jakarta.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
@Slf4j
@RestController
@RequestMapping("/api/affiliate")
@Api(tags = "Affiliate模块")
@Tag(name = "Affiliate模块")
public class AffiliateController {
@Resource
private AffiliateService affiliateService;
@ApiOperation(value = "注册成为affiliate")
@Resource
private ReferralService referralService;
@Operation(summary = "注册成为affiliate")
@GetMapping("/registration")
public Response<Boolean> completeGuidance(@RequestParam(value = "promotionMethod", required = false) String promotionMethod) {
return Response.success(affiliateService.registerAsAnAffiliate(promotionMethod));
}
@ApiOperation(value = "获取affiliate列表")
@Operation(summary = "获取affiliate列表")
@PostMapping("/list")
public Response<PageBaseResponse<AffiliateVO>> getAffiliateList(@Valid @RequestBody AffiliateQueryDTO affiliateQueryDTO) {
public Response<PageBaseResponse<AffiliateVO>> getAffiliateList(@Validated @RequestBody AffiliateQueryDTO affiliateQueryDTO) {
return Response.success(affiliateService.getAffiliateList(affiliateQueryDTO));
}
@ApiOperation(value = "获取affiliate个人中心")
@Operation(summary = "获取affiliate个人中心")
@GetMapping("/personalCenter")
public Response<AffiliateVO> personalAffiliateCenter() {
return Response.success(affiliateService.personalAffiliateCenter());
}
@ApiOperation(value = "获取个人佣金图表数据")
@Operation(summary = "获取个人佣金图表数据")
@GetMapping("/getPersonalMonthlyIncome")
public Response<double[]> getPersonalMonthlyIncome(@RequestParam("year")int year) {
public Response<BigDecimal[]> getPersonalMonthlyIncome(@RequestParam("year") int year) {
return Response.success(affiliateService.getPersonalMonthlyIncome(year));
}
@ApiOperation(value = "审批affiliate申请")
@Operation(summary = "审批affiliate申请")
@GetMapping("/approval")
public Response<Boolean> applicationApproval(@RequestParam("id") Long id,
@RequestParam("isApproved")Boolean isApproved,
@RequestParam("commission") Float commission) {
@RequestParam("isApproved") Boolean isApproved,
@RequestParam(value = "commission", required = false) Float commission) {
return Response.success(affiliateService.applicationApproval(id, isApproved, commission));
}
@ApiOperation(value = "更新佣金比例")
@GetMapping("/updateCommission")
public Response<String> updateCommissionPercentage(@RequestParam("id") Long id, @RequestParam("commission") Float commission) {
affiliateService.updateCommissionPercentage(id, commission);
@Operation(summary = "编辑affiliate")
@GetMapping("/editAffiliate")
public Response<String> editAffiliate(@RequestParam("id") Long id,
@Parameter(description = "佣金比例", example = "25")
@RequestParam(value = "commission", required = false) Float commission,
@Parameter(description = "操作类型", example = "Active",
schema = @Schema(allowableValues = {"Active", "Inactive", "Delete"}))
@RequestParam(value = "operationType", required = false) String operationType) {
affiliateService.editAffiliate(id, commission, operationType);
return Response.success("success");
}
@@ -78,17 +95,42 @@ public class AffiliateController {
return Response.success("success ");
}*/
@ApiOperation(value = "affiliate链接浏览量增加")
@Operation(summary = "affiliate链接浏览量增加")
@GetMapping("/viewsIncrease")
public Response<Boolean> viewsGet(@RequestParam("id") Long id) {
return Response.success(affiliateService.affiliateLinkViewsIncrease(id));
}
@ApiOperation(value = "获取每个affiliate产生的收入")
@Operation(summary = "获取每个affiliate产生的收入")
@PostMapping("/getEachAffiliateGeneratedRevenue")
public Response<IPage<AffiliateInvitationDetailsVO>> getEachAffiliateGeneratedRevenue(@RequestBody AffiliateQueryDTO affiliateQueryDTO) {
public Response<IPage<AffiliateInvitationDetailsVO>> getEachAffiliateGeneratedRevenue(@Validated @RequestBody AffiliateQueryDTO affiliateQueryDTO) {
return Response.success(affiliateService.getEachAffiliateGeneratedRevenue(affiliateQueryDTO));
}
@Operation(summary = "分页获取所有的referral")
@PostMapping("/getReferrals")
public Response<IPage<ReferralPageQueryVO>> getReferrals(@RequestBody ReferralPageQueryDTO referralPageQueryDTO) {
return Response.success(referralService.queryByPage(referralPageQueryDTO));
}
@Operation(summary = "编辑单个referral")
@PostMapping("/editReferral")
public Response<String> editReferral(@Validated @RequestBody EditReferralDTO editReferralDTO) {
referralService.editReferral(editReferralDTO);
return Response.success();
}
@Operation(summary = "批量删除referral")
@PostMapping("/batchDeleteReferral")
public Response<String> batchDeleteReferral(@RequestBody List<Long> idList) {
referralService.deleteReferral(idList);
return Response.success();
}
@Operation(summary = "获取所有affiliate用户名")
@GetMapping("/getAllAffiliateUsername")
public Response<List<Map<String, Object>>> getAllAffiliateUsername() {
return Response.success(affiliateService.getAllAffiliateUsername());
}
}

View File

@@ -3,27 +3,27 @@ package com.ai.da.controller;
import com.ai.da.common.response.Response;
import com.ai.da.model.dto.ProductPurchaseDTO;
import com.ai.da.service.AliPayService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import java.util.Map;
@CrossOrigin
@RestController
@RequestMapping("/api/ali-pay")
@Api(tags = "网站支付宝支付")
@Tag(name = "网站支付宝支付")
@Slf4j
public class AliPayController {
@Resource
private AliPayService aliPayService;
@ApiOperation("统一收单下单并支付页面接口的调用")
@Operation(summary = "统一收单下单并支付页面接口的调用")
@PostMapping("/trade/page/pay")
public Response<String> tradePagePay(@Valid @RequestBody ProductPurchaseDTO productPurchaseDTO, HttpServletRequest request){
log.info("统一收单下单并支付页面接口的调用");
@@ -35,7 +35,7 @@ public class AliPayController {
return Response.success(formStr);
}
@ApiOperation("支付通知")
@Operation(summary = "支付通知")
@PostMapping("/trade/notify")
public String tradeNotify(@RequestParam Map<String, String> params){
return aliPayService.tradeNotify(params);
@@ -46,7 +46,7 @@ public class AliPayController {
* @param orderNo
* @return
*/
@ApiOperation("用户取消订单")
@Operation(summary = "用户取消订单")
@PostMapping("/trade/close/{orderNo}")
public Response<String> cancel(@PathVariable String orderNo){
log.info("取消订单");
@@ -59,7 +59,7 @@ public class AliPayController {
* @param orderNo
* @return
*/
@ApiOperation("查询订单:测试订单状态用")
@Operation(summary = "查询订单:测试订单状态用")
@GetMapping("/trade/query/{orderNo}")
public Response<String> queryOrder(@PathVariable String orderNo) {
log.info("查询订单");
@@ -74,7 +74,7 @@ public class AliPayController {
* @param reason
* @return
*/
@ApiOperation("申请退款")
@Operation(summary = "申请退款")
@PostMapping("/trade/refund/{orderNo}/{reason}")
public Response<String> refunds(@PathVariable String orderNo, @PathVariable String reason){
log.info("申请退款");
@@ -88,7 +88,7 @@ public class AliPayController {
* @return
* @throws Exception
*/
@ApiOperation("查询退款:测试用")
@Operation(summary = "查询退款:测试用")
@GetMapping("/trade/fastpay/refund/{orderNo}")
public Response<String> queryRefund(@PathVariable String orderNo) {
log.info("查询退款");
@@ -103,7 +103,7 @@ public class AliPayController {
* @param type
* @return
*/
@ApiOperation("获取账单url")
@Operation(summary = "获取账单url")
@GetMapping("/bill/downloadurl/query/{billDate}/{type}")
public Response<String> queryTradeBill(
@PathVariable String billDate,

View File

@@ -3,40 +3,40 @@ package com.ai.da.controller;
import com.ai.da.common.response.Response;
import com.ai.da.model.dto.ProductPurchaseDTO;
import com.ai.da.service.AlipayHKService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
@CrossOrigin
@RestController
@RequestMapping("/api/alipay-hk")
@Api(tags = "网站支付 香港支付宝")
@Tag(name = "网站支付 香港支付宝")
@Slf4j
public class AlipayHKController {
@Resource
private AlipayHKService alipayHKService;
@ApiOperation(value = "创建订单")
@Operation(summary = "创建订单")
@PostMapping(value = "/createOrder")
public Response<String> createOrder(@Valid @RequestBody ProductPurchaseDTO productPurchaseDTO, HttpServletRequest request) {
String order = alipayHKService.createOrder(productPurchaseDTO, request);
return Response.success(order);
}
@ApiOperation("支付通知")
@Operation(summary = "支付通知")
@PostMapping("/trade/notify")
public String callback(@RequestBody String paramString){
log.info("alipay-hk callback parameter : {}", paramString);
return alipayHKService.callback(paramString);
}
@ApiOperation("订单查询")
@Operation(summary = "订单查询")
@PostMapping("/trade/query/{orderRef}")
public Response<String> queryOrder(@PathVariable String orderRef){
String s = alipayHKService.queryDetail(orderRef);

View File

@@ -5,15 +5,14 @@ import com.ai.da.model.dto.ClassificationDTO;
import com.ai.da.model.vo.ClassificationVO;
import com.ai.da.service.ClassificationService;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import java.util.List;
/**
@@ -26,7 +25,7 @@ import java.util.List;
@AllArgsConstructor
@NoArgsConstructor
@RequestMapping("/api/classification")
@Api(value = "", tags = "分类")
@Tag(name = "分类")
public class ClassificationController {
@Resource
@@ -37,7 +36,7 @@ public class ClassificationController {
*/
@PostMapping("/saveOrUpdate")
@ApiOperationSupport(order = 1)
@ApiOperation(value = "新增修改", notes = "传入ClassificationDTO")
@Operation(summary = "新增修改", description = "传入ClassificationDTO")
public Response<Boolean> saveOrUpdate(@Valid @RequestBody ClassificationDTO classificationDTO) {
return Response.success(classificationService.saveOrUpdate(classificationDTO));
}
@@ -47,28 +46,28 @@ public class ClassificationController {
*/
@PostMapping("/delete")
@ApiOperationSupport(order = 2)
@ApiOperation(value = "删除", notes = "传入ClassificationDTO")
@Operation(summary = "删除", description = "传入ClassificationDTO")
public Response<Boolean> delete(@Valid @RequestBody ClassificationDTO classificationDTO) {
return Response.success(classificationService.delete(classificationDTO));
}
@PostMapping("/queryClassification")
@ApiOperationSupport(order = 3)
@ApiModelProperty(value = "查询", notes = "传入ClassificationDTO")
@Operation(summary = "查询", description = "传入ClassificationDTO")
public Response<List<ClassificationVO>> queryClassification(@Valid @RequestBody ClassificationDTO classificationDTO) {
return Response.success(classificationService.queryClassification(classificationDTO));
}
@PostMapping("/relationLibrary")
@ApiOperationSupport(order = 4)
@ApiModelProperty(value = "关联", notes = "传入ClassificationDTO")
@Operation(summary = "关联", description = "传入ClassificationDTO")
public Response<Boolean> relationLibrary(@Valid @RequestBody ClassificationDTO classificationDTO) {
return Response.success(classificationService.relationLibrary(classificationDTO));
}
@PostMapping("/getRelClassificationIdList")
@ApiOperationSupport(order = 5)
@ApiModelProperty(value = "获取关联分类IDList", notes = "传入ClassificationDTO")
@Operation(summary = "获取关联分类IDList", description = "传入ClassificationDTO")
public Response<List<Long>> getRelClassificationIdList(@Valid @RequestBody ClassificationDTO classificationDTO) {
return Response.success(classificationService.getRelClassificationIdList(classificationDTO));
}
@@ -80,7 +79,7 @@ public class ClassificationController {
*/
@PostMapping("/getRelPublicClassificationIdList")
@ApiOperationSupport(order = 5)
@ApiModelProperty(value = "获取关联公共分类IDList", notes = "传入ClassificationDTO")
@Operation(summary = "获取关联公共分类IDList", description = "传入ClassificationDTO")
public Response<List<Long>> getRelPublicClassificationIdList(@Valid @RequestBody ClassificationDTO classificationDTO) {
return Response.success(classificationService.getRelPublicClassificationIdList(classificationDTO));
}
@@ -92,7 +91,7 @@ public class ClassificationController {
*/
@PostMapping("/editRelPublicClassificationIdList")
@ApiOperationSupport(order = 5)
@ApiModelProperty(value = "编辑关联公共分类IDList", notes = "传入ClassificationDTO")
@Operation(summary = "编辑关联公共分类IDList", description = "传入ClassificationDTO")
public Response<Boolean> editRelPublicClassificationIdList(@Valid @RequestBody ClassificationDTO classificationDTO) {
return Response.success(classificationService.editRelPublicClassificationIdList(classificationDTO));
}

View File

@@ -6,10 +6,9 @@ import com.ai.da.common.response.PageBaseResponse;
import com.ai.da.common.response.Response;
import com.ai.da.mapper.primary.DesignMapper;
import com.ai.da.mapper.primary.entity.Account;
import com.ai.da.mapper.primary.entity.Organization;
import com.ai.da.mapper.primary.entity.TrialOrder;
import com.ai.da.model.dto.AccountAddDTO;
import com.ai.da.model.dto.QueryPaymentInfoDTO;
import com.ai.da.model.dto.UserDesignStatisticDTO;
import com.ai.da.model.dto.*;
import com.ai.da.model.vo.PaymentInfoVO;
import com.ai.da.model.vo.QuestionnaireFeedbackVO;
import com.ai.da.model.vo.QuestionnaireVO;
@@ -18,20 +17,20 @@ import com.ai.da.service.AccountService;
import com.ai.da.service.ConvenientInquiryService;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.netty.util.internal.StringUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Nullable;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import jakarta.annotation.Nullable;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import java.text.SimpleDateFormat;
import java.util.*;
@Api(tags = "便利查询")
@Tag(name = "便利查询")
@Slf4j
@RestController
@RequestMapping("/api/inquiry")
@@ -44,28 +43,18 @@ public class ConvenientInquiryController {
private AccountService accountService;
@ApiOperation("获取当前所有试用用户")
@Operation(summary = "获取当前所有试用用户")
@PostMapping("/getTrial")
public Response<IPage<TrialOrder>> getTrial(@Valid @RequestBody QueryUserConditionsVO queryUserConditionsVO) {
Long accountId = UserContext.getUserHolder().getId();
String userEmail = accountService.getById(accountId).getUserEmail();
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("chelseayu@code-create.com.hk")
|| userEmail.equals("cheungzt007@gmail.com")
) {
return Response.success(convenientInquiryService.getTrial(queryUserConditionsVO));
} else {
return Response.fail("Sorry, you don't have permission");
}
return Response.success(convenientInquiryService.getTrial(queryUserConditionsVO));
}
@ApiOperation("获取指定时间区间内所有用户design的使用情况")
@Operation(summary = "获取指定时间区间内所有用户design的使用情况")
@GetMapping("/getDesignStatistic")
public Response<List<UserDesignStatisticDTO>> getDesignStatistic(@RequestParam(required = false) String startTime, @RequestParam(required = false) String endTime,
@RequestParam(required = false) List<Long> ids, @RequestParam(required = false) String email) {
Long accountId = UserContext.getUserHolder().getId();
@RequestParam(required = false) List<Long> ids, @RequestParam(required = false) String email,
@RequestParam(required = false) String organizationName) {
/*Long accountId = UserContext.getUserHolder().getId();
String userEmail = accountService.getById(accountId).getUserEmail();
if (accountId.equals(31L) || accountId.equals(87L) || accountId.equals(83L)
|| accountId.equals(6L) || accountId.equals(4L) || accountId.equals(73L)
@@ -82,77 +71,78 @@ public class ConvenientInquiryController {
if (!StringUtil.isNullOrEmpty(email)){
email = email.trim();
}
List<UserDesignStatisticDTO> designStatistic = designMapper.getDesignStatistic(startTime, endTime, ids, email);
List<UserDesignStatisticDTO> designStatistic = designMapper.getDesignStatistic(startTime, endTime, ids, email,"prsn", null);
return Response.success(designStatistic);
} else {
return Response.fail("Sorry, you don't have permission");
}
}*/
return Response.success(convenientInquiryService.getDesignStatistic(startTime, endTime, ids, email, organizationName));
}
//调查问卷
@ApiOperation("获取调查问卷统计详情")
@Operation(summary = "获取调查问卷统计详情")
@GetMapping("/getQuestionnaireStatistic")
public Response<QuestionnaireFeedbackVO> getQuestionnaire() {
return Response.success(convenientInquiryService.getQuestionnaireInfo());
}
@ApiOperation("获取所有调查问卷")
@Operation(summary = "获取所有调查问卷")
@GetMapping("/getAllQuestionnaire")
public Response<List<QuestionnaireVO>> getAllQuestionnaire() {
return Response.success(convenientInquiryService.getAllQuestionnaire());
}
@ApiOperation("获取近期新用户")
@Operation(summary = "获取近期新用户")
@PostMapping("/recentNewUser")
public Response<IPage<Account>> recentNewUser(@Valid @RequestBody QueryUserConditionsVO queryUserConditionsVO) {
return Response.success(convenientInquiryService.recentNewUser(queryUserConditionsVO));
}
@ApiOperation("获取近期新用户图表数据")
@Operation(summary = "获取近期新用户图表数据")
@GetMapping("/recentNewUserChart")
public Response<Map<String, Object>> recentNewUserChart(@ApiParam(value = "startTime") @RequestParam @Nullable String startTime,
@ApiParam(value = "endTime") @RequestParam @Nullable String endTime,
@ApiParam("userType") @RequestParam Integer userType) {
public Response<Map<String, Object>> recentNewUserChart(@Parameter(description = "startTime") @RequestParam @Nullable String startTime,
@Parameter(description = "endTime") @RequestParam @Nullable String endTime,
@Parameter(description = "userType") @RequestParam @Nullable Integer userType) {
return Response.success(convenientInquiryService.recentNewUserChart(startTime, endTime, userType));
}
@ApiOperation("获取近期活跃用户")
@Operation(summary = "获取近期活跃用户")
@PostMapping("/recentActiveUser")
public Response<IPage<Account>> recentActiveUser(@Valid @RequestBody QueryUserConditionsVO queryUserConditionsVO) {
return Response.success(convenientInquiryService.recentActiveUser(queryUserConditionsVO));
}
@ApiOperation("获取近期活跃用户图表数据")
@Operation(summary = "获取近期活跃用户图表数据")
@GetMapping("/recentActiveUserChart")
public Response<Integer> recentActiveUserChart(@ApiParam(value = "startTime") @RequestParam @Nullable String startTime,
@ApiParam(value = "endTime") @RequestParam @Nullable String endTime) {
public Response<Integer> recentActiveUserChart(@Parameter(description = "startTime") @RequestParam @Nullable String startTime,
@Parameter(description = "endTime") @RequestParam @Nullable String endTime) {
return Response.success(convenientInquiryService.recentActiveUserChart(startTime, endTime));
}
@ApiOperation("获取用户的各模块功能使用详情")
@Operation(summary = "获取用户的各模块功能使用详情")
@GetMapping("/getActiveUserFunc")
public Response<Map<String, List<Object>>> getActiveUserFunc(@ApiParam(value = "startTime") @RequestParam @Nullable String startTime,
@ApiParam(value = "endTime") @RequestParam @Nullable String endTime,
@ApiParam("userIdList") @RequestParam @Nullable List<Long> userIdList) {
public Response<Map<String, List<Object>>> getActiveUserFunc(@Parameter(description = "startTime") @RequestParam @Nullable String startTime,
@Parameter(description = "endTime") @RequestParam @Nullable String endTime,
@Parameter(description = "userIdList") @RequestParam(required = false) @Nullable List<Long> userIdList) {
return Response.success(convenientInquiryService.getActiveUserFunc(startTime, endTime, userIdList));
}
@ApiOperation("试用用户到正式用户的转化率")
@Operation(summary = "试用用户到正式用户的转化率")
@GetMapping("/conversionRate")
public Response<Map<String, Object>> conversionRate(@ApiParam(value = "startTime") @RequestParam(required = false) @Nullable String startTime,
@ApiParam(value = "endTime") @RequestParam(required = false) @Nullable String endTime) {
public Response<Map<String, Object>> conversionRate(@Parameter(description = "startTime") @RequestParam(required = false) @Nullable String startTime,
@Parameter(description = "endTime") @RequestParam(required = false) @Nullable String endTime) {
return Response.success(convenientInquiryService.conversionRate(startTime, endTime));
}
@ApiOperation("试用用户国家/城市分布")
@Operation(summary = "试用用户国家/城市分布")
@GetMapping("/trialUserCountry")
public Response<Map<String, List<Object>>> trialUserCountry(@ApiParam(value = "startTime") @RequestParam(required = false) @Nullable String startTime,
@ApiParam(value = "endTime") @RequestParam(required = false) @Nullable String endTime) {
public Response<Map<String, List<Object>>> trialUserCountry(@Parameter(description = "startTime") @RequestParam(required = false) @Nullable String startTime,
@Parameter(description = "endTime") @RequestParam(required = false) @Nullable String endTime) {
return Response.success(convenientInquiryService.trialUserCountry(startTime, endTime));
}
@ApiOperation("添加用户")
@Operation(summary = "添加用户")
@PostMapping("/addUser")
public Response<Boolean> addUser(@Valid @RequestBody AccountAddDTO accountAddDTO) {
Long userAccountId = UserContext.getUserHolder().getId();
@@ -165,12 +155,12 @@ public class ConvenientInquiryController {
}
}
@ApiOperation("修改用户信息")
@Operation(summary = "修改用户信息")
@PostMapping("/modifyUser")
public Response<Boolean> modifyUser(@ApiParam(value = "用户id") @RequestParam @Nullable Long accountId,
@ApiParam(value = "有效期截止时间的毫秒级unix格式") @RequestParam @Nullable Long validEndTime,
@ApiParam(value = "用户类型 1/2/3/0 -> yearly/monthly/trial/visitor") @RequestParam @Nullable Integer systemUser,
@ApiParam("积分") @RequestParam @Nullable Long credits) {
public Response<Boolean> modifyUser(@Parameter(description = "用户id") @RequestParam @Nullable Long accountId,
@Parameter(description = "有效期截止时间的毫秒级unix格式") @RequestParam @Nullable Long validEndTime,
@Parameter(description = "用户类型 1/2/3/0 -> yearly/monthly/trial/visitor") @RequestParam @Nullable Integer systemUser,
@Parameter(description = "积分") @RequestParam @Nullable Long credits) {
Long userAccountId = UserContext.getUserHolder().getId();
if (userAccountId.equals(31L) || userAccountId.equals(87L) || userAccountId.equals(83L)
|| userAccountId.equals(6L) || userAccountId.equals(4L) || userAccountId.equals(73L)
@@ -181,44 +171,61 @@ public class ConvenientInquiryController {
}
}
@ApiOperation("获取用户信息")
@Operation(summary = "获取用户信息")
@PostMapping("/getUserInfo")
public Response<IPage<Account>> getUserInfo(@Valid @RequestBody QueryUserConditionsVO queryUserConditionsVO) {
Long accountId = UserContext.getUserHolder().getId();
String userEmail = accountService.getById(accountId).getUserEmail();
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("chelseayu@code-create.com.hk")
|| userEmail.equals("cheungzt007@gmail.com")
) {
return Response.success(convenientInquiryService.getUserInfo(queryUserConditionsVO));
} else {
return Response.fail("Sorry, you don't have permission");
}
return Response.success(convenientInquiryService.getUserInfo(queryUserConditionsVO));
}
@ApiOperation("获取所有用户id")
@Operation(summary = "获取所有用户id")
@GetMapping("/getAllUserId")
public Response<List<Map<String, Object>>> getAllUsrIdList() {
return Response.success(convenientInquiryService.getAllUserIdList());
public Response<IPage<Map<String, Object>>> getAllUserIdList(@Parameter(description = "page") @RequestParam Integer page,
@Parameter(description = "size") @RequestParam Integer size,
@Parameter(description = "email 模糊查询") @RequestParam(required = false) String email) {
return Response.success(convenientInquiryService.getAllUserIdList(page, size, email));
}
@ApiOperation("获取所有交易信息")
@Operation(summary = "获取所有交易信息")
@PostMapping("/queryTransaction")
public Response<PageBaseResponse<PaymentInfoVO>> queryTransactionRecords(@Valid @RequestBody QueryPaymentInfoDTO queryPaymentInfoDTO){
return Response.success(convenientInquiryService.queryTransactionRecords(queryPaymentInfoDTO));
}
@ApiOperation("获取所有国家、城市")
@Operation(summary = "获取所有国家、城市")
@GetMapping("/getCities")
public Response<Map<String, List<String>>> getCities(){
return Response.success(convenientInquiryService.getCities());
}
@ApiOperation("下载交易记录")
@Operation(summary = "下载交易记录")
@PostMapping("/queryTransaction/download")
public Response<String> exportTransactionRecords(@Valid @RequestBody QueryPaymentInfoDTO queryPaymentInfoDTO, HttpServletResponse response){
return Response.success(convenientInquiryService.exportTransactionRecords(queryPaymentInfoDTO, response));
}
@Operation(summary = "获取生成功能使用频次")
@PostMapping("/getGenerateFrequency")
public Response<PageBaseResponse<AccountCreditsUsageDTO>> getGenerateFrequency(@Valid @RequestBody AccountCreditsUsageQueryDTO queryDTO){
return Response.success(convenientInquiryService.getGenerateFrequency(queryDTO));
}
@Operation(summary = "获取所有生成功能的名字")
@GetMapping("/getAllGenerateFuncName")
public Response<List<String>> getAllGenerateFuncName(){
return Response.success(convenientInquiryService.getAllGenerateFuncName());
}
@Operation(summary = "添加组织机构")
@GetMapping("/addOrganization")
public Response<String> addOrganization(@Parameter(description = "机构名") @RequestParam String name, @Parameter(description = "Enterprise || Education") @RequestParam String type){
convenientInquiryService.addOrganization(name, type);
return Response.success();
}
@Operation(summary = "查询所有企业或教育机构")
@PostMapping("/queryOrganization")
public Response<IPage<Organization>> queryOrganization(@RequestBody QueryOrganizationPageDTO queryOrganizationPageDTO){
return Response.success(convenientInquiryService.queryOrganization(queryOrganizationPageDTO));
}
}

View File

@@ -6,32 +6,32 @@ import com.ai.da.common.response.Response;
import com.ai.da.mapper.primary.entity.CreditsDetail;
import com.ai.da.model.dto.QueryIncomeOrExpenditureDTO;
import com.ai.da.service.CreditsService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
@CrossOrigin
@RestController
@RequestMapping("/api/credits")
@Api(tags = "积分")
@Tag(name = "积分")
@Slf4j
public class CreditsController {
@Resource
private CreditsService creditsService;
@ApiOperation("获取当前积分")
@Operation(summary = "获取当前积分")
@GetMapping("/getCredits")
public Response<String> getCredits() {
String credits = creditsService.getCredits(UserContext.getUserHolder().getId());
return Response.success(credits);
}
@ApiOperation("获取积分详细")
@Operation(summary = "获取积分详细")
@PostMapping("/getCreditsDetail")
public Response<PageBaseResponse<CreditsDetail>> getCreditsDetail(@Valid @RequestBody QueryIncomeOrExpenditureDTO queryPageByTimeDTO) {
PageBaseResponse<CreditsDetail> credits = creditsService.queryCreditsDetailsPage(queryPageByTimeDTO);

View File

@@ -1,104 +1,130 @@
package com.ai.da.controller;
import com.ai.da.common.config.exception.BusinessException;
import com.ai.da.common.response.PageBaseResponse;
import com.ai.da.common.response.Response;
import com.ai.da.mapper.primary.entity.CloudTask;
import com.ai.da.mapper.primary.entity.CollectionSort;
import com.ai.da.model.dto.*;
import com.ai.da.model.vo.CollectionSketchVO;
import com.ai.da.model.vo.DesignCollectionVO;
import com.ai.da.model.vo.DesignLikeVO;
import com.ai.da.model.vo.*;
import com.ai.da.service.DesignService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import com.ai.da.service.UserLikeGroupService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import java.math.BigDecimal;
import java.util.List;
@Api(tags = "design模块")
@Tag(name = "design模块")
@Slf4j
@RestController
@RequestMapping("/api/design")
public class DesignController {
@Resource
private DesignService designService;
@Resource
private UserLikeGroupService userLikeGroupService;
@ApiOperation(value = "设计 Conllection")
@Operation(summary = "设计 Conllection")
@PostMapping("/designCollection")
@CrossOrigin
public Response<String> designCollection(@Valid @RequestBody DesignCollectionDTO designDTO) {
return Response.success(designService.designCollection(designDTO));
}
@ApiOperation(value = "design进度条")
@Operation(summary = "design进度条")
@GetMapping("/designProcess")
public Response<Integer> designProcess(@RequestParam("processId") String processId) {
return Response.success(designService.designProcess(processId));
}
@ApiOperation(value = "重新设计 Collection")
@Operation(summary = "重新设计 Collection")
@PostMapping("/reDesignCollection")
public Response<String> reDesignCollection(@Valid @RequestBody ReDesignCollectionDTO reDesignDTO) {
return Response.success(designService.reDesignCollection(reDesignDTO));
}
@ApiOperation(value = "designItem list,刷新用")
@Operation(summary = "designItem list,刷新用")
@GetMapping("/designItemList")
public Response<DesignCollectionVO> designItemList(@ApiParam("designId") @RequestParam("designId") Long designId) {
public Response<DesignCollectionVO> designItemList(@Parameter(description = "designId") @RequestParam("designId") Long designId) {
return Response.success(designService.designItemList(designId));
}
@ApiOperation(value = "统计design进度")
@Operation(summary = "统计design进度")
@PostMapping("/countDesignProcess")
public Response<BigDecimal> countDesignProcess() {
return Response.success(designService.countDesignProcess());
}
@ApiOperation(value = "Design Like")
@Operation(summary = "Design Like")
@PostMapping("/like")
public Response<DesignLikeVO> like(@Valid @RequestBody DesignLikeDTO designLikeDTO) {
return Response.success(designService.like(designLikeDTO));
}
@ApiOperation(value = "Design Dislike")
@Operation(summary = "Design Dislike")
@PostMapping("/dislike")
public Response<Boolean> dislike(@Valid @RequestBody DisDesignLikeDTO disDesignLikeDTO) {
return Response.success(designService.dislike(disDesignLikeDTO));
}
@ApiOperation(value = "Design sort")
@Operation(summary = "Design sort")
@PostMapping("/sort")
public Response<Boolean> sort(@Valid @RequestBody UserLikeSortDTO userLikeSortDTO) {
public Response<Boolean> sort(@Valid @RequestBody CollectionSortDTO userLikeSortDTO) {
return Response.success(designService.sort(userLikeSortDTO));
}
@ApiOperation(value = "sketchBoard upload generate design前裁剪")
@Operation(summary = "sketchBoard upload generate design前裁剪")
@PostMapping("/sketchBoardsBoundingBox")
public Response<List<CollectionSketchVO>> sketchesBoundingBox(@Valid @RequestBody ReDesignCollectionDTO reDesignCollectionDTO) {
return Response.success(designService.sketchesBoundingBox(reDesignCollectionDTO));
}
@ApiOperation(value = "通过designItemId获取模特图")
@Operation(summary = "通过designItemId获取模特图")
@PostMapping("/getModel")
public Response<List<String>> getModel(@RequestBody List<Long> designItemIdList){
return Response.success(designService.getModel(designItemIdList));
}
@ApiOperation(value = "获取design结果")
@Operation(summary = "获取design结果")
@GetMapping("/getDesignResult")
public Response<DesignCollectionVO> getDesignResult(@RequestParam("requestId") String requestId, @RequestParam("objectSignList") List<String> objectSignList){
return Response.success(designService.getDesignResult(requestId, objectSignList));
}
@ApiOperation(value = "云生成")
@Operation(summary = "云生成")
@PostMapping("/designCloud")
@CrossOrigin
public Response<String> designCloud(@Valid @RequestBody DesignCollectionDTO designDTO) {
return Response.success(designService.designCloud(designDTO));
public Response<String> designCloud(@Valid @RequestBody CloudTaskDTO cloudTaskDTO) {
return Response.success(designService.designCloud(cloudTaskDTO));
}
@Operation(summary = "云生成修改任务名")
@PostMapping("/cloudTaskNameUpdate")
public Response<Boolean> cloudTaskNameUpdate(@Valid @RequestBody CloudTaskDTO cloudTaskDTO) {
return Response.success(designService.cloudTaskNameUpdate(cloudTaskDTO));
}
@Operation(summary = "云生成删除任务")
@PostMapping("/cloudTaskDelete")
public Response<Boolean> cloudTaskDelete(@Valid @RequestBody CloudTaskDTO cloudTaskDTO) {
return Response.success(designService.cloudTaskDelete(cloudTaskDTO));
}
@Operation(summary = "云生成page")
@PostMapping("/cloudPage")
public Response<PageBaseResponse<CloudTaskVO>> cloudPage(@Valid @RequestBody CloudPageDTO cloudPageDTO) {
return Response.success(PageBaseResponse.success(designService.cloudPage(cloudPageDTO)));
}
@Operation(summary = "获取design云生成结果")
@PostMapping("/getDesignCloudResult")
public Response<CloudTaskResultVO> getDesignCloudResult(@Valid @RequestBody DesignCloudResultQuery designCloudResultQuery) {
return Response.success(designService.getDesignCloudResult(designCloudResultQuery));
}
}

View File

@@ -5,18 +5,18 @@ import com.ai.da.model.dto.*;
import com.ai.da.model.vo.*;
import com.ai.da.service.DesignItemService;
import com.ai.da.service.DesignService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import java.io.IOException;
@Api(tags = "design Detail模块")
@Tag(name = "design Detail模块")
@Slf4j
@RestController
@RequestMapping("/api/design/detail")
@@ -26,7 +26,7 @@ public class DesignDetailController {
@Resource
private DesignItemService designItemService;
@ApiOperation(value = "生成高级design图片")
@Operation(summary = "生成高级design图片")
@PostMapping("/generateHighDesign")
public Response<String> generateHighDesign(@Valid @RequestBody GenerateHighDesignDTO generateHighDesignDTO) {
Response response = new Response();
@@ -34,7 +34,7 @@ public class DesignDetailController {
return response;
}
@ApiOperation(value = "删除高级design图片")
@Operation(summary = "删除高级design图片")
@PostMapping("/deleteHighDesign")
public Response<Boolean> deleteHighDesign(@Valid @RequestBody GenerateHighDesignDTO generateHighDesignDTO) {
Response response = new Response();
@@ -42,28 +42,28 @@ public class DesignDetailController {
return response;
}
@ApiOperation(value = "查询design详情")
@Operation(summary = "查询design详情")
@GetMapping("/getDetail")
public Response<DesignItemDetailVO> getDetail(@ApiParam("designItemId") @RequestParam("designItemId") Long designItemId,
@ApiParam("designPythonOutfitId") @RequestParam(value = "designPythonOutfitId", required = false) Long designPythonOutfitId) {
public Response<DesignItemDetailVO> getDetail(@Parameter(description = "designItemId") @RequestParam("designItemId") Long designItemId,
@Parameter(description = "designPythonOutfitId") @RequestParam(value = "designPythonOutfitId", required = false) Long designPythonOutfitId) {
return Response.success(designService.detail(designPythonOutfitId, designItemId));
}
@ApiOperation(value = "切换系统的element")
@Operation(summary = "切换系统的element")
@GetMapping("/getNextSysElement")
public Response<GetNextSysElementVO> getNextSysElement(@ApiParam("要切换的系统element 类型") @RequestParam("type") String type,
@ApiParam("要切换的系统element id") @RequestParam("id") Long id,
@ApiParam("操作类型 PREV 上一步 NEXT 下一步") @RequestParam("operateType") String operateType) {
public Response<GetNextSysElementVO> getNextSysElement(@Parameter(description = "要切换的系统element 类型") @RequestParam("type") String type,
@Parameter(description = "要切换的系统element id") @RequestParam("id") Long id,
@Parameter(description = "操作类型 PREV 上一步 NEXT 下一步") @RequestParam("operateType") String operateType) {
return Response.success(designItemService.getNextSysElement(id, type, operateType));
}
@ApiOperation(value = "单个design")
@Operation(summary = "单个design")
@PostMapping("/designSingle")
public Response<DesignSingleVO> designSingle(@Valid @RequestBody DesignSingleIncludeLayersDTO designSingleIncludeLayersDTO) {
return Response.success(designItemService.designSingleIncludeLayers(designSingleIncludeLayersDTO));
}
@ApiOperation(value = "print打点")
@Operation(summary = "print打点")
@PostMapping("/printDot")
public Response<String> printDot(@Valid @RequestBody DesignSingleDTO designSingleDTO) {
Response<String> response = new Response();
@@ -72,20 +72,20 @@ public class DesignDetailController {
return response;
}
@ApiOperation(value = "编辑图层大小和位置 废弃")
@Operation(summary = "编辑图层大小和位置 废弃")
@PostMapping("/editLayers")
public Response<ComposeLayersVO> editPositionAndScale(@Valid @RequestBody EditLayersPositionAndScaleVO positionAndScaleVO) throws IOException {
return Response.success(designItemService.editLayersPositionAndScale(positionAndScaleVO));
}
@ApiOperation(value = "mask数据兼容")
@Operation(summary = "mask数据兼容")
@GetMapping("/convertWithoutGradient")
public Response<String> convertHistoryMaskWithoutGradient(){
designItemService.convertHistoryMaskWithoutGradient();
return Response.success("success");
}
@ApiOperation(value = "mask数据库路径更新")
@Operation(summary = "mask数据库路径更新")
@GetMapping("/updateMaskUrl")
public Response<String> updateMaskUrl(){
designItemService.updateMaskUrl();

View File

@@ -8,20 +8,23 @@ import com.ai.da.model.vo.*;
import com.ai.da.service.CollectionElementService;
import com.ai.da.service.PanToneService;
import com.ai.da.service.SysFileService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.validation.Valid;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Pattern;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@Api(tags = "collection模块")
@Tag(name = "collection模块")
@Slf4j
@RestController
@RequestMapping("/api/element")
@@ -34,7 +37,7 @@ public class ElementController {
@Resource
private SysFileService sysFileService;
@ApiOperation(value = "初始化系统文件")
@Operation(summary = "初始化系统文件")
@PostMapping("/initDefaultSysFile")
public Response<Boolean> initDefaultSysFile(@RequestParam("validate") String validateUse) {
if (validateUse.equals("da_fl_mm_dad88888")) {
@@ -44,22 +47,24 @@ public class ElementController {
return Response.success();
}
@ApiOperation(value = "element文件上传")
@Operation(summary = "element文件上传")
@PostMapping("/upload")
public Response<CollectionElementVO> upload(@RequestParam("file") MultipartFile file,
@ApiParam("一级类型 Moodboard Printboard Sketchboard MarketingSketch Colorboard")
@Parameter(description = "一级类型 Moodboard Printboard Sketchboard MarketingSketch Colorboard")
@RequestParam(value = "level1Type") String level1Type,
@RequestParam(name = "gender", required = false) String gender,
@ApiParam("本地时区,比如 'Asia/Tokyo' 东京时间 , 'Asia/Shanghai' 北京时间 由js本地获取")
@RequestParam(name = "level2Type", required = false) String level2Type,
@RequestParam(name = "projectId", required = false) Long projectId,
@Parameter(description = "本地时区,比如 'Asia/Tokyo' 东京时间 , 'Asia/Shanghai' 北京时间 由js本地获取")
@RequestParam(value = "timeZone") String timeZone) {
if (null == file || StringUtils.isEmpty(file.getOriginalFilename())) {
throw new BusinessException("file.cannot.be.empty");
}
return Response.success(collectionElementService.upload(
new CollectionElementUploadDTO(file, level1Type, gender, timeZone, MD5Utils.encryptFile(file))));
new CollectionElementUploadDTO(file, projectId, level1Type, level2Type, gender, timeZone, MD5Utils.encryptFile(file))));
}
@ApiOperation(value = "element文件删除")
@Operation(summary = "element文件删除")
@PostMapping("/delete")
public Response<Boolean> delete(@Valid @RequestBody CollectionDeleteFileDTO deleteFileDTO) {
collectionElementService.delete(deleteFileDTO.getId());
@@ -68,42 +73,71 @@ public class ElementController {
/** 该功能已删除 */
@Deprecated
@ApiOperation(value = "生成印花")
@Operation(summary = "生成印花")
@PostMapping("/generatePrint")
public Response<GenerateCollectionItemVO> generatePrint(@Valid @RequestBody CollectionGeneratePrintDTO generatePrintDTO) {
return Response.success(collectionElementService.generatePrint(generatePrintDTO));
}
@ApiOperation(value = "保存印花")
@Operation(summary = "保存印花")
@PostMapping("/savePrint")
public Response<Boolean> savePrint(@Valid @RequestBody CollectionSavePrintDTO savePrintDTO) {
return Response.success(collectionElementService.savePrint(savePrintDTO));
}
@ApiOperation(value = "通过tcx值获取潘通信息")
@Operation(summary = "通过tcx值获取潘通信息")
@GetMapping("/getRgbByTcx")
public Response<PantoneVO> getRgbByHsv(@ApiParam("tcx") @RequestParam("tcx") String tcx) {
public Response<PantoneVO> getRgbByHsv(@Parameter(description = "tcx") @RequestParam("tcx") String tcx) {
return Response.success(panToneService.getByTCX(tcx));
}
@ApiOperation(value = "通过hsv值获取潘通信息")
@Operation(summary = "通过hsv值获取潘通信息")
@GetMapping("/getRgbByHsv")
public Response<PantoneVO> getRgbByHsv(@RequestParam("h") Integer h,
@RequestParam("s") Integer s, @RequestParam("v") Integer v) {
return Response.success(panToneService.getByHSV(h, s, v));
}
@ApiOperation(value = "通过hsv值数组批量获取潘通信息")
@Operation(summary = "通过hsv值数组批量获取潘通信息")
@PostMapping("/getRgbByHsvBatch")
public Response<List<PantoneVO>> getRgbByHsvBatch(@RequestBody @Valid List<GetRgbByHsvBatchDTO> rgbByHsvBatch) {
return Response.success(panToneService.getRgbByHsvBatch(rgbByHsvBatch));
}
@ApiOperation(value = "刷新历史数据")
@Operation(summary = "刷新历史数据")
@PostMapping("/refreshHistoryData")
public Response<Boolean> refreshHistoryData() {
collectionElementService.refreshHistoryData();
return Response.success();
}
@Operation(summary = "图片分割")
@PostMapping("/imageSegmentation")
public Response<List<CollectionElementVO>> selectedImageSeg(
@RequestPart(value = "file", required = false) MultipartFile[] file,
@RequestParam(value = "type", required = false) @Pattern(regexp = "sketch|product", message = "Please choose the image type") String type,
@RequestParam(value = "id", required = false) Long id,
@RequestParam(value = "sourceType", required = false) @Pattern(regexp = "Library|Upload", message = "Select an image from the library or upload one.") String sourceType) {
// 过滤空文件
List<MultipartFile> nonEmptyFiles = Arrays.stream(file)
.filter(item -> !item.isEmpty())
.collect(Collectors.toList());
// 参数校验
if ((nonEmptyFiles.isEmpty()) && id == null) {
throw new BusinessException("必须提供文件上传或ID");
}
if (!nonEmptyFiles.isEmpty() && id != null) {
throw new BusinessException("不能同时提供文件上传和ID");
}
return Response.success(collectionElementService.selectedImageSeg(nonEmptyFiles, id, type, sourceType));
}
@Operation(summary = "更新element level2type")
@GetMapping("/updateElementLevel2Type")
public Response<String> updateLibraryLevel2Type(@RequestParam(value = "elementId") Long elementId, @RequestParam(value = "level2Type") String level2Type) {
collectionElementService.updateElementLevel2Type(elementId, level2Type);
return Response.success("success");
}
}

View File

@@ -0,0 +1,42 @@
package com.ai.da.controller;
import com.ai.da.service.EmailService;
import com.alibaba.fastjson.JSONObject;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.thymeleaf.context.Context;
import jakarta.annotation.Resource;
import java.util.Collections;
@Tag(name = "邮件模块")
@Slf4j
@RestController
@RequestMapping("/api/email")
public class EmailController {
@Resource
private EmailService emailService;
@GetMapping("/loadSingleTemplate")
public void loadSingleEmailTemplate(){
emailService.loadSingleEmailTemplate("templates\\upgrade\\122899_AiDA发版完成通知中文版.html");
}
@GetMapping("/loadTemplate")
public void loadTemplatesFromResources(){
emailService.loadTemplatesFromResources("templates");
}
@GetMapping("/sendEmailTest")
public void sendEmailTest(){
Context context = new Context();
context.setVariable("username", "小白");
JSONObject jsonObject = new JSONObject();
jsonObject.put("username", "小白");
emailService.sendEmail(Collections.singletonList("xupei3360@163.com"), jsonObject, "132124_affiliate_accepted_en.html", "测试邮件", null, null );
}
}

View File

@@ -1,101 +1,240 @@
package com.ai.da.controller;
import com.ai.da.common.response.Response;
import com.ai.da.model.dto.GenerateLikeDTO;
import com.ai.da.model.dto.GenerateModifyDTO;
import com.ai.da.model.dto.GenerateThroughImageTextDTO;
import com.ai.da.model.dto.ImageToSketchDTO;
import com.ai.da.model.vo.*;
import com.ai.da.service.GenerateService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
/**
* @author XP
*/
@Api(tags = "Generate模块")
@Slf4j
@RestController
@RequestMapping("/api/generate")
public class GenerateController {
@Resource
private GenerateService generateService;
/*@ApiOperation("自动识别sketch的caption 暂时未上")
@PostMapping("/caption")
public Response<GenerateCaptionVO> generateCaption(@RequestParam Long sketchElementId) {
return Response.success(generateService.generateCaption(sketchElementId));
}*/
/*@ApiOperation("通过文字、图片生成图片")
@PostMapping("/sketchAndPrint")
public void generateThroughImageText(@Valid @RequestBody GenerateThroughImageTextDTO generateThroughImageTextDTO) {
// return Response.success(generateService.generateThroughImageText(generateThroughImageTextDTO));
generateService.generateThroughImageText(generateThroughImageTextDTO);
}*/
@ApiOperation("喜欢生成的图片")
@PostMapping("/like")
public Response<GenerateLikeVO> like(@Valid @RequestBody GenerateLikeDTO generateLikeDTO) {
return Response.success(generateService.generateLike(generateLikeDTO));
}
@ApiOperation(value = "取消喜欢")
@GetMapping("/dislike")
public Response<Boolean> dislike(@ApiParam("generateDetailId") @RequestParam Long generateDetailId,
@ApiParam("timeZone") @RequestParam String timeZone) {
return Response.success(generateService.generateDislike(generateDetailId, timeZone));
}
@ApiOperation(value = "发起生成请求,异步获取结果")
@PostMapping("/prepare")
public Response<PrepareForGenerateVO> prepareForGenerate(@Valid @RequestBody GenerateThroughImageTextDTO generateThroughImageTextDTO) {
return Response.success(generateService.prepareForGenerate(generateThroughImageTextDTO));
}
@ApiOperation(value = "取消继续生成")
@GetMapping("/stopWaiting")
public Response<String> stopWaiting(@RequestParam("userId") Long userId,
@RequestParam("uniqueId") List<String> uniqueId,
@RequestParam("timeZone") String timeZone,
@RequestParam("type") String type) {
generateService.cancelGenerate(userId, uniqueId, timeZone, type);
return Response.success("stop waiting successfully");
}
/*@ApiOperation(value = "获取生成结果")
@GetMapping("/result")
public Response<GenerateCollectionVO> getGenerateResult(@RequestParam("uniqueId") String uniqueId) {
GenerateCollectionVO generateResult = generateService.getGenerateResult(uniqueId);
return Response.success(generateResult);
}*/
@ApiOperation(value = "获取生成结果")
@PostMapping("/result")
public Response<List<GenerateResultVO>> getGenerateResults(@Valid @RequestBody List<String> taskIdList) {
List<GenerateResultVO> generateResult = generateService.getGenerateResultList(taskIdList);
return Response.success(generateResult);
}
@ApiOperation(value = "imageToSketch")
@PostMapping("/imageToSketch")
public Response<GenerateResultVO> imageToSketch(@Valid @RequestBody ImageToSketchDTO imageToSketchDTO) {
return Response.success(generateService.imageToSketch(imageToSketchDTO));
}
// modifySketch
@ApiOperation(value = "modifySketch")
@PostMapping("/modifySketch")
public Response<GenerateResultVO> modifySketch(@Valid @RequestBody GenerateModifyDTO generateModifyDTO) {
return Response.success(generateService.modifySketch(generateModifyDTO));
}
}
package com.ai.da.controller;
import com.ai.da.common.enums.CreditsEventsEnum;
import com.ai.da.common.response.Response;
import com.ai.da.mapper.primary.entity.CollectionSort;
import com.ai.da.model.dto.*;
import com.ai.da.model.vo.*;
import com.ai.da.service.GenerateService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import java.util.List;
import java.util.Map;
/**
* @author XP
*/
@Tag(name = "Generate模块")
@Slf4j
@RestController
@RequestMapping("/api/generate")
public class GenerateController {
@Resource
private GenerateService generateService;
/*@ApiOperation("自动识别sketch的caption 暂时未上")
@PostMapping("/caption")
public Response<GenerateCaptionVO> generateCaption(@RequestParam Long sketchElementId) {
return Response.success(generateService.generateCaption(sketchElementId));
}*/
/*@ApiOperation("通过文字、图片生成图片")
@PostMapping("/sketchAndPrint")
public void generateThroughImageText(@Valid @RequestBody GenerateThroughImageTextDTO generateThroughImageTextDTO) {
// return Response.success(generateService.generateThroughImageText(generateThroughImageTextDTO));
generateService.generateThroughImageText(generateThroughImageTextDTO);
}*/
@Operation(summary = "喜欢生成的图片")
@PostMapping("/like")
public Response<GenerateLikeVO> like(@Valid @RequestBody GenerateLikeDTO generateLikeDTO) {
return Response.success(generateService.generateLike(generateLikeDTO));
}
@Operation(summary = "取消喜欢")
@GetMapping("/dislike")
public Response<Boolean> dislike(@Parameter(description = "generateDetailId") @RequestParam Long generateDetailId,
@Parameter(description = "timeZone") @RequestParam String timeZone) {
return Response.success(generateService.generateDislike(generateDetailId, timeZone));
}
@Operation(summary = "发起生成请求,异步获取结果")
@PostMapping("/prepare")
public ResponseEntity<Response<PrepareForGenerateVO>> prepareForGenerate(@Valid @RequestBody GenerateThroughImageTextDTO generateThroughImageTextDTO) {
PrepareForGenerateVO prepareForGenerateVO = generateService.prepareForGenerate(generateThroughImageTextDTO);
if (prepareForGenerateVO.getStatus().equals(200)){
prepareForGenerateVO.setStatus(0);
return ResponseEntity.ok(Response.success(prepareForGenerateVO));
} else {
return ResponseEntity.status(prepareForGenerateVO.getStatus()).body(Response.fail("The rate limit has been exceeded. Please wait 1 minute before retrying."));
}
}
@Operation(summary = "取消继续生成")
@GetMapping("/stopWaiting")
public Response<String> stopWaiting(@RequestParam("userId") Long userId,
@RequestParam("uniqueId") List<String> uniqueId,
@RequestParam("timeZone") String timeZone,
@RequestParam("type") String type) {
generateService.cancelGenerate(userId, uniqueId, timeZone, type);
return Response.success("stop waiting successfully");
}
/*@ApiOperation(value = "获取生成结果")
@GetMapping("/result")
public Response<GenerateCollectionVO> getGenerateResult(@RequestParam("uniqueId") String uniqueId) {
GenerateCollectionVO generateResult = generateService.getGenerateResult(uniqueId);
return Response.success(generateResult);
}*/
@Operation(summary = "获取生成结果")
@PostMapping("/result")
public Response<List<GenerateResultVO>> getGenerateResults(@Valid @RequestBody List<String> taskIdList) {
List<GenerateResultVO> generateResult = generateService.getGenerateResultList(taskIdList);
return Response.success(generateResult);
}
@Operation(summary = "imageToSketch")
@PostMapping("/imageToSketch")
public Response<String> imageToSketch(@Valid @RequestBody ImageToSketchDTO imageToSketchDTO) {
return Response.success(generateService.imageToSketchAsync(imageToSketchDTO, null, null));
// return Response.success(generateService.imageToSketch(imageToSketchDTO, null, null));
}
// modifySketch
@Operation(summary = "modifySketch")
@PostMapping("/modifySketch")
public Response<GenerateResultVO> modifySketch(@Valid @RequestBody GenerateModifyDTO generateModifyDTO) {
return Response.success(generateService.modifySketch(generateModifyDTO));
}
@Operation(summary = "请求进行姿势变换")
@PostMapping("/poseTransform")
public Response<ToProductImageResultVO> poseTransform(@Valid @RequestBody PoseTransformDTO poseTransformDTO) {
return Response.success(generateService.poseTransform(poseTransformDTO));
}
@Operation(summary = "获取姿势变换生成结果")
@PostMapping("/poseTransformResult")
public Response<List<PoseTransformationVO>> getPoseTransformationResults(@Valid @RequestBody List<String> taskIdList) {
List<PoseTransformationVO> generateResult = generateService.getPoseTransformationResult(taskIdList, null, null);
return Response.success(generateResult);
}
@Operation(summary = "喜欢或取消喜欢姿势变换生成的图片")
@PostMapping("/likeOrDislike")
public Response<CollectionSort> likeOrDislike(@Parameter(description = "id") @RequestParam Long transformedId, @Parameter(description = "like || dislike") @RequestParam String likeOrDislike, @RequestParam("projectId") Long projectId, @RequestParam(value = "collectionSortParentId", required = false) Long collectionSortParentId) {
return Response.success(generateService.disOrLikePose(transformedId, likeOrDislike, projectId, collectionSortParentId));
}
@Operation(summary = "修改模特比例")
@PostMapping("/modifyProportion")
public Response<String> modifyModelProportion(@Valid @RequestBody ModifyModelProportionDTO proportionDTO){
String path = generateService.modifyModelProportion(proportionDTO);
return Response.success(path);
}
@Operation(summary = "拼贴图生成线稿")
@PostMapping("/genSketchRecon")
public Response<GenerateResultVO> sketchReconstructionGenerate(@Valid @RequestBody SketchReconstructionDTO sketchReconstructionDTO){
GenerateResultVO generateResultVO = generateService.sketchReconstructionGenerate(sketchReconstructionDTO);
return Response.success(generateResultVO);
}
@Operation(summary = "获取拼贴图最后一次生成结果")
@GetMapping("/getReconLastResult")
public Response<SketchReconstructionVO> getSketchReconstruction(@RequestParam("projectId") Long projectId){
SketchReconstructionVO sketchReconstruction = generateService.getSketchReconstruction(projectId);
return Response.success(sketchReconstruction);
}
@Operation(summary = "获取pose transfer的所有pose")
@GetMapping("/getAllPose")
public Response<List<Map<String, String>>> getAllPose(){
return Response.success(generateService.getAllPose());
}
@Operation(summary = "删除pose transfer的结果")
@GetMapping("/deleteResult")
public Response<String> deleteToProductRelightResult(@RequestParam("projectId") @NotNull Long projectId,
@RequestParam("id") @NotNull Long id){
try{
generateService.deleteGeneratedPose(projectId, id);
return Response.success();
}catch (Exception e){
return Response.fail(e.getMessage());
}
}
/*@ApiOperation(value = "万象 t2i 创建异步任务")
@GetMapping("/createAsyncTask")
public Response<String> createAsyncTask(@RequestParam("prompt") String prompt){
return Response.success(generateService.createAsyncTask(87L, prompt, ""));
}
@Operation(summary = "万象 t2i 获取异步任务结果")
@GetMapping("/waitAsyncTask")
public Response<GenerateResultVO> waitAsyncTask(@RequestParam("taskId") String taskId){
return Response.success(generateService.getAsyncTaskResult(taskId));
}
@Operation(summary = "万象 图生动图")
@GetMapping("/animateAnyone")
public Response<String> animateAnyone(@Valid @RequestBody PoseTransformDTO poseTransformDTO){
return Response.success(generateService.animateAnyone(poseTransformDTO, null));
}
@Operation(summary = "万象 获取动图模板id")
@GetMapping("/getVideoTemplateId")
public Response<String> getVideoTemplateId(@RequestParam("videoPath") String videoPath){
return Response.success(generateService.getVideoTemplateId(videoPath));
}
@Operation(summary = "万象 获取动图结果")
@GetMapping("/getAnimateResult")
public Response<PoseTransformationVO> getAnimateResult(@RequestParam("taskId") String taskId){
return Response.success(generateService.getAnimateResult(taskId));
}
@Operation(summary = "freepik toProductImage")
@GetMapping("/reimagineFreePik")
public Response<String> reimagineFreePik(@RequestParam("path") String path,
@RequestParam("prompt") String prompt,
@RequestParam("style") String style) throws IOException {
return Response.success(generateService.reimagineFreePik(path, prompt, style));
}
@Operation(summary = "获取图片描述")
@GetMapping("/getImageDescription")
public Response<String> getImageDescription(@RequestParam("path") String path) {
return Response.success(generateService.getImageDescription(path));
}*/
// @Operation(summary = "试用flux")
// @GetMapping("/flux")
public Response<String> flux(@RequestParam(value = "path", required = false) String path,
@RequestParam("type") int type,
@RequestParam(value = "prompt", required = false) String prompt){
CreditsEventsEnum typeEnum = CreditsEventsEnum.RELIGHT;
switch (type){
case 1:
typeEnum = CreditsEventsEnum.TO_PRODUCT_IMAGE;
break;
case 2:
typeEnum = CreditsEventsEnum.IMAGE_TO_SKETCH;
break;
case 3:
typeEnum = CreditsEventsEnum.PATTERN;
break;
}
return Response.success(generateService.flux(typeEnum, prompt, path, false));
}
// @Operation(summary = "获取flux结果")
// @GetMapping("/fluxResult")
public Response<String> fluxResult(@RequestParam("taskId") String taskId){
return Response.success(generateService.getFluxResult(taskId, "87/" + taskId + ".png"));
}
}

View File

@@ -0,0 +1,187 @@
package com.ai.da.controller;
import com.ai.da.common.response.Response;
import com.ai.da.model.dto.*;
import com.ai.da.model.dto.ContestantDTO;
import com.ai.da.model.vo.CheckOTPVO;
import com.ai.da.service.GlobalAwardService;
import com.ai.da.service.upload.UploadService;
import com.ai.da.service.upload.UploadTask;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.Map;
@RestController
@RequestMapping("/api/global-award")
@Api(tags = "全球奖项API", description = "全球奖项大赛管理和文件上传")
public class GlobalAwardController {
@Resource
private GlobalAwardService globalAwardService;
@Resource
private UploadService uploadService;
// @PostMapping("/uploads/pdf")
// public Response<String> uploadPdf(@RequestParam("file") MultipartFile file,
// @RequestParam(value = "email", required = false) String email) throws Exception {
// return Response.success(globalAwardService.uploadPdf(file, email));
// }
//
// @PostMapping("/uploads/video")
// public Response<String> uploadVideo(@RequestParam("file") MultipartFile file,
// @RequestParam(value = "email", required = false) String email) throws Exception {
// return Response.success(globalAwardService.uploadVideo(file, email));
// }
// ===== 新增分片上传接口 =====
// ===== PDF分片上传接口 =====
/** 初始化PDF上传任务 */
@PostMapping("/uploads/pdf/init")
@ApiOperation(value = "初始化PDF上传", notes = "创建新的PDF上传任务并返回上传参数")
public Response<UploadInitResponse> initPdfUpload(@ApiParam(value = "PDF上传初始化请求", required = true) @RequestBody UploadInitRequest request) {
UploadTask uploadTask = uploadService.initPdfUpload(request);
return Response.success(UploadInitResponse.builder()
.uploadId(uploadTask.getUploadId())
.chunkSize(uploadTask.getChunkSize())
.totalChunks(uploadTask.getTotalChunks())
.expiresAt(uploadTask.getExpiresAt())
.build());
}
/** 上传PDF分片 */
@PostMapping("/uploads/pdf/chunk")
@ApiOperation(value = "上传PDF分片", notes = "上传PDF文件的单个分片")
public Response<UploadChunkResponse> uploadPdfChunk(
@ApiParam(value = "PDF文件分片", required = true) @RequestParam("chunk") MultipartFile chunk,
@ApiParam(value = "上传任务ID", required = true) @RequestParam("uploadId") String uploadId,
@ApiParam(value = "分片索引(从0开始)", required = true) @RequestParam("chunkIndex") int chunkIndex,
@ApiParam(value = "分片总数", required = true) @RequestParam("totalChunks") int totalChunks) {
UploadChunkResponse uploadChunkResponse = uploadService.uploadPdfChunk(uploadId, chunk, chunkIndex, totalChunks);
return Response.success(uploadChunkResponse);
}
/** 完成PDF上传 */
@PostMapping("/uploads/pdf/complete")
@ApiOperation(value = "完成PDF上传", notes = "完成PDF上传并合并所有分片")
public Response<UploadCompleteResponse> completePdfUpload(@ApiParam(value = "PDF上传完成请求", required = true) @RequestBody UploadCompleteRequest request) {
UploadCompleteResponse uploadCompleteResponse = uploadService.completePdfUpload(
request.getUploadId(),
request.getFileName(),
request.getTotalSize(),
request.getEmail(),
request.getSecureToken());
return Response.success(uploadCompleteResponse);
}
/** 查询PDF上传状态 */
@GetMapping("/uploads/pdf/status/{uploadId}")
@ApiOperation(value = "查询PDF上传状态", notes = "获取PDF上传任务的当前状态")
public Response<UploadStatusResponse> getPdfUploadStatus(@ApiParam(value = "上传任务ID", required = true) @PathVariable String uploadId) {
UploadStatusResponse pdfUploadStatus = uploadService.getPdfUploadStatus(uploadId);
return Response.success(pdfUploadStatus);
}
// ===== 视频分片上传接口 =====
/** 初始化视频上传任务 */
@PostMapping("/uploads/video/init")
@ApiOperation(value = "初始化视频上传", notes = "创建新的视频上传任务并返回上传参数")
public Response<UploadInitResponse> initVideoUpload(@ApiParam(value = "视频上传初始化请求", required = true) @RequestBody UploadInitRequest request) {
UploadTask uploadTask = uploadService.initVideoUpload(request);
return Response.success(UploadInitResponse.builder()
.uploadId(uploadTask.getUploadId())
.chunkSize(uploadTask.getChunkSize())
.totalChunks(uploadTask.getTotalChunks())
.expiresAt(uploadTask.getExpiresAt())
.build());
}
/** 上传视频分片 */
@PostMapping("/uploads/video/chunk")
@ApiOperation(value = "上传视频分片", notes = "上传视频文件的单个分片")
public Response<UploadChunkResponse> uploadVideoChunk(
@ApiParam(value = "视频文件分片", required = true) @RequestParam("chunk") MultipartFile chunk,
@ApiParam(value = "上传任务ID", required = true) @RequestParam("uploadId") String uploadId,
@ApiParam(value = "分片索引(从0开始)", required = true) @RequestParam("chunkIndex") int chunkIndex,
@ApiParam(value = "分片总数", required = true) @RequestParam("totalChunks") int totalChunks) {
UploadChunkResponse uploadChunkResponse = uploadService.uploadVideoChunk(uploadId, chunk, chunkIndex, totalChunks);
return Response.success(uploadChunkResponse);
}
/** 完成视频上传 */
@PostMapping("/uploads/video/complete")
@ApiOperation(value = "完成视频上传", notes = "完成视频上传并合并所有分片")
public Response<UploadCompleteResponse> completeVideoUpload(@ApiParam(value = "视频上传完成请求", required = true) @RequestBody UploadCompleteRequest request) {
UploadCompleteResponse uploadCompleteResponse = uploadService.completeVideoUpload(
request.getUploadId(),
request.getFileName(),
request.getTotalSize(),
request.getEmail(),
request.getSecureToken());
return Response.success(uploadCompleteResponse);
}
/** 查询视频上传状态 */
@GetMapping("/uploads/video/status/{uploadId}")
@ApiOperation(value = "查询视频上传状态", notes = "获取视频上传任务的当前状态")
public Response<UploadStatusResponse> getVideoUploadStatus(@ApiParam(value = "上传任务ID", required = true) @PathVariable String uploadId) {
UploadStatusResponse videoUploadStatus = uploadService.getVideoUploadStatus(uploadId);
return Response.success(videoUploadStatus);
}
@PostMapping("/contestants/save")
@ApiOperation(value = "保存参赛者信息", notes = "保存或更新参赛者信息及已上传的文件")
public Response<Map<String,Object>> submit(@ApiParam(value = "参赛者信息", required = true) @RequestBody ContestantDTO request) {
return Response.success(globalAwardService.saveContestant(request));
}
@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);
}
@GetMapping("/checkEmail")
public Response<String> checkEmail(@RequestParam("email") String email) {
globalAwardService.checkEmail(email);
return Response.success();
}
@GetMapping("/checkCode")
public Response<CheckOTPVO> checkCode(@RequestParam("email") String email, @RequestParam("code") String code) {
return Response.success(globalAwardService.checkCode(email, code));
}
@GetMapping("/contestants/export")
@ApiOperation(value = "导出参赛者列表为Excel", notes = "导出所有参赛者信息为xlsx并触发下载")
public void exportContestants(HttpServletResponse response) throws Exception {
byte[] data = globalAwardService.exportContestants();
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment; filename=\"contestants.xlsx\"");
response.setContentLength(data.length);
response.getOutputStream().write(data);
response.getOutputStream().flush();
}
@PostMapping("/contestants/export/files")
@ApiOperation(value = "导出参赛者文件到本地", notes = "根据参赛者编号范围导出PDF和视频文件到本地temp/uploads/contestants目录")
public Response<Integer> exportContestantFiles(@ApiParam(value = "参赛者文件导出请求", required = true) @RequestBody ContestantExportRequest request) throws Exception {
int exportedCount = globalAwardService.exportContestantFiles(request.getMinContestantNumber(), request.getMaxContestantNumber());
return Response.success(exportedCount);
}
}

View File

@@ -0,0 +1,74 @@
package com.ai.da.controller;
import com.ai.da.common.response.PageBaseResponse;
import com.ai.da.common.response.Response;
import com.ai.da.mapper.primary.entity.ChatMessage;
import com.ai.da.model.dto.*;
import com.ai.da.service.LLMService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import jakarta.annotation.Resource;
import java.util.*;
@Tag(name = "llm模块")
@Slf4j
@RestController
@RequestMapping("/api/llm")
public class LLMController {
@Resource
private LLMService llmService;
@Operation(summary = "对话")
@CrossOrigin
@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter streamPrompt(@RequestParam String prompt,
@RequestParam(required = false) Long projectId,
@RequestParam(required = false) String fileUrl,
@RequestParam(required = false) List<String> imageUrlList,
@RequestParam(required = false) String process,
@RequestParam String token,
@RequestParam Boolean enableThinking) {
return llmService.stream(prompt, projectId, fileUrl, imageUrlList, token, enableThinking, process);
}
@Operation(summary = "对话")
@CrossOrigin
@GetMapping(value = "/streamNew", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter streamNew(@RequestParam String prompt,
@RequestParam(required = false) Long projectId,
@RequestParam(required = false) String fileUrl,
@RequestParam(required = false) List<String> imageUrlList,
@RequestParam(required = false) String process,
@RequestParam String token,
@RequestParam Boolean enableThinking) {
return llmService.streamNew(prompt, projectId, fileUrl, imageUrlList, token, enableThinking, process);
}
@Operation(summary = "对话创建项目")
@GetMapping(value = "/chatCreateProject")
public Response<Long> chatCreateProject(@RequestParam String prompt, @RequestParam String process,
@RequestParam(required = false) String fileUrl,
@RequestParam(required = false) List<String> imageUrlList) {
return Response.success(llmService.chatCreateProject(prompt, process, fileUrl, imageUrlList));
}
@Operation(summary = "上传文件")
@PostMapping(value = "/uploadFile")
public Response<List<String>> uploadFile(@RequestParam("file") MultipartFile file) {
return Response.success(llmService.uploadFile(file));
}
@Operation(summary = "获取历史聊天记录")
@PostMapping(value = "/getChatHistory")
public Response<PageBaseResponse<ChatMessage>> getChatHistory(@RequestBody ChatHistoryDTO chatHistoryDTO) {
return Response.success(llmService.getChatHistory(chatHistoryDTO));
}
}

View File

@@ -14,25 +14,24 @@ import com.ai.da.model.vo.*;
import com.ai.da.service.LibraryModelPointService;
import com.ai.da.service.LibraryService;
import com.alibaba.fastjson.JSON;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.validation.Valid;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import java.io.File;
import java.text.ParseException;
import java.util.Date;
import java.util.Objects;
import java.util.UUID;
import java.util.*;
@Api(tags = "library模块")
@Tag(name = "library模块")
@Slf4j
@RestController
@RequestMapping("/api/library")
@@ -50,29 +49,30 @@ public class LibraryController {
@Value("${minio.bucketName.sysImage}")
private String sysImage;
@ApiOperation(value = "Library分页列表")
@Operation(summary = "Library分页列表")
@PostMapping("/queryLibraryPage")
public Response<PageBaseResponse<QueryLibraryPageVO>> queryLibraryPage(@Valid @RequestBody QueryLibraryPageDTO query) {
return Response.success(libraryService.queryLibraryPage(CopyUtil.copyObject(query, QueryLibraryPageServiceDTO.class)));
}
@ApiOperation(value = "Library分页列表(查询top和bottom)")
@Operation(summary = "Library分页列表(查询top和bottom)")
@PostMapping("/queryLibraryTopAndBottomPage")
public Response<PageBaseResponse<QueryLibraryPageVO>> queryLibraryTopAndBottomPage(@Valid @RequestBody QueryLibraryTopPageDTO query) {
return Response.success(libraryService.queryLibraryPage(CopyUtil.copyObject(query, QueryLibraryPageServiceDTO.class)));
}
@ApiOperation(value = "Library文件上传")
@Operation(summary = "Library文件上传")
@PostMapping("/upload")
public Response<LibraryUpdateVo> upload(@RequestParam("file") MultipartFile file,
@ApiParam("一级类型 Moodboard Printboard Sketchboard MarketingSketch Models")
@Parameter(description = "一级类型 Moodboard Printboard Sketchboard MarketingSketch Models")
@RequestParam(value = "level1Type") String level1Type,
@ApiParam("二级类型 争对 Sketchboard; 有 Outwear Dress Blouse Skirt Trousers")
@Parameter(description = "二级类型 争对 Sketchboard; 有 Outwear Dress Blouse Skirt Trousers")
@RequestParam(value = "level2Type", required = false) String level2Type,
@ApiParam("本地时区,比如 'Asia/Tokyo' 东京时间 , 'Asia/Shanghai' 北京时间 由js本地获取")
@Parameter(description = "本地时区,比如 'Asia/Tokyo' 东京时间 , 'Asia/Shanghai' 北京时间 由js本地获取")
@RequestParam(value = "timeZone") String timeZone,
@RequestParam(value = "modelType") String modelType,
@RequestParam(value = "sex") String sex,
@RequestParam(value = "ageGroup") String ageGroup,
@RequestParam(value = "checkMd5") Integer checkMd5) {
if (null == file || StringUtils.isEmpty(file.getOriginalFilename())) {
throw new BusinessException("file.cannot.be.empty");
@@ -99,23 +99,23 @@ public class LibraryController {
}
}
return Response.success(libraryService.upload(new LibraryUploadDTO(file, level1Type, level2Type,
timeZone, md5, high, width, modelType, sex)));
timeZone, md5, high, width, modelType, sex, ageGroup)));
}
@ApiOperation(value = "保存或者编辑template打点")
@Operation(summary = "保存或者编辑template打点")
@PostMapping("/saveOrEditTemplatePoint")
public Response<LibraryModelPointVO> saveOrEditTemplatePoint(@Valid @RequestBody LibraryModelPointDTO libraryModelPoint) {
return Response.success(libraryModelPointService.saveOrEditTemplatePoint(libraryModelPoint));
}
@ApiOperation(value = "批量Library修改用户文件名")
@Operation(summary = "批量Library修改用户文件名")
@PostMapping("/batchUpdateLibraryName")
public Response<Boolean> batchUpdateLibraryName(@Valid @RequestBody LibraryUpdateDTO libraryUpdateDTO) {
libraryService.updateLibraryName(libraryUpdateDTO);
return Response.success(Boolean.TRUE);
}
@ApiOperation(value = "批量删除library")
@Operation(summary = "批量删除library")
@PostMapping("/batchDeleteLibrary")
public Response<Boolean> batchDeleteLibrary(@Valid @RequestBody LibraryDeleteDTO deleteDTO) {
libraryService.batchDeleteLibrary(deleteDTO);
@@ -123,10 +123,10 @@ public class LibraryController {
}
@ApiOperation(value = "Models打点预览")
@Operation(summary = "Models打点预览")
@PostMapping("/modelsDot")
public Response<String> modelsDot(@ApiParam("file") @RequestPart(value = "file", required = false) MultipartFile file,
@ApiParam("models对象") @RequestPart("models") ModelsDotDTO modelsDotDTO) {
public Response<String> modelsDot(@Parameter(description = "file") @RequestPart(value = "file", required = false) MultipartFile file,
@Parameter(description = "models对象") @RequestPart("models") ModelsDotDTO modelsDotDTO) {
if (Objects.nonNull(file)) {
if (StringUtils.isEmpty(file.getOriginalFilename())) {
throw new BusinessException("file.cannot.be.empty");
@@ -167,9 +167,9 @@ public class LibraryController {
return response;
}
@ApiOperation(value = "更新sketchboard level2type")
@Operation(summary = "更新sketchboard level2type")
@PostMapping("/updateLibraryLevel2Type")
public Response<Boolean> updateLibraryLevel2Type(@RequestBody LibraryLevel2TypeUpdateDTO libraryLevel2TypeUpdateDTO) {
public Response<Boolean> updateLibraryLevel2Type(@Validated @RequestBody LibraryLevel2TypeUpdateDTO libraryLevel2TypeUpdateDTO) {
return Response.success(libraryService.updateLibraryLevel2Type(libraryLevel2TypeUpdateDTO));
}
@@ -196,10 +196,57 @@ public class LibraryController {
}
@PostMapping("moveLibraryData")
@ApiOperation(value = "用户library数据迁移")
@Operation(summary = "用户library数据迁移")
public Response<Boolean> moveLibraryDate() throws ParseException {
libraryService.moveLibraryDate();
return Response.success(true);
}
@Operation(summary = "将系统模特添加到个人library")
@GetMapping("addSysModelToLib")
public Response<Map<String, String>> addSysModelToLib(@Parameter(description = "系统模特id") @RequestParam("sysModelId")long sysModelId){
return Response.success(libraryService.addSysModelToLib(sysModelId));
}
@Operation(summary = "将个人library元素添加到公共库")
@GetMapping("addToPublicLibrary")
public Response<String> addToPublicLibrary(@Parameter(description = "元素的libraryId") @RequestParam("libraryId") Long libraryId){
boolean b = libraryService.saveToOrganizationLibrary(libraryId);
if (b){
return Response.success("success");
}else {
return Response.success("fail");
}
}
@Operation(summary = "将个人library元素从公共库中删除")
@GetMapping("deleteFromPublicLib")
public Response<String> deleteFromPublicLib(@Parameter(description = "元素的libraryId") @RequestParam("libraryId") Long libraryId){
libraryService.deleteFromPublicLib(libraryId);
return Response.success("success");
}
@Operation(summary = "获取公共库")
@GetMapping("getPublicLib")
public Response<PageBaseResponse<Library>> getPublicLib(@Parameter(description = "排序" ) @RequestParam(value = "order", defaultValue = "DESC", required = false) String order,
@Parameter(description = "page") @RequestParam(value = "page", defaultValue = "1", required = false) Long page,
@Parameter(description = "size") @RequestParam(value = "size", defaultValue = "20", required = false) Long size){
return Response.success(libraryService.getPublicLib(order, page, size));
}
@Operation(summary = "管理员获取所有子账号lib元素")
@GetMapping("getAllSubAccLib")
public Response<PageBaseResponse<Library>> getAllSubAccLib(@Parameter(description = "排序") @RequestParam(value = "order", defaultValue = "DESC", required = false) String order,
@Parameter(description = "page") @RequestParam(value = "page", defaultValue = "1", required = false) Long page,
@Parameter(description = "size") @RequestParam(value = "size", defaultValue = "20", required = false) Long size){
return Response.success(libraryService.getAllSubAccLib(order, page, size));
}
@Operation(summary = "将系统sketch添加到library")
@GetMapping("addSysSketchToLibrary")
public Response<String> addSysSketchToLibrary(Long clothId, String path) {
return Response.success(libraryService.addSysSketchToLibrary(clothId, path));
}
}

View File

@@ -6,17 +6,17 @@ import com.ai.da.model.dto.GetNotificationDTO;
import com.ai.da.model.vo.NotificationVO;
import com.ai.da.model.dto.PublishSysNotificationDTO;
import com.ai.da.service.MessageCenterService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import java.util.List;
import java.util.Map;
@Api(tags = "消息中心模块")
@Tag(name = "消息中心模块")
@Slf4j
@RestController
@RequestMapping("/api/message")
@@ -26,35 +26,35 @@ public class MessageCenterController {
private MessageCenterService messageCenterService;
// 获取未读消息总数
@ApiOperation(value = "获取未读消息数")
@Operation(summary = "获取未读消息数")
@GetMapping("/getUnreadCount")
public Response<Map<String, Long>> getUnreadMessage(){
return Response.success(messageCenterService.getAllTypeMessageUnreadCount());
}
// 获取历史消息
@ApiOperation(value = "获取历史消息")
@Operation(summary = "获取历史消息")
@PostMapping("/getHistoryNotification")
public Response<PageBaseResponse<NotificationVO>> getHistoryNotification(@Valid @RequestBody GetNotificationDTO getNotificationDTO) {
return Response.success(messageCenterService.getHistoryNotification(getNotificationDTO));
}
// 已读消息
@ApiOperation(value = "设置消息状态为已读")
@Operation(summary = "设置消息状态为已读")
@PostMapping("/setReadStatus")
public Response<Boolean> setReadStatus(@RequestParam("notificationIdList") List<Long> notificationIdList, @RequestParam("type") String type) {
return Response.success(messageCenterService.setReadStatus(notificationIdList, type));
}
// 发布系统消息
@ApiOperation(value = "发布系统消息")
@Operation(summary = "发布系统消息")
@PostMapping("/publishSysMessage")
public Response<String> publishSysMessage(@Valid @RequestBody PublishSysNotificationDTO message) {
messageCenterService.publishSystemNotification(message);
return Response.success("success");
}
@ApiOperation(value = "一键已读")
@Operation(summary = "一键已读")
@PostMapping("/oneClickRead")
public Response<String> setReadAll(@RequestParam("type") String type) {
messageCenterService.setReadAll(type);

View File

@@ -7,15 +7,15 @@ import com.ai.da.model.dto.QueryPageByTimeDTO;
import com.ai.da.model.vo.OrderListVO;
import com.ai.da.service.OrderInfoService;
import com.ai.da.service.PaymentInfoService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
@CrossOrigin //开放前端的跨域访问
@Api(tags = "商品订单管理")
@Tag(name = "商品订单管理")
@RestController
@RequestMapping("/api/order-info")
public class OrderInfoController {
@@ -26,7 +26,7 @@ public class OrderInfoController {
@Resource
private PaymentInfoService paymentInfoService;
@ApiOperation("订单列表")
@Operation(summary = "订单列表")
@PostMapping("/list")
public Response<PageBaseResponse<OrderListVO>> list(@Valid @RequestBody QueryPageByTimeDTO queryPageByTimeDTO){
PageBaseResponse<OrderListVO> orderByAccountId = paymentInfoService.getPaymentInfo(queryPageByTimeDTO);
@@ -39,7 +39,7 @@ public class OrderInfoController {
* @param orderNo
* @return
*/
@ApiOperation("查询本地订单状态")
@Operation(summary = "查询本地订单状态")
@GetMapping("/query-order-status/{orderNo}")
public Response<String> queryOrderStatus(@PathVariable String orderNo){
String orderStatus = orderInfoService.getOrderStatus(orderNo);

View File

@@ -7,34 +7,34 @@ import com.paypal.http.HttpResponse;
import com.paypal.http.exceptions.SerializeException;
import com.paypal.orders.Order;
import com.paypal.payments.Refund;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import java.io.IOException;
import java.util.HashMap;
@RestController
@Api(tags = "PayPalCheckout接口")
@Tag(name = "PayPalCheckout接口")
@RequestMapping("/api/paypal")
public class PayPalCheckoutController {
@Resource
private PayPalCheckoutService payPalCheckoutService;
@ApiOperation(value = "创建订单")
@Operation(summary = "创建订单")
@PostMapping(value = "/trade")
public Response<HashMap<String, String>> createOrder(@Valid @RequestBody ProductPurchaseDTO productPurchaseDTO, HttpServletRequest request) throws SerializeException {
HashMap<String, String> approvalUrl = payPalCheckoutService.createOrder(productPurchaseDTO, request);
return Response.success(approvalUrl);
}
@ApiOperation(value = "ipn异步回调")
@Operation(summary = "ipn异步回调")
@PostMapping(value = "/ipn/back")
public Response<String> callback(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Boolean result = payPalCheckoutService.doPost(request, response);
@@ -45,7 +45,7 @@ public class PayPalCheckoutController {
}
}
@ApiOperation(value = "查询指定订单")
@Operation(summary = "查询指定订单")
@PostMapping(value = "/trade/query/{orderNo}")
public Response<Order> queryOrder(@PathVariable String orderNo) throws SerializeException {
Order s = payPalCheckoutService.queryOrder(orderNo);
@@ -53,7 +53,7 @@ public class PayPalCheckoutController {
}
/** 不提供退款接口 */
@ApiOperation("申请退款")
@Operation(summary = "申请退款")
@PostMapping("/trade/refund/{orderNo}/{reason}")
public Response<HttpResponse<Refund>> refund(@PathVariable String orderNo, @PathVariable String reason) throws IOException {
Boolean response = payPalCheckoutService.refundOrder(orderNo,reason);
@@ -64,7 +64,7 @@ public class PayPalCheckoutController {
}
}
@ApiOperation("执行扣款")
@Operation(summary = "执行扣款")
@PostMapping("/trade/capture/{orderNo}")
public Response<com.paypal.orders.Order> captureOrder(@PathVariable String orderNo) throws IOException {
Order response = payPalCheckoutService.captureOrder(orderNo);

View File

@@ -3,24 +3,23 @@ package com.ai.da.controller;
import com.ai.da.common.config.exception.BusinessException;
import com.ai.da.common.response.PageBaseResponse;
import com.ai.da.common.response.Response;
import com.ai.da.mapper.primary.entity.Account;
import com.ai.da.model.dto.*;
import com.ai.da.model.vo.*;
import com.ai.da.model.vo.CommentVO;
import com.ai.da.model.vo.PortfolioVO;
import com.ai.da.model.vo.UserLikeChooseVO;
import com.ai.da.service.PortfolioService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import com.ai.da.service.UserFollowService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.validation.Valid;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import java.util.List;
@Api(tags = "Portfolio模块")
@Tag(name = "Portfolio模块")
@Slf4j
@RestController
@RequestMapping("/api/portfolio")
@@ -29,129 +28,139 @@ public class PortfolioController {
@Resource
private PortfolioService portfolioService;
@ApiOperation(value = "发布作品集")
@Resource
private UserFollowService userFollowService;
@Operation(summary = "发布作品集")
@PostMapping("/publish")
public Response<Long> preLogin(@RequestParam("file") MultipartFile canvas, @RequestParam("data") String data) {
public Response<Long> publish(@RequestParam("file") MultipartFile canvas, @RequestParam("data") String data) {
return Response.success(portfolioService.publish(canvas, data));
}
@ApiOperation(value = "删除作品集")
@Operation(summary = "删除作品集")
@GetMapping("/delete")
public Response<Boolean> delete(@RequestParam("id") Long id) {
return Response.success(portfolioService.delete(id));
}
@CrossOrigin
@ApiOperation(value = "作品集page")
@Operation(summary = "作品集page")
@PostMapping("/page")
public Response<PageBaseResponse<PortfolioVO>> page(@Valid @RequestBody QueryPortfolioPageDTO query) {
return Response.success(portfolioService.page(query));
}
@CrossOrigin
@ApiOperation(value = "作品详情")
@Operation(summary = "作品详情")
@PostMapping("/detail")
public Response<PortfolioVO> detail(@Valid @RequestBody PortfolioDTO portfolioDTO) {
return Response.success(portfolioService.detail(portfolioDTO));
}
@ApiOperation(value = "选择作品")
@Operation(summary = "选择作品")
@PostMapping("/choose")
public Response<UserLikeChooseVO> choose(@Valid @RequestBody PortfolioDTO portfolioDTO) {
public Response<ProjectChooseVO> choose(@Valid @RequestBody PortfolioDTO portfolioDTO) {
return Response.success(portfolioService.choose(portfolioDTO));
}
@ApiOperation(value = "更新作品")
@Operation(summary = "更新作品")
@PostMapping("/update")
public Response<PortfolioVO> update(@Valid @RequestBody PortfolioDTO portfolioDTO) {
return Response.success(portfolioService.update(portfolioDTO));
}
@ApiOperation(value = "广场用户注册")
@Operation(summary = "广场用户注册")
@PostMapping("/designWorksRegister")
public Response<Boolean> designWorksRegister(@Valid @RequestBody DesignWorksRegisterDTO designWorksRegisterDTO) {
return Response.success(portfolioService.designWorksRegister(designWorksRegisterDTO));
}
@ApiOperation(value = "喜欢")
@Operation(summary = "喜欢")
@GetMapping("/like")
public Response<Boolean> like(@RequestParam("id") Long id) {
return Response.success(portfolioService.like(id));
}
@ApiOperation(value = "不喜欢")
@Operation(summary = "不喜欢")
@GetMapping("/unlike")
public Response<Boolean> unlike(@RequestParam("id") Long id) {
return Response.success(portfolioService.unlike(id));
}
@ApiOperation(value = "获取点赞数")
@Operation(summary = "获取点赞数")
@GetMapping("/getLikeCount")
public Response<Long> getLikeCount(@RequestParam("id") Long id) {
return Response.success(portfolioService.getLikeCount(id));
}
@ApiOperation(value = "评论")
@Operation(summary = "评论")
@PostMapping("/comment")
public Response<Boolean> comment(@Valid @RequestBody CommentDTO commentDTO) {
return Response.success(portfolioService.comment(commentDTO));
}
@ApiOperation(value = "评论列表")
@Operation(summary = "评论列表")
@PostMapping("/commentPage")
public Response<PageBaseResponse<CommentVO>> commentPage(@Valid @RequestBody CommentPageDTO commentPageDTO) {
return Response.success(portfolioService.commentPage(commentPageDTO));
}
@ApiOperation(value = "增加浏览量")
@Operation(summary = "增加浏览量")
@GetMapping("/viewsIncrease")
public Response<Boolean> viewsIncrease(@RequestParam("id") Long id) {
return Response.success(portfolioService.viewsIncrease(id));
}
@ApiOperation(value = "浏览量获取")
@Operation(summary = "浏览量获取")
@GetMapping("/viewsGet")
public Response<Long> viewsGet(@RequestParam("id") Long id) {
return Response.success(portfolioService.viewsGet(id));
}
@ApiOperation(value = "删除评论")
@Operation(summary = "删除评论")
@PostMapping("/commentDelete")
public Response<Boolean> commentDelete(@Valid @RequestBody CommentDTO commentDTO) {
return Response.success(portfolioService.commentDelete(commentDTO));
}
@ApiOperation(value = "关注")
@Operation(summary = "关注")
@GetMapping("/follow")
public Response<String> follow(@RequestParam("followeeId") Long followeeId) {
portfolioService.follow(followeeId);
return Response.success(BusinessException.getMessageFromResource("subscription.success"));
}
@ApiOperation(value = "取消关注")
@Operation(summary = "取消关注")
@GetMapping("/cancelFollow")
public Response<String> cancelFollow(@RequestParam("followeeId") Long followeeId) {
portfolioService.cancelFollow(followeeId);
return Response.success(BusinessException.getMessageFromResource("unsubscribe.success"));
}
@ApiOperation(value = "获取关注列表")
@Operation(summary = "获取关注列表")
@PostMapping("/getFolloweeList")
public Response<List<AccountFollowVO>> getFolloweeList(@Valid @RequestBody GetFollowListDTO getFollowListDTO) {
return Response.success(portfolioService.getFolloweeList(getFollowListDTO));
return Response.success(userFollowService.getFolloweeList(getFollowListDTO));
}
@ApiOperation(value = "获取粉丝列表")
@Operation(summary = "获取粉丝列表")
@PostMapping("/getFollowerList")
public Response<List<AccountFollowVO>> getFollowerList(@Valid @RequestBody GetFollowListDTO getFollowListDTO) {
return Response.success(portfolioService.getFollowerList(getFollowListDTO));
return Response.success(userFollowService.getFollowerList(getFollowListDTO));
}
/* @ApiOperation(value = "按标签名查询作品")
/* @Operation(summary = "按标签名查询作品")
@GetMapping("/queryPortfolioByTag")
public Response<List<PortfolioVO>> queryPortfolioByTag(@RequestParam(value = "tagName", required = false) String tagName,
@RequestParam(value = "tagId", required = false) Long tagId) {
return Response.success(portfolioService.queryPortfolioByTag(tagName, tagId));
}*/
@Operation(summary = "将企业或教育版中的作品发布到公共gallery")
@GetMapping("/toPublic")
public Response<String> setPortfolioToPublic(@RequestParam("portfolioId") Long portfolioId) {
portfolioService.setPortfolioToPublic(portfolioId);
return Response.success("success");
}
}

View File

@@ -4,19 +4,19 @@ package com.ai.da.controller;
import com.ai.da.common.response.Response;
import com.ai.da.mapper.primary.entity.Product;
import com.ai.da.service.ProductService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import jakarta.annotation.Resource;
import java.util.Date;
import java.util.List;
@CrossOrigin //开放前端的跨域访问
@Api(tags = "商品管理")
@Tag(name = "商品管理")
@RestController
@RequestMapping("/api/product")
public class ProductController {
@@ -24,14 +24,14 @@ public class ProductController {
@Resource
private ProductService productService;
@ApiOperation("测试接口")
@Operation(summary = "测试接口")
@GetMapping("/test")
public Response<String> test(){
return Response.success("now" + new Date());
}
@ApiOperation("商品列表")
@Operation(summary = "商品列表")
@GetMapping("/list")
public Response<List<Product>> list(){

View File

@@ -0,0 +1,152 @@
package com.ai.da.controller;
import com.ai.da.common.config.MyTaskScheduler;
import com.ai.da.common.response.PageBaseResponse;
import com.ai.da.common.response.Response;
import com.ai.da.model.dto.*;
import com.ai.da.model.vo.*;
import com.ai.da.service.ProjectService;
import com.ai.da.service.UserLikeGroupService;
import com.ai.da.service.WorkspaceService;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.minio.errors.MinioException;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import java.io.IOException;
@Tag(name = "Project模块")
@Slf4j
@RestController
@RequestMapping("/api/project")
public class ProjectController {
@Resource
private WorkspaceService workspaceService;
@Resource
private UserLikeGroupService userLikeGroupService;
@Resource
private ProjectService projectService;
@PostMapping("/saveOrUpdate")
@ApiOperationSupport(order = 1)
@Operation(summary = "新增或编辑", description = "传入project")
public Response<SaveOrUpdateProjectVO> saveOrUpdateProject(@Valid @RequestBody ProjectDTO projectDTO) {
return Response.success(workspaceService.saveOrUpdateProject(projectDTO));
}
@PostMapping("/page")
@ApiOperationSupport(order = 2)
@Operation(summary = "分页查询", description = "传入project")
public Response<PageBaseResponse<ProjectVO>> page(@Valid @RequestBody ProjectQueryDTO projectQueryDTO) {
return Response.success(PageBaseResponse.success(userLikeGroupService.getPage(projectQueryDTO)));
}
// @PostMapping("/detail")
// @ApiOperationSupport(order = 3)
// @ApiOperation(value = "详情", notes = "传入project")
// public Response saveOrUpdateProject(@Valid @RequestBody ProjectDTO projectDTO) {
// return Response.success(workspaceService.saveOrUpdateProject(projectDTO));
// }
//
@PostMapping("/choose")
@ApiOperationSupport(order = 4)
@Operation(summary = "选择", description = "传入project")
public Response<ProjectChooseVO> choose(@Valid @RequestBody ProjectDTO projectDTO) {
return Response.success(userLikeGroupService.choose(projectDTO));
}
@PostMapping("/getModuleContent")
@ApiOperationSupport(order = 5)
@Operation(summary = "获取模块内容", description = "传入project")
public Response<ModuleChooseVO> getModuleContent(@Valid @RequestBody ProjectDTO projectDTO) {
return Response.success(userLikeGroupService.getModuleContent(projectDTO));
}
@PostMapping("/saveModuleContent")
@ApiOperationSupport(order = 6)
@Operation(summary = "存储模块内容", description = "传入project")
public Response<ModuleChooseVO> saveModuleContent(@Valid @RequestBody ModuleSaveDTO moduleSaveDTO) {
return Response.success(userLikeGroupService.saveModuleContent(moduleSaveDTO));
}
//
// @PostMapping("/delete")
// @ApiOperationSupport(order = 5)
// @ApiOperation(value = "删除", notes = "传入project")
// public Response saveOrUpdateProject(@Valid @RequestBody ProjectDTO projectDTO) {
// return Response.success(workspaceService.saveOrUpdateProject(projectDTO));
// }
@PostMapping("/getMannequinDetail")
@ApiOperationSupport(order = 7)
@Operation(summary = "获取模特详情", description = "传入mannequinId")
public Response<QueryLibraryPageVO> getMannequinDetail(@Valid @RequestBody MannequinDTO mannequinDTO) {
return Response.success(userLikeGroupService.getMannequinDetail(mannequinDTO));
}
@PostMapping("/threeDPage")
@ApiOperationSupport(order = 8)
@Operation(summary = "获取3Dpage", description = "传入ThreeDLayoutQueryDTO")
public Response<PageBaseResponse<ThreeDLayoutVO>> threeDPage(@Valid @RequestBody ThreeDLayoutQueryDTO threeDLayoutQueryDTO) {
return Response.success(PageBaseResponse.success(userLikeGroupService.getThreeDLayoutPage(threeDLayoutQueryDTO)));
}
@PostMapping("/getLayoutDetail")
@ApiOperationSupport(order = 9)
@Operation(summary = "获取3D详情", description = "传入project")
public Response<ThreeDVO> getLayoutDetail(@RequestParam(value = "threeDSimpleId") Long threeDSimpleId) {
return Response.success(userLikeGroupService.getLayoutDetail(threeDSimpleId));
}
@PostMapping("/getThreeDSize")
@ApiOperationSupport(order = 10)
@Operation(summary = "获取尺码", description = "传入project")
public Response<ThreeDSizeVO> getThreeDSize(@RequestParam(value = "threeDSimpleId") Long threeDSimpleId) {
return Response.success(userLikeGroupService.getThreeDSize(threeDSimpleId));
}
@GetMapping("/getThreeDGlb")
@ApiOperationSupport(order = 11)
@Operation(summary = "获取GLB", description = "传入project")
public void getThreeDGlb(@RequestParam(value = "threeDSimpleId") Long threeDSimpleId, HttpServletResponse response) throws MinioException, IOException {
userLikeGroupService.getThreeDGlb(threeDSimpleId, response);
}
@GetMapping("/downloadZip")
@ApiOperationSupport(order = 11)
@Operation(summary = "下载", description = "传入project")
public Response<String> downloadZip(@RequestParam(value = "threeDSimpleId") Long threeDSimpleId, @RequestParam(value = "sizeType") String sizeType, @RequestParam(value = "size") String size, HttpServletResponse response) throws MinioException, IOException {
return Response.success(userLikeGroupService.downloadZip(threeDSimpleId, sizeType, size, response));
}
@PostMapping("/delete")
@ApiOperationSupport(order = 12)
@Operation(summary = "删除", description = "传入project")
public Response<Boolean> delete(@RequestParam("projectId") Long projectId) {
return Response.success(userLikeGroupService.delete(projectId));
}
@Resource
private MyTaskScheduler myTaskScheduler;
/*@GetMapping("/dataMigration")
public String dataMigration(){
myTaskScheduler.projectDataCreate();
return "success";
}*/
@GetMapping("/getNextSequence")
public Response<Integer> getNextSequence(){
return Response.success(projectService.getOrCreateSequence());
}
}

View File

@@ -16,14 +16,17 @@ import com.ai.da.service.ChatRobotService;
import com.ai.da.service.LibraryService;
import com.ai.da.service.SuperResolutionService;
import com.ai.da.service.SysFileService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import jakarta.annotation.Resource;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
@@ -31,7 +34,7 @@ import java.util.Map;
import java.util.stream.Collectors;
@Api(tags = "python对接模块")
@Tag(name = "python对接模块")
@Slf4j
@RestController
@RequestMapping("/api/python")
@@ -49,17 +52,17 @@ public class PythonController {
@Resource
private SuperResolutionService superResolutionService;
@ApiOperation(value = "python服务保存图片到java服务")
@Operation(summary = "python服务保存图片到java服务")
@PostMapping("/saveGeneratePicture")
public Response<String> upload(@RequestParam("file") MultipartFile file,
@ApiParam("操作类型 generatePrint ->生成印花 " +
@Parameter(description = "操作类型 generatePrint ->生成印花 " +
"designCollection ->设计collection generateAdvancedDesign ->生成高级design" +
"generateSketch -> 生成草图")
@RequestParam(value = "operateType") String operateType) {
return Response.success(pythonService.upload(file, operateType));
}
// @ApiOperation(value = "python服务保存多张图片到java服务")
// @Operation(summary = "python服务保存多张图片到java服务")
// @PostMapping("/saveMultiGeneratePicture")
// public Response<List<String>> uploadMultiple(@RequestParam("files") MultipartFile[] files,
// @ApiParam("操作类型 generatePrint ->生成印花 " +
@@ -69,13 +72,13 @@ public class PythonController {
// return Response.success(pythonService.upload(files, operateType));
// }
@ApiOperation(value = "通过文件类型获取系统文件")
@Operation(summary = "通过文件类型获取系统文件")
@GetMapping("/getSysFileByLevel2Type")
public Response<List<SysFileVO>> getSysFileByLevel2Type(/*@RequestParam(value = "level2Type",required = false) String level2Type*/) {
return Response.success(sysFileService.getByLevel2Type("All"));
}
@ApiOperation(value = "通过用户id获取library")
@Operation(summary = "通过用户id获取library")
@GetMapping("/getLibraryByUserId")
public Response<Map<String, List<String>>> getLibraryByUserId(@RequestParam(value = "userId") Long userId) {
List<PythonLibraryVo> response = CopyUtil.copyList(libraryService.selectByAccountIdAnd1TypeList(userId,
@@ -86,37 +89,47 @@ public class PythonController {
}
@CrossOrigin
@ApiOperation(value = "发送用户输入消息")
@Operation(summary = "发送用户输入消息")
@PostMapping("/chatStream")
public Response<ChatRobotVO> MessageToPythonChatStream(@RequestBody ChatSendDTO chatSendDTO) {
log.info(chatSendDTO.toString());
return Response.success(chatRobotService.sendMessageToChatRobot(chatSendDTO));
}
@ApiOperation(value = "血条")
@Operation(summary = "血条")
@GetMapping("/getBloodBars")
public Response<BigDecimal> getBloodBars(@RequestParam(value = "userId") Long userId) {
return Response.success(chatRobotService.getBloodBars(userId));
}
@CrossOrigin
@ApiOperation(value = "likeOrUnlike")
@Operation(summary = "likeOrUnlike")
@PostMapping("/pictureLikeOrUnLike")
public Response<Library> pictureLikeOrUnLike(@RequestBody ChatRobotLibraryDTO chatRobotLibraryDTO) {
return Response.success(chatRobotService.pictureLikeOrUnLike(chatRobotLibraryDTO));
}
@CrossOrigin
@ApiOperation(value = "刷新会话缓存")
@Operation(summary = "刷新会话缓存")
@PostMapping("/flush")
public Response<String> ChatBufferFlush(@RequestBody ChatFlushDTO chatFlushDTO) {
return Response.success(chatRobotService.chatBufferFlush(chatFlushDTO));
}
@ApiOperation(value = "超分辨率")
@Operation(summary = "超分辨率")
@PostMapping("/prepareForSR")
public Response<List<String>> superResolution(@RequestBody List<SuperResolutionDTO> superResolutionDTO) {
return Response.success(superResolutionService.prepareForSR(superResolutionDTO));
}
@CrossOrigin
@Operation(summary = "Seg Anything 转发接口")
@PostMapping("/segAnything")
public Response<String> segAnything(@RequestBody Map<String, Object> payload) {
// 将前端传来的 Map 转为 fastjson JSONObject 并转发给 python 服务
JSONObject requestJson = (JSONObject) JSON.toJSON(payload);
String url = pythonService.segAnything(requestJson);
return Response.success(url);
}
}

View File

@@ -17,24 +17,29 @@ 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.google.common.base.Function;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.validation.Valid;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Pattern;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
@Api(tags = "History模块(saved Collection)")
@Tag(name = "History模块(saved Collection)")
@Slf4j
@RestController
@Validated
@RequestMapping("/api/history")
public class SavedCollectionController {
@Resource
@@ -52,7 +57,7 @@ public class SavedCollectionController {
@Resource
private PortfolioService portfolioService;
@ApiOperation(value = "History用户分页分组列表")
@Operation(summary = "History用户分页分组列表")
@PostMapping("/queryUserGroup")
public Response<PageBaseResponse<UserLikeGroupVO>> queryUserGroup(@Valid @RequestBody QueryHistoryPageDTO query) {
AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder();
@@ -143,21 +148,21 @@ public class SavedCollectionController {
return Response.success(PageBaseResponse.success(convert));
}
@ApiOperation(value = "History用户分组详情,目前弃用 ")
@Operation(summary = "History用户分组详情,目前弃用 ")
@GetMapping("/getUserGroupDetail")
public Response<List<UserLikeVO>> getUserGroupDetail(
@ApiParam("用户分组id") @RequestParam("userGroupId") Long userGroupId) {
@Parameter(description = "用户分组id") @RequestParam("userGroupId") Long userGroupId) {
return Response.success(userLikeService.getGroupDetail(userGroupId));
}
@ApiOperation(value = "History修改用户分组名")
@Operation(summary = "History修改用户分组名")
@PostMapping("/updateUserGroupName")
public Response<HistoryUpdateVO> updateUserGroupName(@Valid @RequestBody HistoryUpdateDTO historyUpdateDTO) {
return Response.success(userLikeGroupService.updateUserGroupName(historyUpdateDTO.getUserGroupId()
, historyUpdateDTO.getUserGroupName(), historyUpdateDTO.getTimeZone()));
}
@ApiOperation(value = "History删除用户分组")
@Operation(summary = "History删除用户分组")
@PostMapping("/deleteUserGroup")
public Response<Boolean> deleteUserGroup(@Valid @RequestBody HistoryDeleteDTO deleteDTO) {
userLikeGroupService.deleteUserGroup(deleteDTO.getUserGroupId());
@@ -165,96 +170,175 @@ public class SavedCollectionController {
return Response.success(Boolean.TRUE);
}
@ApiOperation(value = "History choose")
@Operation(summary = "History choose")
@GetMapping("/choose")
public Response<UserLikeChooseVO> choose(
@ApiParam("用户分组id") @RequestParam("userGroupId") Long userGroupId) {
@Parameter(description = "用户分组id") @RequestParam("userGroupId") Long userGroupId) {
return Response.success(userLikeGroupService.choose(userGroupId));
}
@ApiOperation(value = "exportSave")
@Operation(summary = "exportSave")
@PostMapping("/exportSave")
public Response<Boolean> exportSave(@RequestParam("file") MultipartFile file, @RequestParam("userLikeGroupId") Long userLikeGroupId) {
return Response.success(userLikeGroupService.exportSave(file, userLikeGroupId));
public Response<Long> exportSave(@RequestParam("file") MultipartFile file, @RequestParam(value = "projectId", required = false) Long projectId,
@RequestParam("module") String module, @RequestParam(value = "designItemDetailId", required = false) Long designItemDetailId) {
return Response.success(userLikeGroupService.exportSave(file, projectId, module, designItemDetailId));
}
@ApiOperation(value = "exportSearch")
@Operation(summary = "exportSearch")
@PostMapping("/exportSearch")
public Response<JSONObject> exportSearch(@Valid @RequestBody ExportSearchDTO exportSearchDTO) {
return Response.success(userLikeGroupService.exportSearch(exportSearchDTO.getUserLikeGroupId()));
return Response.success(userLikeGroupService.exportSearch(exportSearchDTO));
}
@ApiOperation(value = "toProduct")
@Operation(summary = "toProduct")
@PostMapping("/toProduct")
public Response<List<ToProductImageResult>> toProduct(@Valid @RequestBody ToProductImageDTO toProductImageDTO) {
public Response<List<ToProductImageResultVO>> toProduct(@Valid @RequestBody ToProductImageDTO toProductImageDTO) {
return Response.success(userLikeGroupService.toProduct(toProductImageDTO));
}
@ApiOperation(value = "toProductImageElementUpload")
@Operation(summary = "toProductImageElementUpload")
@PostMapping("/toProductImageElementUpload")
public Response<ToProductElementVO> toProductImageElementUpload(@RequestParam("file") MultipartFile file, @RequestParam(value = "userlikeGroupId") Long userLikeGroupId) {
return Response.success(userLikeGroupService.toProductImageElementUpload(file, userLikeGroupId));
public Response<ToProductElementVO> toProductImageElementUpload(@RequestParam("file") MultipartFile file,
@RequestParam(value = "projectId", required = false) Long projectId,
@Parameter(description = "首尾帧", example = "first",
schema = @Schema(allowableValues = {"first", "last"}))
@RequestParam(value = "type", required = false) String type) {
return Response.success(userLikeGroupService.toProductImageElementUpload(file, projectId, type));
}
@ApiOperation(value = "productImageLike")
@Operation(summary = "toProductImageElementDelete")
@PostMapping("/toProductImageElementDelete")
public Response<Boolean> toProductImageElementDelete(@RequestParam(value = "id") Long id) {
return Response.success(userLikeGroupService.toProductImageElementDelete(id));
}
@Operation(summary = "productImageLike")
@PostMapping("/productImageLike")
public Response<Boolean> productImageLike(@Valid @RequestBody ProductImageLikeDTO productImageLikeDTO) {
return Response.success(userLikeGroupService.productImageLike(productImageLikeDTO));
public Response<CollectionSort> productImageLike(@Valid @RequestBody ProductImageLikeDTO productImageLikeDTO) {
CollectionSort collectionSort = userLikeGroupService.productImageLike(productImageLikeDTO);
return Response.success(collectionSort);
}
@ApiOperation(value = "productImageUnLike")
@Operation(summary = "collectionLikeUpdate")
@PostMapping("/collectionLikeUpdate")
public Response<Boolean> collectionLikeUpdate(@Valid @RequestBody CollectionLikeUpdateDTO collectionLikeUpdateDTO) {
return Response.success(userLikeGroupService.collectionLikeUpdate(collectionLikeUpdateDTO));
}
@Operation(summary = "productImageUnLike")
@PostMapping("/productImageUnLike")
public Response<Boolean> productImageUnLike(@Valid @RequestBody ProductImageLikeDTO productImageLikeDTO) {
return Response.success(userLikeGroupService.productImageUnLike(productImageLikeDTO));
}
@ApiOperation(value = "获取生成结果")
@Operation(summary = "获取生成结果")
@PostMapping("/toProductImageResult")
public Response<List<MagicToolResultVO>> getToProductImageResult(@Valid @RequestBody List<String> taskIdList) {
List<MagicToolResultVO> magicToolResultVOList = userLikeGroupService.getToProductImageResultList(taskIdList);
return Response.success(magicToolResultVOList);
}
@ApiOperation(value = "画布用户上传元素")
@Operation(summary = "画布用户上传元素")
@PostMapping("/canvasElementUpload")
public Response<CanvasElementUpload> canvasElementUpload(@RequestParam("file") MultipartFile file) {
return Response.success(userLikeGroupService.canvasElementUpload(file));
}
@ApiOperation("productImageLikeList")
@Operation(summary = "productImageLikeList")
@PostMapping("/productImageLikeList")
public Response<List<ToProductImageResultVO>> productImageLikeList(@Valid @RequestBody ToProductImageDTO toProductImageDTO) {
return Response.success(userLikeGroupService.productImageLikeList(toProductImageDTO));
}
@ApiOperation(value = "relight")
@Operation(summary = "relight")
@PostMapping("/relight")
public Response<List<ToProductImageResult>> relight(@Valid @RequestBody ToProductImageDTO toProductImageDTO) {
public Response<List<ToProductImageResultVO>> relight(@Valid @RequestBody ToProductImageDTO toProductImageDTO) {
return Response.success(userLikeGroupService.relight(toProductImageDTO));
}
@ApiOperation(value = "获取relight结果")
@Operation(summary = "relight元素")
@PostMapping("/convertRelightElement")
public Response<ToProductElementVO> convertRelightElement(@RequestParam("id") Long id) {
return Response.success(userLikeGroupService.convertRelightElement(id));
}
@Operation(summary = "获取relight结果")
@PostMapping("/relightResult")
public Response<List<MagicToolResultVO>> getRelightResult(@Valid @RequestBody List<String> taskIdList) {
List<MagicToolResultVO> magicToolResultVOList = userLikeGroupService.getRelightResult(taskIdList);
return Response.success(magicToolResultVOList);
}
@ApiOperation(value = "likeHistoryRelSketch")
@Operation(summary = "删除toProduct Relight的结果")
@GetMapping("/deleteResult")
public Response<String> deleteResult(@RequestParam("id") Long id,
@RequestParam("projectId") Long projectId,
@RequestParam("type") @Pattern(regexp = "^(Relight|ToProductImage)$", message = "Please choose type from 'Relight|ToProductImage'") String type){
try{
userLikeGroupService.deleteToProductRelightResult(id, projectId, type);
return Response.success();
}catch (Exception e){
return Response.fail(e.getMessage());
}
}
@Operation(summary = "likeHistoryRelSketch")
@PostMapping("/likeHistoryRelSketch")
public Response<String> likeHistoryRelSketch() {
return Response.success(userLikeGroupService.likeHistoryRelSketch());
}
@ApiOperation(value = "download")
@Operation(summary = "download")
@PostMapping("/download")
public Response<String> download() {
return Response.success(userLikeGroupService.download());
}
@ApiOperation(value = "productImageInitialize")
@Operation(summary = "productImageInitialize")
@PostMapping("/productImageInitialize")
public Response<Boolean> productImageUpload(@Valid @RequestBody ProductImageInitializeDTO productImageInitializeDTO) {
return Response.success(userLikeGroupService.productImageInitialize(productImageInitializeDTO));
}
@Operation(summary = "getInitializeProgress")
@PostMapping("/getInitializeProgress")
public Response<InitializeProgressVO> getInitializeProgress(@Valid @RequestBody ProductImageInitializeDTO productImageInitializeDTO) {
return Response.success(userLikeGroupService.getInitializeProgress(productImageInitializeDTO));
}
@Operation(summary = "brandDNASaveOrUpdate")
@PostMapping("/brandDNASaveOrUpdate")
public Response<Boolean> brandDNASaveOrUpdate(@Valid @RequestBody BrandDNADTO brandDNADTO) {
return Response.success(userLikeGroupService.brandDNASaveOrUpdate(brandDNADTO));
}
@Operation(summary = "brandDNADelete")
@PostMapping("/brandDNADelete")
public Response<Boolean> brandDNADelete(@Valid @RequestBody BrandDNADTO brandDNADTO) {
return Response.success(userLikeGroupService.brandDNADelete(brandDNADTO));
}
@Operation(summary = "brandDNAPage")
@PostMapping("/brandDNAPage")
public Response<PageBaseResponse<BrandDNAVO>> brandDNAPage(@Valid @RequestBody BrandDNAQueryDTO brandDNAQueryDTO) {
return Response.success(userLikeGroupService.brandDNAPage(brandDNAQueryDTO));
}
@Operation(summary = "brandLogoUpload")
@PostMapping("/brandLogoUpload")
public Response<BrandLogoUploadVO> brandDNASaveOrUpdate(@RequestParam("file") MultipartFile file) {
return Response.success(userLikeGroupService.brandLogoUpload(file));
}
@Operation(summary = "brandDNAUpload")
@PostMapping("/brandDNAUpload")
public Response<LibraryUpdateVo> brandDNAUpload(@RequestParam("file") MultipartFile file, @RequestParam("brandId") Long brandId) throws IOException {
return Response.success(userLikeGroupService.brandDNAUpload(file, brandId));
}
@Operation(summary = "brandDNAGenerate")
@PostMapping("/brandDNAGenerate")
public Response<BrandDNAGenerateVO> brandDNAGenerate(@RequestParam("prompt") String prompt) {
return Response.success(userLikeGroupService.brandDNAGenerate(prompt));
}
}

View File

@@ -14,27 +14,26 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.paypal.http.HttpResponse;
import com.paypal.payments.Refund;
import com.stripe.exception.StripeException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import java.io.IOException;
import java.util.Date;
import java.util.List;
@Api(tags = "Stripe模块")
@Tag(name = "Stripe模块")
@Slf4j
@RestController
@RequestMapping("/api/stripe")
@ApiIgnore
//@ApiIgnore
public class StripeController {
@Resource
@@ -42,7 +41,7 @@ public class StripeController {
@Resource
private RedisUtil redisUtil;
@ApiOperation("创建支付链接")
@Operation(summary = "创建支付链接")
@PostMapping("/createOrder")
public Response<String> pay(@Valid @RequestBody ProductPurchaseDTO productPurchaseDTO, HttpServletRequest request) {
return Response.success(stripeService.pay(productPurchaseDTO, request));
@@ -51,7 +50,7 @@ public class StripeController {
@Value("${stripe.webhook.fail.reminder}")
private String webhookReminderFlag;
@ApiOperation("支付通知")
@Operation(summary = "支付通知")
@PostMapping("/trade/notify")
public void callback(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try{
@@ -71,13 +70,13 @@ public class StripeController {
Long size = redisUtil.getSize(key_1);
// 给我发送邮件
if (webhookReminderFlag.equals("1") && size == 3){
SendEmailUtil.commonExceptionReminder("Stripe Webhook 回调", new String[]{"xupei3360@163.com"});
SendEmailUtil.commonExceptionReminder("Stripe Webhook 回调处理出现异常", new String[]{"xupei3360@163.com"});
}
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
}
@ApiOperation("申请退款")
@Operation(summary = "申请退款")
@GetMapping("/trade/refund/{orderNo}/{reason}")
public Response<HttpResponse<Refund>> refund(@PathVariable String orderNo, @PathVariable String reason) throws IOException {
String response = stripeService.refund(null,orderNo,reason);
@@ -88,7 +87,7 @@ public class StripeController {
}
}
@ApiOperation("获取订阅")
@Operation(summary = "获取订阅")
@GetMapping("/getSubscription")
public Response<List<String>> getSubscription(@RequestParam String name, @RequestParam String email) {
try {
@@ -98,44 +97,44 @@ public class StripeController {
}
}
@ApiOperation("取消订阅")
@Operation(summary = "取消订阅")
@GetMapping("/cancelSubscription")
public Response<String> cancelSubscription(@RequestParam String subscriptionId, @RequestParam(required = false) String reason) {
stripeService.cancelSubscription(subscriptionId, reason);
return Response.success("success");
}
@ApiOperation("创建推广码")
@Operation(summary = "创建推广码")
@PostMapping("/createCoupon")
public Response<String> createCoupon(@Valid @RequestBody CreateCouponDTO createCouponDTO){
return Response.success(stripeService.createCoupon(createCouponDTO));
}
@ApiOperation("检查推广码")
@Operation(summary = "检查推广码")
@GetMapping("/checkCoupon")
public Response<CheckCouponsVO> checkCoupon(@RequestParam String promotionCode, @RequestParam Long price){
return Response.success(stripeService.checkProductCoupon(promotionCode, price));
}
@ApiOperation("获取所有推广码")
@Operation(summary = "获取所有推广码")
@PostMapping("/getAllCoupons")
public Response<IPage<ProductCoupons>> getAllCoupons(@RequestBody QueryCouponsPageDTO queryCouponsPageDTO){
return Response.success(stripeService.getAllCoupons(queryCouponsPageDTO));
}
@ApiOperation("检索优惠券")
@Operation(summary = "检索优惠券")
@GetMapping("/retrieveCoupon")
public Response<String> retrieveCoupon(@RequestParam String couponId){
return Response.success(stripeService.retrieveCoupon(couponId));
}
@ApiOperation("检索推广码")
@Operation(summary = "检索推广码")
@GetMapping("/retrievePromotionCode")
public Response<String> retrievePromotionCode(@RequestParam String retrievePromotionCode){
return Response.success(stripeService.retrievePromotionCode(retrievePromotionCode));
}
@ApiOperation("更新推广码信息")
@Operation(summary = "更新推广码信息")
@GetMapping("/updatePromCodeInfo")
public Response<ProductCoupons> updateCouponsInfo(@RequestParam Long id, @RequestParam(required = false) String paidCommission,
@RequestParam(required = false) String cooperator,
@@ -144,7 +143,7 @@ public class StripeController {
return Response.success(stripeService.updateCouponsInfo(id, paidCommission, cooperator, remark, startTime));
}
@ApiOperation("删除推广码")
@Operation(summary = "删除推广码")
@GetMapping("/deletePromCode")
public Response<String> deleteCoupon(@RequestParam Long id){
stripeService.deleteCoupon(id);
@@ -158,31 +157,31 @@ public class StripeController {
return Response.success("success");
}
@ApiOperation("创建订阅 临时")
@Operation(summary = "创建订阅 临时")
@GetMapping("/createSubscriptionTemp")
public Response<String> createSubscriptionTemp(@RequestParam String name, @RequestParam String email) {
return Response.success(stripeService.createSubscriptionTemp(name, email));
}
@ApiOperation("修改用户默认支付方式 临时")
@Operation(summary = "修改用户默认支付方式 临时")
@GetMapping("/changeCustomerPayment")
public Response<String> changeCustomerPayment(@RequestParam String name, @RequestParam String email) {
return Response.success(stripeService.changeCustomerPayment(name, email));
}
@ApiOperation("临时 发送续订失败邮件")
@Operation(summary = "临时 发送续订失败邮件")
@GetMapping("/sendRenewalFailEmail")
public Response<Boolean> sendRenewalFailEmail(@RequestParam String invoiceId, @RequestParam String subscriptionId, @RequestParam String orderNo) {
return Response.success(stripeService.sendRenewalFailEmail(invoiceId, subscriptionId,orderNo));
}
@ApiOperation("临时 查询指定用户绑定的付款方式")
@Operation(summary = "临时 查询指定用户绑定的付款方式")
@GetMapping("/getCustomerPaymentMethod")
public Response<List<Map<String,String>>> getCustomerPaymentMethod(@RequestParam String name, @RequestParam String email) {
return Response.success(stripeService.getCustomerPaymentMethod(name, email));
}
@ApiOperation("临时 解绑指定用户绑定的所有付款方式")
@Operation(summary = "临时 解绑指定用户绑定的所有付款方式")
@GetMapping("/detachCustomerAllPaymentMethod")
public Response<String> detachCustomerAllPaymentMethod(@RequestParam String name, @RequestParam String email) {
return Response.success(stripeService.detachCustomerAllPaymentMethod(name, email));

View File

@@ -0,0 +1,112 @@
package com.ai.da.controller;
import com.ai.da.common.response.Response;
import com.ai.da.common.task.SubscriptionReminderTask;
import com.ai.da.mapper.primary.entity.SubscriptionPlan;
import com.ai.da.model.dto.SubscriptionPlanDTO;
import com.ai.da.model.dto.SubscriptionPlanPageQuery;
import com.ai.da.model.dto.UpdateSubscriptionPlanDTO;
import com.ai.da.model.vo.SubscriptionPlanVO;
import com.ai.da.service.SubscriptionPlanService;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Tag(name = "订阅计划模块")
@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/api/subscription_plan")
public class SubscriptionPlanController {
private final SubscriptionPlanService subscriptionPlanService;
private final SubscriptionReminderTask subscriptionReminderTask;
@Operation(summary = "创建订阅计划")
@PostMapping("/createPlan")
public Response<String> createPlan(@Valid @RequestBody SubscriptionPlanDTO subscriptionPlanDTO) {
subscriptionPlanService.createPlan(subscriptionPlanDTO);
return Response.success();
}
@Operation(summary = "更新订阅计划")
@PostMapping("/updatePlan")
public Response<String> updatePlan(@Valid @RequestBody UpdateSubscriptionPlanDTO updateDTO) {
subscriptionPlanService.updatePlan(updateDTO);
return Response.success();
}
@Operation(summary = "搜索订阅计划")
@PostMapping("/searchByOrganizationIdAndStatus")
public Response<List<SubscriptionPlan>> searchByOrganizationIdAndStatus(@Valid @RequestBody SubscriptionPlanPageQuery subscriptionPlanPageQuery) {
return Response.success(subscriptionPlanService.searchByOrganizationIdAndStatus(subscriptionPlanPageQuery));
}
@Operation(summary = "分页搜索订阅计划")
@PostMapping("/searchByPage")
public Response<IPage<SubscriptionPlanVO>> searchByPage(@Valid @RequestBody SubscriptionPlanPageQuery subscriptionPlanPageQuery) {
IPage<SubscriptionPlanVO> subscriptionPlanVOIPage = subscriptionPlanService.searchByPage(subscriptionPlanPageQuery);
return Response.success(subscriptionPlanVOIPage);
}
@Operation(summary = "删除订阅计划")
@GetMapping("/deletePlan")
public Response<String> deletePlan(@RequestParam Long id) {
subscriptionPlanService.deletePlan(id);
return Response.success();
}
@Operation(summary = "管理员切换订阅计划")
@GetMapping("/switchSubscriptionPlan")
public Response<String> switchSubscriptionPlan(@RequestParam Long targetSubscriptionPlanId, @RequestParam(required = false) Long adminAccId) {
subscriptionPlanService.switchSubscriptionPlan(targetSubscriptionPlanId, adminAccId);
return Response.success();
}
@Operation(summary = "子账号切换订阅计划")
@GetMapping("/switchSubAccSubscriptionPlan")
public Response<String> switchSubAccSubscriptionPlan(@RequestParam Long targetSubscriptionPlanId, @RequestParam Long subAccId) {
subscriptionPlanService.switchSubAccSubscriptionPlan(targetSubscriptionPlanId, subAccId);
return Response.success();
}
// @Hidden
@Operation(summary = "activeSubscriptionPlan")
@GetMapping("/activeSubscriptionPlan")
public Response<String> activeSubscriptionPlan() {
subscriptionPlanService.activeSubscriptionPlan(null);
return Response.success();
}
// @Hidden
@Operation(summary = "expireSubscription")
@GetMapping("/expireSubscription")
public Response<String> expireSubscription() {
subscriptionPlanService.expireSubscription();
return Response.success();
}
@Operation(summary = "subscriptionReminder")
@GetMapping("/subscriptionReminder")
public Response<String> subscriptionReminder() {
subscriptionReminderTask.subscriptionReminder();
return Response.success();
}
@Operation(summary = "trialReminder")
@GetMapping("/trialReminder")
public Response<String> trialReminder() {
subscriptionReminderTask.trialReminder();
return Response.success();
}
}

View File

@@ -6,16 +6,16 @@ import com.ai.da.mapper.primary.entity.Product;
import com.ai.da.mapper.primary.entity.Tags;
import com.ai.da.service.ProductService;
import com.ai.da.service.TagsService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import jakarta.annotation.Resource;
import java.util.Date;
import java.util.List;
@CrossOrigin //开放前端的跨域访问
@Api(tags = "标签管理")
@Tag(name = "标签管理")
@RestController
@RequestMapping("/api/tags")
public class TagsController {
@@ -23,7 +23,7 @@ public class TagsController {
@Resource
private TagsService tagsService;
@ApiOperation("获取标签")
@Operation(summary = "获取标签")
@GetMapping("/getTags")
public Response<List<Tags>> getTags(@RequestParam(value = "userInput", required = false) String userInput) {
return Response.success(tagsService.getTags(userInput));

View File

@@ -7,16 +7,16 @@ import com.ai.da.model.dto.SuperResolutionDTO;
import com.ai.da.model.dto.TaskDTO;
import com.ai.da.model.vo.TaskVO;
import com.ai.da.service.TaskListService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import java.util.List;
@Api(tags = "任务列表模块")
@Tag(name = "任务列表模块")
@Slf4j
@RestController
@RequestMapping("/api/tasks")
@@ -26,13 +26,13 @@ public class TaskListController {
private TaskListService taskListService;
@PostMapping("/getList")
@ApiOperation("获取未执行完的任务")
@Operation(summary = "获取未执行完的任务")
public Response<List<TaskDTO<SuperResolutionDTO>>> getTaskList(@Valid @RequestBody List<String> taskIdList) {
return Response.success(taskListService.getExecTask(taskIdList));
}
@PostMapping("/getAllTask")
@ApiOperation("获取所有任务")
@Operation(summary = "获取所有任务")
public Response<PageBaseResponse<TaskVO>> getAllTask(@Valid @RequestBody QueryTaskHistoryDTO queryTaskHistoryDTO) {
return Response.success(taskListService.getAllTask(queryTaskHistoryDTO));
}

View File

@@ -1,149 +1,167 @@
package com.ai.da.controller;
import com.ai.da.common.response.Response;
import com.ai.da.mapper.primary.entity.GoogleUser;
import com.ai.da.model.dto.*;
import com.ai.da.model.vo.AccountLoginVO;
import com.ai.da.model.vo.DesignCollectionVO;
import com.ai.da.service.AccountService;
import com.ai.da.service.DesignService;
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.security.cert.X509Certificate;
@Api(tags = "Third Party Modules")
@Slf4j
@RestController
@RequestMapping("/api/third/party")
public class ThirdPartyController {
@Resource
private AccountService accountService;
@Resource
private DesignService designService;
/*@ApiOperation(value = "Add user information")
@PostMapping("/addUser")
public Response<Boolean> addUser(@Valid @RequestBody AccountAddDTO accountAddDTO) {
return Response.success(accountService.addUser(accountAddDTO));
}*/
@ApiOperation(value = "Edit user information")
@PostMapping("/editUser")
public Response<Boolean> editUser(@RequestBody AccountEditDTO accountEditDTO) {
return Response.success(accountService.editUser(accountEditDTO));
}
@CrossOrigin
@ApiOperation(value = "Add user information")
@PostMapping("/addTrialUser")
public Response<Boolean> addTrialUser(@RequestBody AccountTrialDTO accountTrialDTO, HttpServletRequest request) {
return Response.success(accountService.addTrialUser(accountTrialDTO, request));
}
@CrossOrigin
@ApiOperation(value = "add No Login Required")
@PostMapping("/addNoLoginRequired")
public Response<Boolean> addNoLoginRequired(@RequestBody NoLoginRequiredDTO noLoginRequiredDTO) {
return Response.success(accountService.addNoLoginRequired(noLoginRequiredDTO));
}
@CrossOrigin
@ApiOperation(value = "add No Login Required")
@PostMapping("/deleteNoLoginRequired")
public Response<Boolean> deleteNoLoginRequired(@RequestBody NoLoginRequiredDTO noLoginRequiredDTO) {
return Response.success(accountService.deleteNoLoginRequired(noLoginRequiredDTO));
}
@CrossOrigin
@ApiOperation(value = "add No Login Required")
@PostMapping("/existNoLoginRequired")
public Response<Boolean> existNoLoginRequired(@RequestBody NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request) {
return Response.success(accountService.existNoLoginRequired(noLoginRequiredDTO, request));
}
@GetMapping("/your-secured-endpoint")
// @PreAuthorize("hasRole('ROLE_USER')")
public String securedEndpoint(HttpServletRequest request, @AuthenticationPrincipal PreAuthenticatedAuthenticationToken authenticationToken) {
// 从请求属性中获取证书
X509Certificate[] certificates = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
if (certificates != null && certificates.length > 0) {
X509Certificate clientCertificate = certificates[0];
// 可以从 clientCertificate 中获取证书信息,例如主题、颁发者等
String subject = clientCertificate.getSubjectX500Principal().getName();
String issuer = clientCertificate.getIssuerX500Principal().getName();
// 处理逻辑
return "Secured Endpoint. Client Subject: " + subject + ", Issuer: " + issuer;
} else {
// 证书不存在或获取失败
return "Failed to retrieve client certificate.";
}
}
@CrossOrigin
@ApiOperation(value = "add No Login Required")
@PostMapping("/addNoLoginRequiredNew")
public Response<String> addNoLoginRequiredNew(@RequestBody NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request) {
return Response.success(accountService.addNoLoginRequiredNew(noLoginRequiredDTO, request));
}
@CrossOrigin
@ApiOperation(value = "add No Login Required")
@PostMapping("/deleteNoLoginRequiredNew")
public Response<Boolean> deleteNoLoginRequiredNew(@RequestBody NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request) {
return Response.success(accountService.deleteNoLoginRequiredNew(noLoginRequiredDTO, request));
}
@Value("${redirect_url}")
private String REDIRECT_URL;
@CrossOrigin
@ApiOperation(value = "add No Login Required")
@PostMapping("/getRedirectUrl")
public Response<String> getRedirectUrl() {
return Response.success(REDIRECT_URL);
}
@CrossOrigin
@ApiOperation(value = "updateNoLoginRequiredNew")
@PostMapping("/updateNoLoginRequiredNew")
public Response<String> updateNoLoginRequiredNew(@RequestBody NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request) {
return Response.success(accountService.updateNoLoginRequiredNew(noLoginRequiredDTO, request));
}
@CrossOrigin
@GetMapping("/auth/google_callback")
public Response<String> googleCallback(@RequestParam("code") String code, HttpSession session) {
return Response.success(accountService.googleCallback(code, session));
}
@CrossOrigin
@GetMapping("/parseGoogleCredential")
public Response<AccountLoginVO> parseGoogleCredential(@RequestParam("credential") String credential, @RequestParam("type") Integer type) {
return Response.success(accountService.parseGoogleCredential(credential, type));
}
@CrossOrigin
@GetMapping("/parseWeChatCode")
public Response<AccountLoginVO> parseWeChatCode(@RequestParam("code") String code, @RequestParam("type") Integer type) {
return Response.success(accountService.parseWeChatCode(code, type));
}
@ApiOperation(value = "接收Design结果")
@PostMapping("/receiveDesignResults")
@CrossOrigin
public Response<Boolean> receiveDesignResults(@Valid @RequestBody JSONObject responseObject) {
return Response.success(designService.receiveDesignResults(responseObject));
}
}
package com.ai.da.controller;
import com.ai.da.common.constant.CommonConstant;
import com.ai.da.common.response.Response;
import com.ai.da.common.utils.MinioUtil;
import com.ai.da.mapper.primary.entity.GoogleUser;
import com.ai.da.model.dto.*;
import com.ai.da.model.vo.AccountLoginVO;
import com.ai.da.model.vo.DesignCollectionVO;
import com.ai.da.service.AccountService;
import com.ai.da.service.DesignService;
import com.alibaba.fastjson.JSONObject;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import jakarta.validation.Valid;
import java.security.cert.X509Certificate;
@Tag(name = "Third Party Modules")
@Slf4j
@RestController
@RequestMapping("/api/third/party")
public class ThirdPartyController {
@Resource
private AccountService accountService;
@Resource
private DesignService designService;
@Resource
private MinioUtil minioUtil;
/*@ApiOperation(value = "Add user information")
@PostMapping("/addUser")
public Response<Boolean> addUser(@Valid @RequestBody AccountAddDTO accountAddDTO) {
return Response.success(accountService.addUser(accountAddDTO));
}*/
@Operation(summary = "Edit user information")
@PostMapping("/editUser")
public Response<Boolean> editUser(@RequestBody AccountEditDTO accountEditDTO) {
return Response.success(accountService.editUser(accountEditDTO));
}
@CrossOrigin
@Operation(summary = "Add user information")
@PostMapping("/addTrialUser")
public Response<Boolean> addTrialUser(@RequestBody AccountTrialDTO accountTrialDTO, HttpServletRequest request) {
return Response.success(accountService.addTrialUser(accountTrialDTO, request));
}
@CrossOrigin
@Operation(summary = "add No Login Required")
@PostMapping("/addNoLoginRequired")
public Response<Boolean> addNoLoginRequired(@RequestBody NoLoginRequiredDTO noLoginRequiredDTO) {
return Response.success(accountService.addNoLoginRequired(noLoginRequiredDTO));
}
@CrossOrigin
@Operation(summary = "add No Login Required")
@PostMapping("/deleteNoLoginRequired")
public Response<Boolean> deleteNoLoginRequired(@RequestBody NoLoginRequiredDTO noLoginRequiredDTO) {
return Response.success(accountService.deleteNoLoginRequired(noLoginRequiredDTO));
}
@CrossOrigin
@Operation(summary = "add No Login Required")
@PostMapping("/existNoLoginRequired")
public Response<Boolean> existNoLoginRequired(@RequestBody NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request) {
return Response.success(accountService.existNoLoginRequired(noLoginRequiredDTO, request));
}
@GetMapping("/your-secured-endpoint")
// @PreAuthorize("hasRole('ROLE_USER')")
public String securedEndpoint(HttpServletRequest request, @AuthenticationPrincipal PreAuthenticatedAuthenticationToken authenticationToken) {
// 从请求属性中获取证书
X509Certificate[] certificates = (X509Certificate[]) request.getAttribute("jakarta.servlet.request.X509Certificate");
if (certificates != null && certificates.length > 0) {
X509Certificate clientCertificate = certificates[0];
// 可以从 clientCertificate 中获取证书信息,例如主题、颁发者等
String subject = clientCertificate.getSubjectX500Principal().getName();
String issuer = clientCertificate.getIssuerX500Principal().getName();
// 处理逻辑
return "Secured Endpoint. Client Subject: " + subject + ", Issuer: " + issuer;
} else {
// 证书不存在或获取失败
return "Failed to retrieve client certificate.";
}
}
@CrossOrigin
@Operation(summary = "add No Login Required")
@PostMapping("/addNoLoginRequiredNew")
public Response<String> addNoLoginRequiredNew(@RequestBody NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request) {
return Response.success(accountService.addNoLoginRequiredNew(noLoginRequiredDTO, request));
}
@CrossOrigin
@Operation(summary = "add No Login Required")
@PostMapping("/deleteNoLoginRequiredNew")
public Response<Boolean> deleteNoLoginRequiredNew(@RequestBody NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request) {
return Response.success(accountService.deleteNoLoginRequiredNew(noLoginRequiredDTO, request));
}
@Value("${redirect_url}")
private String REDIRECT_URL;
@CrossOrigin
@Operation(summary = "add No Login Required")
@PostMapping("/getRedirectUrl")
public Response<String> getRedirectUrl() {
return Response.success(REDIRECT_URL);
}
@CrossOrigin
@Operation(summary = "updateNoLoginRequiredNew")
@PostMapping("/updateNoLoginRequiredNew")
public Response<String> updateNoLoginRequiredNew(@RequestBody NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request) {
return Response.success(accountService.updateNoLoginRequiredNew(noLoginRequiredDTO, request));
}
@CrossOrigin
@GetMapping("/auth/google_callback")
public Response<String> googleCallback(@RequestParam("code") String code, HttpSession session) {
return Response.success(accountService.googleCallback(code, session));
}
@CrossOrigin
@GetMapping("/parseGoogleCredential")
public Response<AccountLoginVO> parseGoogleCredential(@RequestParam("credential") String credential, @RequestParam("type") Integer type) {
return Response.success(accountService.parseGoogleCredential(credential, type));
}
@CrossOrigin
@GetMapping("/parseWeChatCode")
public Response<AccountLoginVO> parseWeChatCode(@RequestParam("code") String code, @RequestParam("type") Integer type) {
return Response.success(accountService.parseWeChatCode(code, type));
}
@Operation(summary = "接收Design结果")
@PostMapping("/receiveDesignResults")
@CrossOrigin
public Response<Boolean> receiveDesignResults(@Valid @RequestBody JSONObject responseObject) {
return Response.success(designService.receiveDesignResults(responseObject));
}
@Operation(summary = "接收Design入参")
@PostMapping("/receiveDesignParams")
@CrossOrigin
public Response<Boolean> receiveDesignParams(@Valid @RequestBody ReceiveDesignParam receiveDesignParam) {
return Response.success(designService.receiveDesignParams(receiveDesignParam));
}
@Operation(summary = "刷新minio预签名地址")
@GetMapping("/refreshMinioUrl")
public Response<String> refreshMinioUrl(@RequestParam("path") String path){
return Response.success(minioUtil.getPreSignedUrl(path, CommonConstant.MINIO_IMAGE_EXPIRE_TIME));
}
}

View File

@@ -3,6 +3,7 @@ package com.ai.da.controller;
import com.ai.da.common.response.Response;
import com.ai.da.mapper.primary.entity.Style;
import com.ai.da.mapper.primary.entity.Workspace;
import com.ai.da.model.dto.ProjectDTO;
import com.ai.da.model.dto.WorkspaceDTO;
import com.ai.da.model.dto.WorkspaceSaveDTO;
import com.ai.da.model.enums.BizJson;
@@ -10,14 +11,14 @@ import com.ai.da.model.vo.ModelsVO;
import com.ai.da.model.vo.StyleVO;
import com.ai.da.model.vo.WorkspaceVO;
import com.ai.da.service.WorkspaceService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import lombok.AllArgsConstructor;
import javax.annotation.Resource;
import javax.validation.Valid;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import lombok.NoArgsConstructor;
import org.springframework.web.bind.annotation.*;
@@ -35,7 +36,7 @@ import java.util.List;
@AllArgsConstructor
@NoArgsConstructor
@RequestMapping("/api/workspace")
@Api(value = "", tags = "工作空间")
@Tag(name = "工作空间")
public class WorkspaceController {
@Resource
@@ -46,8 +47,8 @@ public class WorkspaceController {
*/
@GetMapping("/detail")
@ApiOperationSupport(order = 1)
@ApiOperation(value = "详情", notes = "传入workspace")
public Response<WorkspaceVO> detail(@ApiParam(value = "主键集合", required = true) @RequestParam Long id) {
@Operation(summary = "详情", description = "传入workspace")
public Response<WorkspaceVO> detail(@Parameter(description = "主键集合", required = true) @RequestParam Long id) {
WorkspaceVO detail = workspaceService.getByIdNew(id);
return Response.success(detail);
}
@@ -57,7 +58,7 @@ public class WorkspaceController {
*/
@PostMapping("/list")
@ApiOperationSupport(order = 2)
@ApiOperation(value = "分页", notes = "传入workspace")
@Operation(summary = "分页", description = "传入workspace")
public Response<WorkspaceVO> list(@Valid @RequestBody WorkspaceDTO query) {
WorkspaceVO response = workspaceService.getPage(query);
return Response.success(response);
@@ -68,7 +69,7 @@ public class WorkspaceController {
*/
@PostMapping("/saveOrUpdate")
@ApiOperationSupport(order = 3)
@ApiOperation(value = "新增或编辑", notes = "传入workspace")
@Operation(summary = "新增或编辑", description = "传入workspace")
public Response saveOrUpdate(@Valid @RequestBody WorkspaceSaveDTO workspaceDTO) {
return Response.success(workspaceService.saveOrUpdate(workspaceDTO));
}
@@ -79,14 +80,14 @@ public class WorkspaceController {
*/
@DeleteMapping("/remove")
@ApiOperationSupport(order = 4)
@ApiOperation(value = "删除", notes = "传入id")
@Operation(summary = "删除", description = "传入id")
public Response<List<Long>> remove(@Valid @RequestBody List<Workspace> workspaceList) {
return Response.success(workspaceService.delete(workspaceList));
}
@GetMapping("/enumValues")
@ApiOperationSupport(order = 5)
@ApiOperation(value = "获取枚举类值")
@Operation(summary = "获取枚举类值")
public Response<List<BizJson>> enumValues(@RequestParam("enumName") String enumName) {
List<BizJson> bizJsonList = workspaceService.getEnumValues(enumName);
return Response.success(bizJsonList);
@@ -94,16 +95,16 @@ public class WorkspaceController {
@GetMapping("/getMannequins")
@ApiOperationSupport(order = 6)
@ApiOperation(value = "获取模特")
public Response<List<ModelsVO>> getMannequins(@RequestParam("sex") String sex, @RequestParam("style") String style) {
List<ModelsVO> modelsVO = workspaceService.getMannequins(sex, style);
@Operation(summary = "获取模特")
public Response<List<ModelsVO>> getMannequins(@RequestParam("sex") String sex, @RequestParam("style") String style, @RequestParam("ageGroup") String ageGroup) {
List<ModelsVO> modelsVO = workspaceService.getMannequins(sex, style, ageGroup);
return Response.success(modelsVO);
}
@PostMapping("system_file_copy")
@ApiOperationSupport(order = 7)
@ApiOperation(value = "minio数据迁移")
@Operation(summary = "minio数据迁移")
public Response<Boolean> systemFileCopy() {
workspaceService.systemFileCopy();
return Response.success(true);
@@ -111,24 +112,31 @@ public class WorkspaceController {
@PostMapping("moveFile")
@ApiOperationSupport(order = 7)
@ApiOperation(value = "增加一级性别路径")
@Operation(summary = "增加一级性别路径")
public Response<Boolean> moveFile() {
workspaceService.moveFile();
return Response.success(true);
}
@PostMapping("maleDataInsert")
@GetMapping("/maleDataInsert")
@ApiOperationSupport(order = 8)
@ApiOperation(value = "男装数据入库入minio")
@Operation(summary = "男装数据入库入minio")
public Response<Boolean> maleDataInsert() throws FileNotFoundException {
workspaceService.maleDataInsert();
// workspaceService.maleDataInsert();
return Response.success(true);
}
@PostMapping("styleList")
@ApiOperationSupport(order = 9)
@ApiOperation(value = "获取style列表")
@Operation(summary = "获取style列表")
public Response<List<StyleVO>> styleList() {
return Response.success(workspaceService.styleList());
}
@PostMapping("/saveOrUpdateProject")
@ApiOperationSupport(order = 3)
@Operation(summary = "新增或编辑", description = "传入project")
public Response saveOrUpdateProject(@Valid @RequestBody ProjectDTO projectDTO) {
return Response.success(workspaceService.saveOrUpdateProject(projectDTO));
}
}

View File

@@ -0,0 +1,7 @@
package com.ai.da.mapper.primary;
import com.ai.da.mapper.primary.entity.APIGenerate;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface APIGenerateMapper extends BaseMapper<APIGenerate> {
}

View File

@@ -2,8 +2,8 @@ package com.ai.da.mapper.primary;
import com.ai.da.common.config.mybatis.plus.CommonMapper;
import com.ai.da.mapper.primary.entity.Account;
import com.ai.da.model.dto.AccountCreditsUsageDTO;
import java.util.Date;
import java.util.List;
/**
@@ -32,4 +32,10 @@ public interface AccountMapper extends CommonMapper<Account> {
void toVisitor(Long id);
List<AccountCreditsUsageDTO> selectCreditUsage(boolean groupByEvent, String changeEvent, String role,
String userEmail, Long id, String startTime, String endTime,
Integer size, Integer offset, String organizationName);
int countCreditUsage(boolean groupByEvent, String changeEvent, String role, String userEmail, Long id, String startTime, String endTime, String organizationName);
}

View File

@@ -1,14 +0,0 @@
package com.ai.da.mapper.primary;
import com.ai.da.mapper.primary.entity.AffiliateIncome;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
import java.util.Map;
public interface AffiliateIncomeMapper extends BaseMapper<AffiliateIncome> {
List<Map<String, Object>> getPersonalMonthlyIncome(Long affiliateAccountId, int year);
List<Map<String, Object>> getMonthlyAffiliateIncome(int year, int month);
}

View File

@@ -12,8 +12,10 @@ public interface AffiliateMapper extends BaseMapper<Affiliate> {
Map<String, Long> getMonthlyApprovedAffiliate(int year, int month);
List<AffiliateVO> getAffiliateList(String status, String startTime, String endTime,
String order, Long affiliateId, int size, int offset);
String order, Long affiliateId, String sortField, int size, int offset);
int queryAffiliateTotalCount(String status, String startTime, String endTime, Long affiliateId);
List<Map<String, Object>> selectAllAffiliateUsername();
}

Some files were not shown because too many files have changed in this diff Show More