Explorar el Código

Merge remote-tracking branch 'origin/master'

# Conflicts:
#	alien-entity/src/main/java/shop/alien/entity/store/StoreCashOutRecord.java
#	alien-store/src/main/java/shop/alien/store/controller/StoreIncomeDetailsRecordController.java
#	alien-store/src/main/java/shop/alien/store/service/impl/StoreIncomeDetailsRecordServiceImpl.java
lyx hace 4 meses
padre
commit
2a64f249b0
Se han modificado 100 ficheros con 3912 adiciones y 1507 borrados
  1. 125 0
      VIDEO_MODERATION_DATABASE_DESIGN.md
  2. 265 0
      VIDEO_MODERATION_USER_GUIDE.md
  3. 1 0
      alien-api/src/main/resources/bootstrap-prod.yml
  4. 1 0
      alien-api/src/main/resources/bootstrap-test.yml
  5. 1 1
      alien-api/src/main/resources/logback-spring.xml
  6. 24 0
      alien-config/src/main/java/shop/alien/config/properties/VideoModerationProperties.java
  7. 70 0
      alien-entity/src/main/java/shop/alien/entity/SecondVideoTask.java
  8. 10 0
      alien-entity/src/main/java/shop/alien/entity/result/BusinessException.java
  9. 9 0
      alien-entity/src/main/java/shop/alien/entity/second/SecondGoods.java
  10. 121 0
      alien-entity/src/main/java/shop/alien/entity/second/SecondGoodsRecord.java
  11. 4 0
      alien-entity/src/main/java/shop/alien/entity/second/SecondTradeRecord.java
  12. 3 0
      alien-entity/src/main/java/shop/alien/entity/second/vo/SecondGoodsRecommendVo.java
  13. 8 0
      alien-entity/src/main/java/shop/alien/entity/store/LifeDiscountCoupon.java
  14. 15 0
      alien-entity/src/main/java/shop/alien/entity/store/StoreCashOutRecord.java
  15. 4 0
      alien-entity/src/main/java/shop/alien/entity/store/StoreInfo.java
  16. 3 0
      alien-entity/src/main/java/shop/alien/entity/store/dto/LifeDiscountCouponDto.java
  17. 13 7
      alien-entity/src/main/java/shop/alien/entity/store/excelVo/util/ExcelGenerator.java
  18. 1 1
      alien-entity/src/main/java/shop/alien/entity/store/vo/LifeCouponVo.java
  19. 10 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/LifeDiscountCouponVo.java
  20. 53 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/LifeGroupBuyMainVo.java
  21. 10 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/ManagementInfoVo.java
  22. 26 4
      alien-entity/src/main/java/shop/alien/entity/store/vo/ScreeningOfEightMajorCategoriesVO.java
  23. 4 0
      alien-entity/src/main/java/shop/alien/entity/store/vo/StoreInfoVo.java
  24. 23 5
      alien-entity/src/main/java/shop/alien/mapper/LifeGroupBuyThaliMapper.java
  25. 29 24
      alien-entity/src/main/java/shop/alien/mapper/LifeMessageMapper.java
  26. 35 0
      alien-entity/src/main/java/shop/alien/mapper/PlatformStoreLifeGroupBuyMainMapper.java
  27. 4 0
      alien-entity/src/main/java/shop/alien/mapper/StoreIncomeDetailsRecordMapper.java
  28. 12 3
      alien-entity/src/main/java/shop/alien/mapper/StoreInfoMapper.java
  29. 7 0
      alien-entity/src/main/java/shop/alien/mapper/second/SecondGoodsRecordMapper.java
  30. 1 1
      alien-entity/src/main/java/shop/alien/mapper/second/SecondRecommendMapper.java
  31. 63 0
      alien-entity/src/main/java/shop/alien/mapper/system/SecondVideoTaskMapper.java
  32. 5 1
      alien-entity/src/main/resources/mapper/ManagementInfoMapper.xml
  33. 25 0
      alien-entity/src/main/resources/mapper/VideoModerationTaskMapper.xml
  34. 17 3
      alien-entity/src/main/resources/mapper/second/SecondGoodsInfoMapper.xml
  35. 5 0
      alien-entity/src/main/resources/mapper/second/SecondGoodsRecordMapper.xml
  36. 1 0
      alien-gateway/src/main/resources/bootstrap-prod.yml
  37. 1 0
      alien-gateway/src/main/resources/bootstrap-test.yml
  38. 1 1
      alien-gateway/src/main/resources/logback-spring.xml
  39. 5 0
      alien-job/pom.xml
  40. 1 2
      alien-job/src/main/java/shop/alien/job/AlienJobApplication.java
  41. 31 1
      alien-job/src/main/java/shop/alien/job/feign/AlienStoreFeign.java
  42. 27 0
      alien-job/src/main/java/shop/alien/job/feign/SecondGoodsFeign.java
  43. 73 0
      alien-job/src/main/java/shop/alien/job/jobhandler/VideoModerationJobHandler.java
  44. 99 96
      alien-job/src/main/java/shop/alien/job/second/SecondGoodsTradeXxlJob.java
  45. 9 9
      alien-job/src/main/java/shop/alien/job/store/DeliciousFoodJob.java
  46. 4 4
      alien-job/src/main/java/shop/alien/job/store/KTVJob.java
  47. 164 0
      alien-job/src/main/java/shop/alien/job/store/LifeCouponJob.java
  48. 79 0
      alien-job/src/main/java/shop/alien/job/store/LifeReverseGroupBuyingJob.java
  49. 14 32
      alien-job/src/main/java/shop/alien/job/store/MassageFootBathJob.java
  50. 118 0
      alien-job/src/main/java/shop/alien/job/store/StoreIncomeDetailsJob.java
  51. 9 10
      alien-job/src/main/java/shop/alien/job/store/StoreMembershipCardJob.java
  52. 1 0
      alien-job/src/main/resources/bootstrap-prod.yml
  53. 1 0
      alien-job/src/main/resources/bootstrap-test.yml
  54. 1 1
      alien-job/src/main/resources/logback-spring.xml
  55. 2 0
      alien-second/src/main/java/shop/alien/second/AlienSecondApplication.java
  56. 56 8
      alien-second/src/main/java/shop/alien/second/controller/SecondGoodsController.java
  57. 20 7
      alien-second/src/main/java/shop/alien/second/controller/SecondTradeRecordController.java
  58. 77 0
      alien-second/src/main/java/shop/alien/second/controller/VideoModerationController.java
  59. 1 1
      alien-second/src/main/java/shop/alien/second/feign/AlienStoreFeign.java
  60. 15 2
      alien-second/src/main/java/shop/alien/second/service/SecondGoodsService.java
  61. 3 3
      alien-second/src/main/java/shop/alien/second/service/SecondTradeRecordService.java
  62. 35 0
      alien-second/src/main/java/shop/alien/second/service/VideoModerationService.java
  63. 28 10
      alien-second/src/main/java/shop/alien/second/service/impl/SecondGoodsReportingServiceImpl.java
  64. 280 18
      alien-second/src/main/java/shop/alien/second/service/impl/SecondGoodsServiceImpl.java
  65. 3 1
      alien-second/src/main/java/shop/alien/second/service/impl/SecondRecommendServiceImpl.java
  66. 43 28
      alien-second/src/main/java/shop/alien/second/service/impl/SecondTradeRecordServiceImpl.java
  67. 204 0
      alien-second/src/main/java/shop/alien/second/service/impl/VideoModerationServiceImpl.java
  68. 335 0
      alien-second/src/main/java/shop/alien/second/task/Task.java
  69. 1 0
      alien-second/src/main/resources/bootstrap-prod.yml
  70. 1 0
      alien-second/src/main/resources/bootstrap-test.yml
  71. 1 1
      alien-second/src/main/resources/logback-spring.xml
  72. 14 8
      alien-store/src/main/java/shop/alien/store/config/WebSocketProcess.java
  73. 4 2
      alien-store/src/main/java/shop/alien/store/controller/AliController.java
  74. 11 0
      alien-store/src/main/java/shop/alien/store/controller/LifeCollectController.java
  75. 11 9
      alien-store/src/main/java/shop/alien/store/controller/LifeDiscountCouponController.java
  76. 15 21
      alien-store/src/main/java/shop/alien/store/controller/LifeMessageController.java
  77. 47 8
      alien-store/src/main/java/shop/alien/store/controller/PlatformStoreCouponController.java
  78. 28 6
      alien-store/src/main/java/shop/alien/store/controller/StoreIncomeDetailsRecordController.java
  79. 4 3
      alien-store/src/main/java/shop/alien/store/controller/StoreInfoController.java
  80. 1 0
      alien-store/src/main/java/shop/alien/store/controller/WebSocketController.java
  81. 11 21
      alien-store/src/main/java/shop/alien/store/service/LifeAppealManageService.java
  82. 2 2
      alien-store/src/main/java/shop/alien/store/service/LifeDiscountCouponService.java
  83. 2 0
      alien-store/src/main/java/shop/alien/store/service/LifeMessageService.java
  84. 10 42
      alien-store/src/main/java/shop/alien/store/service/LifeUserOrderService.java
  85. 1 1
      alien-store/src/main/java/shop/alien/store/service/LifeUserStoreService.java
  86. 9 2
      alien-store/src/main/java/shop/alien/store/service/PlatformStoreCouponService.java
  87. 16 0
      alien-store/src/main/java/shop/alien/store/service/StoreIncomeDetailsRecordService.java
  88. 1 1
      alien-store/src/main/java/shop/alien/store/service/StoreInfoService.java
  89. 198 82
      alien-store/src/main/java/shop/alien/store/service/impl/LifeDiscountCouponServiceImpl.java
  90. 33 4
      alien-store/src/main/java/shop/alien/store/service/impl/LifeDiscountCouponUserServiceImpl.java
  91. 16 50
      alien-store/src/main/java/shop/alien/store/service/impl/LifeMessageServiceImpl.java
  92. 1 1
      alien-store/src/main/java/shop/alien/store/service/impl/LifeStoreOrderServiceImpl.java
  93. 10 9
      alien-store/src/main/java/shop/alien/store/service/impl/LifeUserViolationServiceImpl.java
  94. 271 32
      alien-store/src/main/java/shop/alien/store/service/impl/PlatformStoreCouponServiceImpl.java
  95. 8 7
      alien-store/src/main/java/shop/alien/store/service/impl/StoreActivityServiceImpl.java
  96. 109 2
      alien-store/src/main/java/shop/alien/store/service/impl/StoreIncomeDetailsRecordServiceImpl.java
  97. 251 305
      alien-store/src/main/java/shop/alien/store/service/impl/StoreInfoServiceImpl.java
  98. 10 10
      alien-store/src/main/java/shop/alien/store/service/impl/StoreStaffConfigServiceImpl.java
  99. 67 64
      alien-store/src/main/java/shop/alien/store/service/impl/StoreUserServiceImpl.java
  100. 0 530
      alien-store/src/main/java/shop/alien/store/task/ScheduledTask.java

+ 125 - 0
VIDEO_MODERATION_DATABASE_DESIGN.md

@@ -0,0 +1,125 @@
+# 视频审核系统数据库设计文档
+
+## 1. 概述
+
+本文档详细描述了视频审核系统的数据库设计方案,包括表结构设计、字段说明、状态管理、索引设计以及落库逻辑等内容。
+
+## 2. 表结构设计
+
+### 2.1 表名
+`video_moderation_task` - 视频审核任务表
+
+### 2.2 表结构
+
+```sql
+CREATE TABLE `video_moderation_task` (
+  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+  `data_id` varchar(64) NOT NULL COMMENT '数据ID',
+  `video_url` varchar(512) NOT NULL COMMENT '视频URL',
+  `task_id` varchar(64) NOT NULL COMMENT '任务ID',
+  `status` varchar(20) NOT NULL DEFAULT 'SUBMITTED' COMMENT '任务状态 (SUBMITTED-已提交, PROCESSING-处理中, SUCCESS-成功, FAILED-失败)',
+  `risk_level` varchar(10) DEFAULT NULL COMMENT '风险级别 (none-无风险, low-低风险, medium-中风险, high-高风险)',
+  `result` text COMMENT '审核结果(JSON格式)',
+  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  `retry_count` int(11) NOT NULL DEFAULT '0' COMMENT '重试次数',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `uk_task_id` (`task_id`),
+  KEY `idx_status` (`status`),
+  KEY `idx_create_time` (`create_time`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='视频审核任务表';
+```
+
+### 2.3 字段说明
+
+| 字段名 | 类型 | 允许空 | 默认值 | 说明 |
+|-------|------|-------|--------|------|
+| id | bigint(20) | 否 | 无 | 主键ID,自增 |
+| data_id | varchar(64) | 否 | 无 | 数据ID,用于标识审核的数据 |
+| video_url | varchar(512) | 否 | 无 | 视频URL地址 |
+| task_id | varchar(64) | 否 | 无 | 阿里云审核任务ID |
+| status | varchar(20) | 否 | SUBMITTED | 任务状态 |
+| risk_level | varchar(10) | 是 | NULL | 风险级别 |
+| result | text | 是 | NULL | 审核结果,JSON格式存储 |
+| create_time | datetime | 否 | CURRENT_TIMESTAMP | 创建时间 |
+| update_time | datetime | 否 | CURRENT_TIMESTAMP | 更新时间 |
+| retry_count | int(11) | 否 | 0 | 重试次数 |
+
+## 3. 状态管理
+
+系统中任务的状态流转如下:
+
+- **SUBMITTED**: 任务已提交到阿里云,等待处理
+- **PROCESSING**: 任务正在处理中
+- **SUCCESS**: 任务处理成功,审核完成
+- **FAILED**: 任务处理失败
+
+状态流转图:
+```
+SUBMITTED -> PROCESSING -> SUCCESS
+      |          |-> FAILED
+      |-> FAILED (提交失败)
+```
+
+## 4. 索引设计
+
+为了提高查询效率,表中设计了以下索引:
+
+1. **主键索引**: `id` 字段,用于唯一标识每条记录
+2. **唯一索引**: `task_id` 字段,确保阿里云任务ID的唯一性
+3. **普通索引**: `status` 字段,提高按状态查询任务的效率
+4. **普通索引**: `create_time` 字段,提高按创建时间查询任务的效率
+
+## 5. 落库逻辑
+
+### 5.1 提交任务时的落库逻辑
+
+当用户提交视频审核任务时,系统会执行以下落库操作:
+
+1. 生成唯一的数据ID (`data_id`)
+2. 调用阿里云接口提交视频审核任务
+3. 获取阿里云返回的`task_id`
+4. 将任务信息保存到数据库中,初始状态为`SUBMITTED`
+
+### 5.2 异步拉取结果时的落库逻辑
+
+通过XXL-JOB定时任务定期拉取审核结果:
+
+1. 查询数据库中状态为`SUBMITTED`或`PROCESSING`的任务
+2. 调用阿里云接口获取审核结果
+3. 根据结果更新数据库中的任务状态:
+   - 如果审核完成,更新状态为`SUCCESS`,并保存审核结果到`result`字段
+   - 如果仍在处理中,保持状态为`PROCESSING`
+   - 如果审核失败,更新状态为`FAILED`
+4. 对于网络异常等情况,增加重试次数,超过3次后标记为`FAILED`
+
+### 5.3 重试机制
+
+系统实现了重试机制来处理临时性错误:
+
+1. 每次处理失败时,`retry_count`字段加1
+2. 当重试次数超过3次时,将任务状态更新为`FAILED`
+3. 重试机制避免了因网络波动等临时问题导致的任务永久失败
+
+## 6. 示例数据
+
+```sql
+INSERT INTO `video_moderation_task` (`data_id`, `video_url`, `task_id`, `status`, `risk_level`, `result`) 
+VALUES 
+('video_1234567890', 'https://example.com/video.mp4', 'task_0987654321', 'SUCCESS', 'low', '{\"riskLevel\":\"low\",\"frameResult\":{}}');
+```
+
+## 7. 相关代码文件
+
+1. 实体类: `alien-entity/src/main/java/shop/alien/entity/VideoModerationTask.java`
+2. Mapper接口: `alien-entity/src/main/java/shop/alien/entity/VideoModerationTaskMapper.java`
+3. Mapper XML: `alien-entity/src/main/resources/mapper/VideoModerationTaskMapper.xml`
+4. 业务服务类: `alien-util/src/main/java/shop/alien/util/common/safe/video/VideoModerationService.java`
+5. XXL-JOB任务类: `alien-job/src/main/java/shop/alien/job/jobhandler/VideoModerationJobHandler.java`
+
+## 8. 注意事项
+
+1. `result`字段存储的是JSON格式的审核结果,可根据需要进行解析
+2. `video_url`字段最大长度为512字符,应确保视频URL不超过此长度
+3. 定时任务会定期清理状态为`SUCCESS`或`FAILED`的旧任务,避免数据量过大
+4. 重试次数限制为3次,可根据实际需求调整

+ 265 - 0
VIDEO_MODERATION_USER_GUIDE.md

@@ -0,0 +1,265 @@
+# 视频审核系统使用文档
+
+## 1. 概述
+
+视频审核系统是基于阿里云内容安全服务构建的一套完整的视频内容审核解决方案。该系统支持视频内容的自动审核,包括暴力、色情、政治敏感等内容的检测,并提供了完整的任务管理、结果存储和异步处理机制。
+
+## 2. 系统架构
+
+视频审核系统采用微服务架构,主要包括以下组件:
+
+1. **视频审核工具类** - 封装阿里云视频审核API调用
+2. **视频审核服务类** - 处理业务逻辑,包括任务提交、结果查询等
+3. **数据库实体类** - 定义视频审核任务的数据结构
+4. **数据库Mapper接口** - 提供数据库操作方法
+5. **XXL-JOB任务处理器** - 异步拉取审核结果
+6. **控制器示例** - 提供HTTP接口示例
+
+## 3. 功能说明
+
+### 3.1 视频审核任务提交
+
+用户可以通过调用[VideoModerationService.submitVideoModerationTask](file:///D:/database/alien_cloud/alien-util/src/main/java/shop/alien/util/common/safe/video/VideoModerationService.java#L47-L76)方法提交视频审核任务。
+
+#### 3.1.1 功能描述
+
+该功能将视频URL提交给阿里云内容安全服务进行审核,并将任务信息存储到数据库中。
+
+#### 3.1.2 使用方法
+
+```java
+@Autowired
+private VideoModerationService videoModerationService;
+
+// 提交视频审核任务
+String taskId = videoModerationService.submitVideoModerationTask("https://example.com/video.mp4");
+```
+
+#### 3.1.3 处理流程
+
+1. 生成唯一的`dataId`标识
+2. 调用阿里云接口提交视频审核任务
+3. 获取阿里云返回的`taskId`
+4. 将任务信息保存到数据库,状态设置为`SUBMITTED`
+
+### 3.2 视频审核结果查询
+
+用户可以通过调用[VideoModerationService.queryVideoModerationResult](file:///D:/database/alien_cloud/alien-util/src/main/java/shop/alien/util/common/safe/video/VideoModerationService.java#L84-L118)方法查询视频审核结果。
+
+#### 3.2.1 功能描述
+
+该功能直接从阿里云获取指定任务的审核结果,并更新数据库中的任务状态和结果。
+
+#### 3.2.2 使用方法
+
+```java
+@Autowired
+private VideoModerationService videoModerationService;
+
+// 查询视频审核结果
+VideoModerationTask task = videoModerationService.queryVideoModerationResult("your_task_id");
+```
+
+#### 3.2.3 处理流程
+
+1. 从数据库查询任务信息
+2. 调用阿里云接口获取审核结果
+3. 更新数据库中的任务状态为`SUCCESS`,并保存审核结果
+4. 返回完整的任务信息
+
+### 3.3 异步审核结果拉取
+
+系统通过XXL-JOB定时任务自动拉取审核结果,无需用户手动查询。
+
+#### 3.3.1 功能描述
+
+定时任务会定期扫描数据库中状态为`SUBMITTED`或`PROCESSING`的任务,并拉取其审核结果。
+
+#### 3.3.2 配置方法
+
+在XXL-JOB管理界面中添加新的任务,配置如下:
+
+- 任务名称:`videoModerationResultJobHandler`
+- 任务描述:视频审核结果拉取任务
+- 调度时间:建议每30秒执行一次
+- 任务参数:无需填写
+- 负责人:根据实际情况填写
+- 报警邮件:根据实际情况填写
+
+#### 3.3.3 处理流程
+
+1. 查询数据库中状态为`SUBMITTED`或`PROCESSING`的任务(最多100条)
+2. 遍历每个任务,调用阿里云接口获取审核结果
+3. 根据结果更新数据库:
+   - 审核完成:更新状态为`SUCCESS`,保存结果
+   - 审核中:更新状态为`PROCESSING`
+   - 审核失败:更新状态为`FAILED`
+4. 对于网络异常等临时错误,增加重试次数,超过3次后标记为`FAILED`
+
+### 3.4 重试机制
+
+系统实现了自动重试机制,以处理网络波动等临时性问题。
+
+#### 3.4.1 功能描述
+
+当异步拉取审核结果失败时,系统会自动重试,最多重试3次。
+
+#### 3.4.2 处理流程
+
+1. 拉取审核结果失败时,增加任务的重试次数
+2. 如果重试次数未超过3次,继续保留任务等待下次拉取
+3. 如果重试次数超过3次,将任务状态更新为`FAILED`
+
+## 4. 数据库设计
+
+### 4.1 表结构
+
+视频审核任务信息存储在`video_moderation_task`表中,包含以下字段:
+
+- `id`: 主键ID
+- `data_id`: 数据ID
+- `video_url`: 视频URL
+- `task_id`: 阿里云任务ID
+- [status](file://D:\database\alien_cloud\alien-entity\src\main\java\shop\alien\entity\result\R.java#L202-L204): 任务状态
+- `risk_level`: 风险级别
+- [result](file://D:\database\alien_cloud\alien-entity\src\main\java\shop\alien\entity\VideoModerationTask.java#L53-L53): 审核结果
+- `create_time`: 创建时间
+- `update_time`: 更新时间
+- `retry_count`: 重试次数
+
+### 4.2 状态说明
+
+任务状态包括:
+
+- `SUBMITTED`: 任务已提交
+- `PROCESSING`: 任务处理中
+- `SUCCESS`: 任务处理成功
+- `FAILED`: 任务处理失败
+
+## 5. API接口
+
+系统提供了示例控制器[VideoModerationController](file:///D:/database/alien_cloud/alien-util/src/main/java/shop/alien/util/common/safe/video/VideoModerationController.java#L14-L52),包含以下HTTP接口:
+
+### 5.1 提交视频审核任务
+
+```
+POST /video/moderation/submit?videoUrl={videoUrl}
+```
+
+#### 请求参数
+
+| 参数名 | 类型 | 必需 | 说明 |
+|--------|------|------|------|
+| videoUrl | string | 是 | 视频URL |
+
+#### 响应示例
+
+```json
+{
+  "code": 200,
+  "message": "任务提交成功,任务ID: task_xxxxxx",
+  "data": null
+}
+```
+
+### 5.2 查询视频审核结果
+
+```
+GET /video/moderation/result?taskId={taskId}
+```
+
+#### 请求参数
+
+| 参数名 | 类型 | 必需 | 说明 |
+|--------|------|------|------|
+| taskId | string | 是 | 任务ID |
+
+#### 响应示例
+
+```json
+{
+  "code": 200,
+  "message": "操作成功",
+  "data": {
+    "id": 1,
+    "dataId": "video_xxxxxx",
+    "videoUrl": "https://example.com/video.mp4",
+    "taskId": "task_xxxxxx",
+    "status": "SUCCESS",
+    "riskLevel": "low",
+    "result": "{\"riskLevel\":\"low\",\"frameResult\":{}}",
+    "createTime": "2023-01-01 12:00:00",
+    "updateTime": "2023-01-01 12:05:00",
+    "retryCount": 0
+  }
+}
+```
+
+## 6. 配置说明
+
+### 6.1 阿里云配置
+
+在`application.yml`或Nacos配置中心中添加以下配置:
+
+```yaml
+ali:
+  yundun:
+    accessKeyID: your_access_key_id
+    secret: your_access_key_secret
+    imgEndpoint: green-cip.cn-shanghai.aliyuncs.com
+    regionId: cn-shanghai
+```
+
+### 6.2 数据库配置
+
+确保数据库连接配置正确,并且数据库中已创建`video_moderation_task`表。
+
+### 6.3 XXL-JOB配置
+
+确保XXL-JOB配置正确,并且任务处理器已注册到调度中心。
+
+## 7. 错误处理
+
+### 7.1 提交任务失败
+
+当提交任务失败时,系统会抛出运行时异常,需要在调用方进行捕获处理。
+
+### 7.2 查询结果失败
+
+当查询结果失败时,系统会抛出运行时异常,需要在调用方进行捕获处理。
+
+### 7.3 网络异常
+
+对于网络异常等临时性错误,系统会自动重试,最多重试3次。
+
+## 8. 性能优化建议
+
+1. **批量处理**: XXL-JOB任务每次最多处理100条任务,可根据实际需求调整
+2. **索引优化**: 数据库表已创建必要的索引,可根据查询模式进一步优化
+3. **任务清理**: 建议定期清理已完成的任务,避免数据量过大影响性能
+4. **重试机制**: 合理设置重试次数,避免无效重试占用系统资源
+
+## 9. 扩展性说明
+
+### 9.1 增加新的审核类型
+
+如需支持其他类型的审核(如直播流审核),可以扩展[VideoModerationUtil](file:///D:/database/alien_cloud/alien-util/src/main/java/shop/alien/util/common/safe/video/VideoModerationUtil.java#L16-L101)工具类,添加相应的方法。
+
+### 9.2 修改审核结果处理逻辑
+
+如需修改审核结果的处理逻辑,可以修改[VideoModerationService.processTask](file:///D:/database/alien_cloud/alien-util/src/main/java/shop/alien/util/common/safe/video/VideoModerationService.java#L126-L185)方法。
+
+### 9.3 调整异步处理策略
+
+如需调整异步处理策略,可以修改[VideoModerationJobHandler](file:///D:/database/alien_cloud/alien-job/src/main/java/shop/alien/job/jobhandler/VideoModerationJobHandler.java#L16-L59)类中的处理逻辑。
+
+## 10. 监控和日志
+
+系统集成了完整的日志记录,可以通过日志监控任务执行情况:
+
+1. 任务提交日志
+2. 任务处理日志
+3. 异常日志
+4. 重试日志
+
+建议通过日志分析工具对这些日志进行集中管理和分析。

+ 1 - 0
alien-api/src/main/resources/bootstrap-prod.yml

@@ -9,6 +9,7 @@ spring:
         server-addr: localhost:8848
         username: nacos
         password: ngfriend198092
+        namespace: 3cbb802a-b56e-47f7-b658-b5012ecafb1f
 
       #配置中心
       config:

+ 1 - 0
alien-api/src/main/resources/bootstrap-test.yml

@@ -9,6 +9,7 @@ spring:
         server-addr: 192.168.2.252:8848
         username: nacos
         password: ngfriend198092
+        namespace: 0e1e2d77-56e8-422c-8317-6f71d7285e59
 
       #配置中心
       config:

+ 1 - 1
alien-api/src/main/resources/logback-spring.xml

@@ -12,7 +12,7 @@
     <!-- 定义全局参数常量 -->
     <property name="log.level" value="debug"/>
     <property name="log.maxHistory" value="30"/><!-- 30表示30个 -->
-    <property name="logging.path" value="/javaLog/apiLog"/>
+    <springProperty scope="context" name="logging.path" source="logging.path"/>
     <!--输出文件前缀-->
     <property name="FILENAME" value="xiaokuihua_api"/>
 

+ 24 - 0
alien-config/src/main/java/shop/alien/config/properties/VideoModerationProperties.java

@@ -0,0 +1,24 @@
+package shop.alien.config.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * 视频审核配置属性
+ */
+@Data
+@Component
+@ConfigurationProperties(prefix = "video.moderation")
+public class VideoModerationProperties {
+    
+    /**
+     * 视频审核开关
+     */
+    private boolean enabled = false;
+    
+    /**
+     * 审核失败时是否阻止商品发布
+     */
+    private boolean blockOnFailure = true;
+}

+ 70 - 0
alien-entity/src/main/java/shop/alien/entity/SecondVideoTask.java

@@ -0,0 +1,70 @@
+package shop.alien.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 视频审核任务实体类
+ */
+@Data
+@TableName("second_video_task")
+public class SecondVideoTask implements Serializable {
+    
+    private static final long serialVersionUID = 1L;
+    
+    /**
+     * 主键ID
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+    
+    /**
+     * 数据ID
+     */
+    private String dataId;
+    
+    /**
+     * 视频URL
+     */
+    private String videoUrl;
+    
+    /**
+     * 任务ID
+     */
+    private String taskId;
+    
+    /**
+     * 任务状态 (SUBMITTED-已提交, PROCESSING-处理中, SUCCESS-成功, FAILED-失败)
+     */
+    private String status;
+    
+    /**
+     * 风险级别 (none-无风险, low-低风险, medium-中风险, high-高风险)
+     */
+    private String riskLevel;
+    
+    /**
+     * 审核结果(JSON格式)
+     */
+    private String result;
+    
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+    
+    /**
+     * 更新时间
+     */
+    private Date updateTime;
+    
+    /**
+     * 重试次数
+     */
+    private Integer retryCount = 0;
+}

+ 10 - 0
alien-entity/src/main/java/shop/alien/entity/result/BusinessException.java

@@ -0,0 +1,10 @@
+package shop.alien.entity.result;
+
+public class BusinessException extends RuntimeException {
+    public BusinessException(String message) {
+        super(message);
+    }
+    public BusinessException(Exception e) {
+        super(e);
+    }
+}

+ 9 - 0
alien-entity/src/main/java/shop/alien/entity/second/SecondGoods.java

@@ -44,6 +44,10 @@ public class SecondGoods implements Serializable {
     @ApiModelProperty(value = "商品封面图片")
     private String homeImage;
 
+    @TableField("video_first_frame")
+    @ApiModelProperty(value = "视频第一帧图片")
+    private String videoFirstFrame;
+
     @TableField("description")
     @ApiModelProperty(value = "商品描述")
     private String description;
@@ -95,6 +99,11 @@ public class SecondGoods implements Serializable {
     @ApiModelProperty(value = "交易ID")
     private Integer tradeId;
 
+    /**
+     * 视频审核任务ID
+     */
+    private String videoTaskId;
+
     @TableField("goods_status")
     @ApiModelProperty(value = "商品状态 0:草稿 1:审核中 2:审核失败 3:已上架 4:已下架 5:已售出")
     private Integer goodsStatus;

+ 121 - 0
alien-entity/src/main/java/shop/alien/entity/second/SecondGoodsRecord.java

@@ -0,0 +1,121 @@
+package shop.alien.entity.second;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+@JsonInclude
+@TableName("second_goods_record")
+public class SecondGoodsRecord implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    @ApiModelProperty(value = "主键ID")
+    private Integer id;
+
+    @TableField("goods_id")
+    @ApiModelProperty(value = "商品ID")
+    private Integer goodsId;
+
+    @TableField("title")
+    @ApiModelProperty(value = "商品标题")
+    private String title;
+
+    @TableField("description")
+    @ApiModelProperty(value = "商品描述")
+    private String description;
+
+    @TableField("price")
+    @ApiModelProperty(value = "商品价格(元,保留小数后两位)")
+    private BigDecimal price;
+
+    @TableField("position")
+    @ApiModelProperty(value = "商品位置")
+    private String position;
+
+    @TableField("like_count")
+    @ApiModelProperty(value = "点赞数量")
+    private Integer likeCount;
+
+    @TableField("collect_count")
+    @ApiModelProperty(value = "收藏数量")
+    private Integer collectCount;
+
+    @TableField("category_one_id")
+    @ApiModelProperty(value = "一级类别ID")
+    private Integer categoryOneId;
+
+    @TableField("category_two_id")
+    @ApiModelProperty(value = "二级类别ID")
+    private Integer categoryTwoId;
+
+    @TableField("label")
+    @ApiModelProperty(value = "标签")
+    private String label;
+
+    @TableField("topic")
+    @ApiModelProperty(value = "话题(以逗号分隔)")
+    private String topic;
+
+    @TableField("trade_id")
+    @ApiModelProperty(value = "交易ID")
+    private Integer tradeId;
+
+    @TableField("release_time")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    @ApiModelProperty(value = "发布时间")
+    private Date releaseTime;
+
+    @TableField("goods_status")
+    @ApiModelProperty(value = "商品状态 0:草稿 1:审核中 2:审核失败 3:已上架 4:已下架 5:已售出")
+    private Integer goodsStatus;
+
+    @TableField("failed_reason")
+    @ApiModelProperty(value = "审核失败原因")
+    private String failedReason;
+
+    @TableField("home_image")
+    @ApiModelProperty(value = "首页图")
+    private String homeImage;
+
+    @TableField("video_task_id")
+    @ApiModelProperty(value = "视频审核任务id")
+    private String videoTaskId;
+
+    @TableField("video_first_frame")
+    @ApiModelProperty(value = "视频第一帧图片")
+    private String videoFirstFrame;
+
+    @TableField("delete_flag")
+    @ApiModelProperty(value = "删除标记 0:未删除 1:已删除")
+    private Integer deleteFlag;
+
+    @TableField("created_time")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    @ApiModelProperty(value = "创建时间")
+    private Date createdTime;
+
+    @TableField("created_user_id")
+    @ApiModelProperty(value = "创建人ID")
+    private Integer createdUserId;
+
+    @TableField("updated_time")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    @ApiModelProperty(value = "修改时间")
+    private Date updatedTime;
+
+    @TableField("updated_user_id")
+    @ApiModelProperty(value = "修改人ID")
+    private Integer updatedUserId;
+
+    @TableField("address_text")
+    @ApiModelProperty(value = "地址文本")
+    private String addressText;
+}

+ 4 - 0
alien-entity/src/main/java/shop/alien/entity/second/SecondTradeRecord.java

@@ -32,6 +32,10 @@ public class SecondTradeRecord extends Model<SecondTradeRecord> {
     @TableId(value = "id", type = IdType.AUTO)
     private Integer id;
 
+    @ApiModelProperty(value = "交易编号")
+    @TableField("trade_no")
+    private String tradeNo;
+
     @ApiModelProperty(value = "商品id")
     @TableField("goods_id")
     private Integer goodsId;

+ 3 - 0
alien-entity/src/main/java/shop/alien/entity/second/vo/SecondGoodsRecommendVo.java

@@ -55,6 +55,9 @@ public class SecondGoodsRecommendVo extends SecondGoods {
     @ApiModelProperty(value = "发布时间")
     private Date releaseTime;
 
+    @ApiModelProperty(value = "视频第一帧")
+    private String videoFirstFrame;
+
     @ApiModelProperty(value = "话题列表")
     @JsonProperty("topicList")
     private List<String> topicList() {

+ 8 - 0
alien-entity/src/main/java/shop/alien/entity/store/LifeDiscountCoupon.java

@@ -138,6 +138,14 @@ public class LifeDiscountCoupon extends Model<LifeDiscountCoupon> {
     @TableField("claim_rule_customize_value")
     private Integer claimRuleCustomizeValue;
 
+    @ApiModelProperty(value = "优惠券状态:0:草稿,1:正式")
+    @TableField("coupon_status")
+    private Integer couponStatus;
+
+    @ApiModelProperty(value = "有效期")
+    @TableField("valid_date")
+    private LocalDate validDate;
+
     @Override
     protected Serializable pkVal() {
         return this.id;

+ 15 - 0
alien-entity/src/main/java/shop/alien/entity/store/StoreCashOutRecord.java

@@ -91,6 +91,21 @@ public class StoreCashOutRecord extends Model<StoreCashOutRecord> {
     @TableField(value = "updated_user_id", fill = FieldFill.INSERT_UPDATE)
     private Integer updatedUserId;
 
+    @ApiModelProperty(value = "审批时间")
+    @TableField(value = "approve_time", fill = FieldFill.INSERT)
+    private Date approveTime;
+
+    @ApiModelProperty(value = "支付时间")
+    @TableField(value = "pay_date", fill = FieldFill.INSERT)
+    private Date payDate;
+
+    @ApiModelProperty(value = "查看失败原因")
+    @TableField(value = "fail_reason")
+    private String failReason;
+
+    @ApiModelProperty(value = "申请storeUserID")
+    @TableField(value = "store_user_id")
+    private Integer storeUserId;
     @ApiModelProperty(value = "审批备注")
     @TableField(value = "comments")
     private String comments;

+ 4 - 0
alien-entity/src/main/java/shop/alien/entity/store/StoreInfo.java

@@ -189,6 +189,10 @@ public class StoreInfo {
     @TableField("img_mode")
     private Integer ImgMode;
 
+    @ApiModelProperty(value = "收藏数")
+    @TableField("collect_num")
+    private Integer collectNum;
+
     @TableField(exist = false)
     private String dist;
 }

+ 3 - 0
alien-entity/src/main/java/shop/alien/entity/store/dto/LifeDiscountCouponDto.java

@@ -110,4 +110,7 @@ public class LifeDiscountCouponDto {
 
     @ApiModelProperty(value = "结束领取时间")
     private LocalDate endGetDate;
+
+    @ApiModelProperty(value = "优惠券状态:0:草稿,1:正式")
+    private Integer couponStatus;
 }

+ 13 - 7
alien-entity/src/main/java/shop/alien/entity/store/excelVo/util/ExcelGenerator.java

@@ -4,17 +4,23 @@ import org.apache.poi.ss.usermodel.*;
 import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 
-import java.io.ByteArrayOutputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
+import java.io.*;
 import java.lang.reflect.Field;
 import java.net.URL;
 import java.util.List;
 
 public class ExcelGenerator {
 
-    public static <T> void generateExcel(String filePath, List<T> dataList, Class<T> clazz) throws IOException {
+    public static <T> String generateExcel(String filePath, List<T> dataList, Class<T> clazz) throws IOException {
+        String osName = System.getProperty("os.name").toLowerCase();
+        if (osName.contains("win")) {
+            filePath = "c:/" + filePath;
+            String substring = filePath.substring(0, filePath.lastIndexOf("/"));
+            File dir = new File(substring);
+            if (!dir.exists()) {
+                dir.mkdirs();
+            }
+        }
         // 创建一个新的工作簿
         XSSFWorkbook workbook = new XSSFWorkbook();
         // 创建一个工作表
@@ -62,8 +68,7 @@ public class ExcelGenerator {
                     try {
                         String imageUrl = (String) field.get(obj);
                         if (imageUrl != null && !imageUrl.isEmpty()) {
-                            try (InputStream is = new URL(imageUrl).openStream();
-                                 ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
+                            try (InputStream is = new URL(imageUrl).openStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
                                 byte[] buffer = new byte[1024];
                                 int length;
                                 while ((length = is.read(buffer)) != -1) {
@@ -122,5 +127,6 @@ public class ExcelGenerator {
 
         // 关闭工作簿
         workbook.close();
+        return filePath;
     }
 }    

+ 1 - 1
alien-entity/src/main/java/shop/alien/entity/store/vo/LifeCouponVo.java

@@ -20,7 +20,7 @@ import java.util.List;
 @EqualsAndHashCode(callSuper = false)
 @JsonInclude
 @NoArgsConstructor
-@ApiModel(value = "LifeCouponVo对象", description = "套餐")
+@ApiModel(value = "LifeCouponVo对象", description = "代金券")
 public class LifeCouponVo extends LifeCoupon {
 
     @TableId(value = "id", type = IdType.AUTO)

+ 10 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/LifeDiscountCouponVo.java

@@ -144,4 +144,14 @@ public class LifeDiscountCouponVo {
 
     @ApiModelProperty(value = "结束领取时间")
     private LocalDate endGetDate;
+
+    @ApiModelProperty(value = "优惠券状态:0:草稿,1:正式")
+    private Integer couponStatus;
+
+    @ApiModelProperty(value = "有效期")
+    private LocalDate validDate;
+
+    @ApiModelProperty(value = "到期日期")
+    private LocalDate expirationTime;
+
 }

+ 53 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/LifeGroupBuyMainVo.java

@@ -0,0 +1,53 @@
+package shop.alien.entity.store.vo;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import shop.alien.entity.store.EssentialHolidayComparison;
+import shop.alien.entity.store.LifeGroupBuyMain;
+import shop.alien.entity.store.LifeGroupBuyThali;
+import shop.alien.entity.store.StoreImg;
+
+import java.util.List;
+import java.util.Map;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@JsonInclude
+@NoArgsConstructor
+@ApiModel(value = "LifeGroupBuyMainVo对象", description = "套餐")
+public class LifeGroupBuyMainVo extends LifeGroupBuyMain {
+
+    @ApiModelProperty(value = "是否过期 0:未过期 1:已过期")
+    private String expiredState;
+
+    @ApiModelProperty(value = "商家名称")
+    private String storeName;
+
+    @ApiModelProperty(value = "商家手机号")
+    private String phone;
+
+    @ApiModelProperty(value = "套餐名称映射导出类字段")
+    private String couponName;
+
+    @ApiModelProperty(value = "套餐状态映射导出类字段")
+    private String couponState;
+
+    @ApiModelProperty(value = "套餐时间映射导出类字段")
+    private String couponTime;
+
+    @ApiModelProperty(value = "剩余天数映射导出类字段")
+    private String daysToExpire;
+
+    @ApiModelProperty(value = "图片list")
+    private List<StoreImg> storeImgList;
+
+    @ApiModelProperty(value = "不可用日期list")
+    private List<EssentialHolidayComparison> essentialHolidayComparisonList;
+
+    @ApiModelProperty(value = "套餐子表list")
+    private List<LifeGroupBuyThali> lifeGroupBuyThaliList;
+}

+ 10 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/ManagementInfoVo.java

@@ -1,6 +1,8 @@
 package shop.alien.entity.store.vo;
 
 
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
@@ -119,4 +121,12 @@ public class ManagementInfoVo {
     private String buyTimeStr;
     @ApiModelProperty(value = "数据可视化-订单金额")
     private String finalPrice;
+    @ApiModelProperty(value = "审批时间")
+    private Date approveTime;
+    @ApiModelProperty(value = "支付时间")
+    private Date payDate;
+    @ApiModelProperty(value = "查看失败原因")
+    private String failReason;
+    @ApiModelProperty(value = "提现状态, 0:进行中, 1:成功, 2:失败,3待审核,4已拒绝,5审核通过")
+    private Integer paymentStatus;
 }

+ 26 - 4
alien-entity/src/main/java/shop/alien/entity/store/vo/ScreeningOfEightMajorCategoriesVO.java

@@ -9,10 +9,10 @@ public class ScreeningOfEightMajorCategoriesVO {
     @ApiModelProperty(value = "筛选ID,多个ID用逗号分隔")
     private String screeningId;
 
-    @ApiModelProperty(value = "经度")
+    @ApiModelProperty(value = "经度", required = true)
     private Double lon;
 
-    @ApiModelProperty(value = "纬度")
+    @ApiModelProperty(value = "纬度", required = true)
     private Double lat;
 
     @ApiModelProperty(value = "距离范围")
@@ -27,15 +27,37 @@ public class ScreeningOfEightMajorCategoriesVO {
     @ApiModelProperty(value = "营业时间自定义结束")
     private String endTime;
 
+    @ApiModelProperty(value = "门店名称")
+    private String storeName;
+
     @ApiModelProperty(value = "价格开始")
     private Double priceStr;
 
     @ApiModelProperty(value = "价格结束")
     private Double priceEnd;
 
-    @ApiModelProperty(value = "页码")
+    @ApiModelProperty(value = "页码", required = true)
     private Integer pageNum;
 
-    @ApiModelProperty(value = "页容")
+    @ApiModelProperty(value = "页容", required = true)
     private Integer pageSize;
+
+    @ApiModelProperty(value = "人气优先0否1是")
+    private Integer rqyx;
+
+    @ApiModelProperty(value = "好评优先0否1是")
+    private Integer hpyx;
+
+    @ApiModelProperty(value = "环境优先0否1是")
+    private Integer hjyx;
+
+    @ApiModelProperty(value = "服务优先0否1是")
+    private Integer fwyx;
+
+    @ApiModelProperty(value = "口味优先0否1是")
+    private Integer kwyx;
+
+    @ApiModelProperty(value = "美食筛选")
+    private String foodType;
+
 }

+ 4 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/StoreInfoVo.java

@@ -12,6 +12,7 @@ import shop.alien.entity.store.StoreInfo;
 import shop.alien.entity.store.StoreStaffConfig;
 
 import java.util.List;
+import java.util.Map;
 
 @EqualsAndHashCode(callSuper = true)
 @Data
@@ -173,5 +174,8 @@ public class StoreInfoVo extends StoreInfo {
     @ApiModelProperty(value = "验证码")
     private String verificationCode;
 
+    private List<Map<String, Object>> quanMapList;
+
+    private String storeClockInCount;
 
 }

+ 23 - 5
alien-entity/src/main/java/shop/alien/mapper/LifeGroupBuyThaliMapper.java

@@ -1,16 +1,34 @@
 package shop.alien.mapper;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
 import shop.alien.entity.store.LifeGroupBuyThali;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 
+
+import java.util.List;
+
 /**
-* @author youch
-* @description 针对表【life_group_buy_thali(团购套餐详情子表)】的数据库操作Mapper
-* @createDate 2025-07-28 14:31:30
-* @Entity shop.alien.entity.store.LifeGroupBuyThali
-*/
+ * @author youch
+ * @description 针对表【life_group_buy_thali(团购套餐详情子表)】的数据库操作Mapper
+ * @createDate 2025-07-28 14:31:30
+ * @Entity shop.alien.entity.store.LifeGroupBuyThali
+ */
 public interface LifeGroupBuyThaliMapper extends BaseMapper<LifeGroupBuyThali> {
 
+    @Select("SELECT\n" +
+            "\tlife.id,life.detail_id,life.group_name,life.parent_id,life.detail_sort,life.price,life.qty,life.detail_sort,life.created_time,store.dish_name,store.dish_price,\n" +
+            "\tstore.dishes_unit,\n" +
+            "\tstore.img_id as dishImg \n" +
+            "FROM\n" +
+            "\tlife_group_buy_thali life\n" +
+            "\tLEFT JOIN store_menu store ON life.detail_id = store.id\n" +
+            "${ew.customSqlSegment}")
+    List<LifeGroupBuyThali> getLifeGroupBuyThaliList(@Param(Constants.WRAPPER) LambdaQueryWrapper<LifeGroupBuyThali> wrapper);
+
 }
 
 

+ 29 - 24
alien-entity/src/main/java/shop/alien/mapper/LifeMessageMapper.java

@@ -53,30 +53,35 @@ public interface LifeMessageMapper extends BaseMapper<LifeMessage> {
             "${ew.customSqlSegment}")
     List<LifeMessageVo> getLifeMessagePageByPhoneId(@Param("phoneId") String phoneId, @Param(Constants.WRAPPER) QueryWrapper<LifeFansVo> dynamicsWrapper);
 
-    @Update("update life_message set delete_phone_id = (if(delete_phone_id is null, #{receiverId}, concat(delete_phone_id, ',', #{receiverId}))) ,delete_flag = '1'" +
-            "where (receiver_id = #{senderId} and sender_id = #{receiverId}) or (sender_id = #{senderId} and receiver_id = #{receiverId}) ")
+    @Update("update life_message set delete_phone_id = (if(delete_phone_id is null, #{receiverId}, concat(delete_phone_id, ',', #{receiverId}))) " +
+            "where ((receiver_id = #{senderId} and sender_id = #{receiverId}) or (sender_id = #{senderId} and receiver_id = #{receiverId})) " +
+            "   and (instr(delete_phone_id, #{receiverId}) is null or instr(delete_phone_id, #{receiverId}) = 0)")
     int deleteMessageByPhoneId(@Param("senderId") String senderId, @Param("receiverId") String receiverId);
 
-    //    @Select("select lm.id,lm.updated_time,lm.created_user_id,lm.receiver_name,lm.is_read,lm.type,lm.content," +
-//            "lm.current_time,lm.delete_flag,lm.sender_id,lm.sender_name,lm.receiver_id,lm.delete_phone_id," +
-//            "lm.created_time,lm.updated_user_id,lu.user_image,img.img_url storeImg" +
-//            "    from life_message lm" +
-//            "    left join life_user lu " +
-//            "    on SUBSTRING(lm.sender_id, INSTR(lm.sender_id, '_') + 1) = lu.user_phone" +
-//            "        left join store_user su on SUBSTRING(lm.sender_id, INSTR(lm.sender_id, '_') + 1) = su.phone " +
-//            "        left join store_info s on su.store_id = s.id" +
-//            "        left join store_img img on img.store_id = s.id and img.img_type = '10' and img.delete_flag = 0 "+
-//            "    where lm.delete_flag = 0 and su.delete_flag = 0 and s.delete_flag = 0" +
-//            "    and ( ((lm.receiver_id = #{senderId} and lm.sender_id = #{receiverId})" +
-//            "    or (lm.sender_id = #{senderId} and lm.receiver_id = #{receiverId})) )" +
-//            "    order by lm.created_time asc")
-    @Select("select lm.id,lm.updated_time,lm.created_user_id,lm.receiver_name,lm.is_read,lm.type,lm.content,lm.current_time,lm.delete_flag,lm.sender_id,lm.sender_name,lm.receiver_id,lm.delete_phone_id,lm.created_time,lm.updated_user_id,lu.user_image" +
-            "    from life_message lm" +
-            "    left join life_user lu " +
-            "    on SUBSTRING(lm.sender_id, INSTR(lm.sender_id, '_') + 1) = lu.user_phone" +
-            "    where lm.delete_flag = 0" +
-            "    and ( ((lm.receiver_id = #{senderId} and lm.sender_id = #{receiverId})" +
-            "    or (lm.sender_id = #{senderId} and lm.receiver_id = #{receiverId})) )" +
-            "    order by lm.created_time asc")
-    List<LifeMessageVo> selectUserImageLists(@Param("receiverId") String receiverId, @Param("senderId") String senderId);
+    @Select("select lm.id,lm.updated_time,lm.created_user_id,lm.receiver_name,lm.is_read,lm.type,lm.content,lm.current_time,lm.delete_flag," +
+            "       lm.sender_id,lm.sender_name,lm.receiver_id,lm.delete_phone_id,lm.created_time,lm.updated_user_id,lu.user_image " +
+            "from life_message lm " +
+            "left join life_user lu on SUBSTRING(lm.sender_id, INSTR(lm.sender_id, '_') + 1) = lu.user_phone " +
+            "where lm.delete_flag = 0 " +
+            "   and (((lm.receiver_id = #{senderId} and lm.sender_id = #{receiverId}) or (lm.sender_id = #{senderId} and lm.receiver_id = #{receiverId}))) " +
+            "   and (instr(delete_phone_id, #{receiverId}) is null or instr(delete_phone_id, #{receiverId}) = 0) " +
+            "order by lm.created_time asc ")
+    List<LifeMessageVo> getMessageListByReceiverId(@Param("receiverId") String receiverId, @Param("senderId") String senderId);
+
+    @Select("select user.id, user.user_name name, user.user_image image, concat('user_', user.user_phone) phoneId, user.jianjie blurb " +
+            "from life_user user " +
+            "where user_phone in ( " +
+            "    select substring_index(sender_id, '_', -1) phone from life_message " +
+            "    where sender_id in " +
+            "          (select receiver_id from life_message " +
+            "            where sender_id = #{senderId} and receiver_id != #{senderId} and delete_flag = 0 " +
+            "            and left(receiver_id, 5) = 'user_' and receiver_id not in ( " +
+            "                    select blocked_phone_id from life_blacklist " +
+            "                    where blocker_phone_id = #{senderId} and delete_flag = 0 " +
+            "                ) " +
+            "            group by receiver_id) " +
+            "    and receiver_id = #{senderId} and delete_flag = 0 " +
+            "    group by sender_id) " +
+            "and delete_flag = 0 ")
+    List<LifeFansVo> getTalkedUserList(@Param("senderId") String senderId);
 }

+ 35 - 0
alien-entity/src/main/java/shop/alien/mapper/PlatformStoreLifeGroupBuyMainMapper.java

@@ -0,0 +1,35 @@
+package shop.alien.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+import shop.alien.entity.store.LifeGroupBuyMain;
+import shop.alien.entity.store.vo.LifeGroupBuyMainVo;
+
+import java.util.List;
+
+
+public interface PlatformStoreLifeGroupBuyMainMapper extends BaseMapper<LifeGroupBuyMain> {
+
+    @Select("SELECT\n" +
+            "\tlife.id,store.store_name,life.inventory_num,life.group_name,user.phone,life.created_time,life.start_time_value,life.end_time,life.status\n" +
+            "FROM\n" +
+            "\tlife_group_buy_main life\n" +
+            "\tJOIN store_info store ON store.id = life.store_id\n" +
+            "\tJOIN store_user user ON store.id = user.store_id\n"+
+            "${ew.customSqlSegment}")
+    IPage<LifeGroupBuyMainVo> getLifeGroupBuyMainList(IPage<LifeGroupBuyMainVo> iPage, @Param(Constants.WRAPPER) QueryWrapper<LifeGroupBuyMainVo> wrapper);
+
+    @Select("SELECT\n" +
+            "\tlife.id,store.store_name,life.inventory_num,life.group_name,user.phone,life.created_time,life.start_time_value,life.end_time,life.status\n" +
+            "FROM\n" +
+            "\tlife_group_buy_main life\n" +
+            "\tJOIN store_info store ON store.id = life.store_id\n" +
+            "\tJOIN store_user user ON store.id = user.store_id\n"+
+            "${ew.customSqlSegment}")
+    List<LifeGroupBuyMainVo> getLifeGroupBuyMainList(@Param(Constants.WRAPPER) QueryWrapper<LifeGroupBuyMainVo> wrapper);
+
+}

+ 4 - 0
alien-entity/src/main/java/shop/alien/mapper/StoreIncomeDetailsRecordMapper.java

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.toolkit.Constants;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
 import shop.alien.entity.store.StoreIncomeDetailsRecord;
 import shop.alien.entity.store.vo.StoreIncomeDetailsRecordVo;
 
@@ -28,4 +29,7 @@ public interface StoreIncomeDetailsRecordMapper extends BaseMapper<StoreIncomeDe
             "${ew.customSqlSegment}")
     List<StoreIncomeDetailsRecordVo> getIncomeList(@Param(Constants.WRAPPER) QueryWrapper<StoreIncomeDetailsRecordVo> wrapper);
 
+    @Update("UPDATE store_income_details_record SET cash_out_id = NULL WHERE delete_flag=0 AND store_id = #{storeId} AND cash_out_id = #{cashOutId}")
+    int updateByCashOutId(@Param("storeId") Integer storeId,
+                                 @Param("cashOutId") Integer cashOutId);
 }

+ 12 - 3
alien-entity/src/main/java/shop/alien/mapper/StoreInfoMapper.java

@@ -92,7 +92,16 @@ public interface StoreInfoMapper extends BaseMapper<StoreInfo> {
     @Select("select * from store_info ${ew.customSqlSegment}")
     List<StoreInfo> getList(@Param(Constants.WRAPPER) LambdaQueryWrapper<StoreInfo> queryWrapper);
 
-    @Select("select *," +
-            "            ROUND(ST_Distance_Sphere(ST_GeomFromText(CONCAT('POINT(', REPLACE(#{position}, ',', ' '), ')' )), ST_GeomFromText(CONCAT('POINT(', REPLACE(store_position, ',', ' '), ')' ))) / 1000, 2) AS dist from store_info ${ew.customSqlSegment}")
-    IPage<StoreInfo> getPageForDistance(@Param(Constants.WRAPPER) QueryWrapper<StoreInfo> queryWrapper, IPage<StoreInfo> page, @Param("position") String position);
+    @Select("with menu as (select store_id,GROUP_CONCAT(dish_name) dish_name from store_menu GROUP BY store_id) " +
+            "select a.*," +
+            "            ROUND(ST_Distance_Sphere(ST_GeomFromText(CONCAT('POINT(', REPLACE(#{position}, ',', ' '), ')' )), ST_GeomFromText(CONCAT('POINT(', REPLACE(a.store_position, ',', ' '), ')' ))) / 1000, 2) dist" +
+            ", b.name store_contact, b.phone store_phone, b.password, c.dish_name,  img.img_url entranceImage, d.img_url, dict.dict_detail storeTypeStr, dict2.dict_detail businessStatusStr " +
+            "from store_info a " +
+            "left join store_user b on a.id = b.store_id  AND b.delete_flag = 0 " +
+            "left join menu c on a.id = c.store_id " +
+            "left join store_img img on img.store_id = a.id and img.img_type = 1 and img.delete_flag = 0 " +
+            "left join store_dictionary dict on dict.type_name = 'storeType' and dict.dict_id = a.store_type and dict.delete_flag = 0 " +
+            "left join store_dictionary dict2 on dict2.type_name = 'businessStatus' and a.business_status = dict2.dict_id and dict2.delete_flag = 0 " +
+            "left join store_img d on d.store_id = a.id and d.img_type = 10 and d.delete_flag = 0 ${ew.customSqlSegment}")
+    IPage<StoreInfoVo> getPageForDistance(IPage<StoreInfoVo> page,  @Param("position") String position,@Param(Constants.WRAPPER) QueryWrapper<StoreInfoVo> queryWrapper);
 }

+ 7 - 0
alien-entity/src/main/java/shop/alien/mapper/second/SecondGoodsRecordMapper.java

@@ -0,0 +1,7 @@
+package shop.alien.mapper.second;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import shop.alien.entity.second.SecondGoodsRecord;
+
+public interface SecondGoodsRecordMapper extends BaseMapper<SecondGoodsRecord> {
+}

+ 1 - 1
alien-entity/src/main/java/shop/alien/mapper/second/SecondRecommendMapper.java

@@ -19,7 +19,7 @@ public interface SecondRecommendMapper extends BaseMapper<SecondGoodsRecommendVo
      */
     IPage<SecondGoodsRecommendVo> getSecondRecommendByPage(IPage<SecondGoodsRecommendVo> page, @Param("userId") Integer userId, @Param("position") String position, @Param("typeId") Integer typeId, @Param("phoneId") String phoneId);
 
-    IPage<SecondGoodsRecommendVo> querySecondConcernByPage(IPage<SecondGoodsRecommendVo> page, @Param("phoneId") String phoneId, @Param("position") String position);
+    IPage<SecondGoodsRecommendVo> querySecondConcernByPage(IPage<SecondGoodsRecommendVo> page, @Param("userId") Integer userId, @Param("phoneId") String phoneId, @Param("position") String position);
 
     IPage<SecondGoodsRecommendVo> querySecondNewGoodsByPage(IPage<SecondGoodsRecommendVo> page,@Param("userId") String userId, @Param("phoneId") String phoneId, @Param("position") String position);
 

+ 63 - 0
alien-entity/src/main/java/shop/alien/mapper/system/SecondVideoTaskMapper.java

@@ -0,0 +1,63 @@
+package shop.alien.mapper.system;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
+import org.springframework.stereotype.Repository;
+import shop.alien.entity.SecondVideoTask;
+
+import java.util.List;
+
+/**
+ * 视频审核任务Mapper接口
+ */
+@Mapper
+@Repository
+public interface SecondVideoTaskMapper extends BaseMapper<SecondVideoTask> {
+
+    /**
+     * 查询待处理的审核任务
+     * @return 审核任务列表
+     */
+    @Select("SELECT * FROM second_video_task WHERE status IN ('SUBMITTED', 'PROCESSING') ORDER BY create_time ASC LIMIT 100")
+    List<SecondVideoTask> selectPendingTasks();
+
+    /**
+     * 根据任务ID查询任务详情
+     * @param taskId 任务ID
+     * @return 任务详情
+     */
+    @Select("SELECT * FROM second_video_task WHERE task_id = #{taskId}")
+    SecondVideoTask selectByTaskId(@Param("taskId") String taskId);
+
+    /**
+     * 更新任务状态
+     * @param taskId 任务ID
+     * @param status 状态
+     * @return 更新记录数
+     */
+    @Update("UPDATE second_video_task SET status = #{status}, update_time = NOW() WHERE task_id = #{taskId}")
+    int updateTaskStatus(@Param("taskId") String taskId, @Param("status") String status);
+
+    /**
+     * 更新任务结果
+     * @param taskId 任务ID
+     * @param status 状态
+     * @param riskLevel 风险级别
+     * @param result 审核结果
+     * @return 更新记录数
+     */
+    @Update("UPDATE second_video_task SET status = #{status}, risk_level = #{riskLevel}, result = #{result}, update_time = NOW() WHERE task_id = #{taskId}")
+    int updateTaskResult(@Param("taskId") String taskId, @Param("status") String status,
+                         @Param("riskLevel") String riskLevel, @Param("result") String result);
+
+    /**
+     * 增加重试次数
+     * @param id 任务ID
+     * @return 更新记录数
+     */
+    @Update("UPDATE second_video_task SET retry_count = retry_count + 1, update_time = NOW() WHERE id = #{id}")
+    int incrementRetryCount(@Param("id") Long id);
+}

+ 5 - 1
alien-entity/src/main/resources/mapper/ManagementInfoMapper.xml

@@ -193,7 +193,11 @@
                 END AS cash_out_type_name,
             cash.money,
             cash.created_time,
-            cash.payment_date
+            cash.payment_date,
+            cash.approve_time,
+            cash.pay_date,
+            cash.fail_reason,
+            cash.payment_status
         FROM
             store_cash_out_record cash
         LEFT JOIN store_info store ON cash.store_id = store.id

+ 25 - 0
alien-entity/src/main/resources/mapper/VideoModerationTaskMapper.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="shop.alien.mapper.system.VideoModerationTaskMapper">
+    
+    <!-- 创建视频审核任务表 -->
+    <update id="createTableIfNotExists">
+        CREATE TABLE IF NOT EXISTS `video_moderation_task` (
+          `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+          `data_id` varchar(64) NOT NULL COMMENT '数据ID',
+          `video_url` varchar(512) NOT NULL COMMENT '视频URL',
+          `task_id` varchar(64) NOT NULL COMMENT '任务ID',
+          `status` varchar(20) NOT NULL DEFAULT 'SUBMITTED' COMMENT '任务状态 (SUBMITTED-已提交, PROCESSING-处理中, SUCCESS-成功, FAILED-失败)',
+          `risk_level` varchar(10) DEFAULT NULL COMMENT '风险级别 (none-无风险, low-低风险, medium-中风险, high-高风险)',
+          `result` text COMMENT '审核结果(JSON格式)',
+          `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+          `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+          `retry_count` int(11) NOT NULL DEFAULT '0' COMMENT '重试次数',
+          PRIMARY KEY (`id`),
+          UNIQUE KEY `uk_task_id` (`task_id`),
+          KEY `idx_status` (`status`),
+          KEY `idx_create_time` (`create_time`)
+        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='视频审核任务表';
+    </update>
+    
+</mapper>

+ 17 - 3
alien-entity/src/main/resources/mapper/second/SecondGoodsInfoMapper.xml

@@ -30,6 +30,7 @@
         <result column="home_image" property="homeImage" jdbcType="VARCHAR"/>
         <result column="user_phone" property="userPhone" jdbcType="VARCHAR"/>
         <result column="release_time" property="releaseTime" jdbcType="VARCHAR"/>
+        <result column="video_first_frame" property="videoFirstFrame" jdbcType="VARCHAR"/>
 
     </resultMap>
 
@@ -79,11 +80,18 @@
             and not exists (select 1 from shieldUser s where s.id = g.id)
             and not exists (select 1 from second_shield s where s.user_id = #{userId} and s.shield_type = 1 and s.shield_id = g.id and s.delete_flag = 0)
             and g.goods_status = 3
+            and g.position != '' and g.position is not null
         order by dist, like_count desc, release_time desc
     </select>
 
     <!-- 分页查询关注数据concern -->
     <select id="querySecondConcernByPage" resultType="shop.alien.entity.second.vo.SecondGoodsRecommendVo">
+        with shieldUser as (
+            select g.id from life_blacklist lb inner join second_goods g
+            on lb.blocked_id = g.user_id  and g.delete_flag = '0' and g.goods_status = '3'
+            where lb.delete_flag = 0 and lb.blocker_type = 2 and lb.blocked_type = 2
+            and lb.blocker_id = #{userId}
+        )
         select
             g.id,
             g.user_id,
@@ -111,6 +119,7 @@
             case when lc.id is null then '0' else '1' end collectStatus,
             (select count(1) from (SELECT id FROM store_comment c where c.business_id = g.id and c.business_type = 7 and c.delete_flag = 0 UNION ALL
             SELECT t.id FROM store_comment t INNER JOIN (SELECT id FROM store_comment c where c.business_id = g.id and c.business_type = 7 and c.delete_flag = 0) d ON t.reply_id = d.id and business_type = 6 and delete_flag = 0) a ) as commentCount
+<!--            (SELECT count(1) FROM store_comment c where c.business_id = g.id and c.business_type = 7 and c.delete_flag = 0 ) as commentCount-->
         from
             life_fans f inner join life_user u on
                 f.followed_id = CONCAT('user_', u.user_phone) and u.delete_flag = 0
@@ -122,6 +131,9 @@
             left join life_collect lc on lc.business_id = g.id and lc.user_id = #{phoneId} and lc.delete_flag = 0 and lc.business_type = 1
         where
             f.fans_id = #{phoneId} and f.delete_flag = 0
+            and not exists (select 1 from shieldUser s where s.id = g.id)
+            and not exists (select 1 from second_shield s where s.user_id = #{userId} and s.shield_type = 1 and s.shield_id = g.id and s.delete_flag = 0)
+            and g.position != '' and g.position is not null
         order by g.release_time desc
     </select>
 
@@ -190,14 +202,16 @@
             case when lc.id is null then '0' else '1' end collectStatus,
             (select count(1) from (SELECT id FROM store_comment c where c.business_id = g.id and c.business_type = 7 and c.delete_flag = 0 UNION ALL
             SELECT t.id FROM store_comment t INNER JOIN (SELECT id FROM store_comment c where c.business_id = g.id and c.business_type = 7 and c.delete_flag = 0) d ON t.reply_id = d.id and business_type = 6 and delete_flag = 0) a ) as commentCount
+<!--            (SELECT count(1) FROM store_comment c where c.business_id = g.id and c.business_type = 7 and c.delete_flag = 0 ) as commentCount-->
         FROM
-            second_goods g inner join life_user u on u.id =  g.user_id
+            second_goods g inner join life_user u on u.id = g.user_id
             left join life_like_record llr on llr.dianzan_id = #{phoneId} and llr.huifu_id = g.id and llr.type = 6 and llr.delete_flag = 0
             left join life_collect lc on lc.business_id = g.id and lc.user_id = #{phoneId} and lc.delete_flag = 0 and lc.business_type = 1
         where g.delete_flag = 0
             and not exists (select 1 from shieldUser s where s.id = g.id)
             and not exists (select 1 from second_shield s where s.user_id = #{userId} and s.shield_type = 1 and s.shield_id = g.id)
             and g.goods_status = 3
+            and g.position != '' and g.position is not null
         order by g.release_time desc
     </select>
 
@@ -217,19 +231,19 @@
             g.topic,
             g.home_image,
             g.release_time,
+            g.video_first_frame,
             lu.user_name,
             CONCAT('user_', lu.user_phone) as user_phone,
             lu.user_image,
             goods_status,
             ROUND(ST_Distance_Sphere(ST_GeomFromText(CONCAT('POINT(', REPLACE(#{position}, ',', ' '), ')' )), ST_GeomFromText(CONCAT('POINT(', REPLACE(g.position, ',', ' '), ')' ))) / 1000, 2) AS dist,
-            (select count(1) from (SELECT id FROM store_comment c where c.business_id = g.id and c.business_type = 7 and c.delete_flag = 0 UNION ALL
-            SELECT t.id FROM store_comment t INNER JOIN (SELECT id FROM store_comment c where c.business_id = g.id and c.business_type = 7 and c.delete_flag = 0) d ON t.reply_id = d.id and business_type = 6 and delete_flag = 0) a ) as commentCount,
             case when llr.id is null then '0' else '1' end likeStatus,
             case when lc.id is null then '0' else '1' end collectStatus
         from second_goods g inner join life_user lu on g.user_id = lu.id and lu.delete_flag = 0
             left join life_like_record llr on llr.dianzan_id = #{phoneId} and llr.huifu_id = g.id and llr.type = 6 and llr.delete_flag = 0
             left join life_collect lc on lc.business_id = g.id and lc.user_id = #{phoneId} and lc.delete_flag = 0 and lc.business_type = 1
         where g.id = #{goodsId} and g.delete_flag = 0
+            and g.position != '' and g.position is not null
     </select>
 
 </mapper>

+ 5 - 0
alien-entity/src/main/resources/mapper/second/SecondGoodsRecordMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="shop.alien.mapper.second.SecondGoodsRecordMapper">
+
+</mapper>

+ 1 - 0
alien-gateway/src/main/resources/bootstrap-prod.yml

@@ -9,6 +9,7 @@ spring:
         server-addr: localhost:8848
         username: nacos
         password: ngfriend198092
+        namespace: 3cbb802a-b56e-47f7-b658-b5012ecafb1f
 
       #配置中心
       config:

+ 1 - 0
alien-gateway/src/main/resources/bootstrap-test.yml

@@ -9,6 +9,7 @@ spring:
         server-addr: 192.168.2.252:8848
         username: nacos
         password: ngfriend198092
+        namespace: 0e1e2d77-56e8-422c-8317-6f71d7285e59
 
       #配置中心
       config:

+ 1 - 1
alien-gateway/src/main/resources/logback-spring.xml

@@ -12,7 +12,7 @@
     <!-- 定义全局参数常量 -->
     <property name="log.level" value="debug"/>
     <property name="log.maxHistory" value="30"/><!-- 30表示30个 -->
-    <property name="logging.path" value="/javaLog/alienGatewayLog"/>
+    <springProperty scope="context" name="logging.path" source="logging.path"/>
     <!--输出文件前缀-->
     <property name="FILENAME" value="xiaokuihua_gateway"/>
 

+ 5 - 0
alien-job/pom.xml

@@ -46,6 +46,11 @@
         </dependency>
 
         <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-openfeign</artifactId>
+        </dependency>
+
+        <dependency>
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>
         </dependency>

+ 1 - 2
alien-job/src/main/java/shop/alien/job/AlienJobApplication.java

@@ -6,9 +6,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.cloud.openfeign.EnableFeignClients;
 import org.springframework.context.annotation.ComponentScan;
 
-
 @SpringBootApplication
-@ComponentScan({"shop.alien.job.*", "shop.alien.config.redis", "shop.alien.config.databases",})
+@ComponentScan({"shop.alien.job.*", "shop.alien.util.*","shop.alien.config.redis", "shop.alien.config.databases",})
 @MapperScan({"shop.alien.mapper"})
 @EnableFeignClients(basePackages = {"shop.alien.job.feign"})
 public class AlienJobApplication {

+ 31 - 1
alien-job/src/main/java/shop/alien/job/feign/AlienStoreFeign.java

@@ -5,7 +5,7 @@ import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 
-@FeignClient(url = "http://localhost:8888", name = "alien-store")
+@FeignClient(url = "${feign.alienStore.url}", name = "alien-store")
 public interface AlienStoreFeign {
 
     @GetMapping("/websocket/sendMsgToClientByPhoneId")
@@ -13,4 +13,34 @@ public interface AlienStoreFeign {
             @RequestParam(value = "messageReceiverId") String messageReceiverId,
             @RequestParam(value = "webSocketVoStr") String webSocketVoStr);
 
+    /**
+     * 转账
+     *
+     * @param name
+     * @param idCard
+     * @param phone
+     * @param money
+     * @return
+     */
+    @GetMapping("/ali/pay")
+    JSONObject aliPay(
+            @RequestParam(value = "name") String name,
+            @RequestParam(value = "idCard") String idCard,
+            @RequestParam(value = "phone") String phone,
+            @RequestParam(value = "money") String money
+    );
+
+    /**
+     * 删除附近商家
+     *
+     * @param flag
+     * @param content
+     * @return
+     */
+    @GetMapping("/near/me/delMer")
+    JSONObject delMer(
+            @RequestParam(value = "flag") Boolean flag,
+            @RequestParam(value = "content") String content
+    );
+
 }

+ 27 - 0
alien-job/src/main/java/shop/alien/job/feign/SecondGoodsFeign.java

@@ -0,0 +1,27 @@
+package shop.alien.job.feign;
+
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+@FeignClient(name = "alien-second", url = "http://localhost:9999")
+public interface SecondGoodsFeign {
+    
+    /**
+     * 处理视频审核结果
+     * 
+     * @param taskId 任务ID
+     * @return 处理结果
+     */
+    @GetMapping("/secondGoods/processVideoResult")
+    boolean processVideoResult(@RequestParam("taskId") String taskId);
+
+    /**
+     * 处理单个视频审核任务
+     *
+     * @param taskId 任务ID
+     * @return 处理结果
+     */
+    @GetMapping("/video/moderation/processTask")
+    boolean processTask(@RequestParam("taskId") String taskId);
+}

+ 73 - 0
alien-job/src/main/java/shop/alien/job/jobhandler/VideoModerationJobHandler.java

@@ -0,0 +1,73 @@
+package shop.alien.job.jobhandler;
+
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.handler.annotation.XxlJob;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import shop.alien.entity.SecondVideoTask;
+import shop.alien.job.feign.SecondGoodsFeign;
+import shop.alien.mapper.system.SecondVideoTaskMapper;
+
+import java.util.List;
+
+/**
+ * 视频审核任务XXL-JOB处理器
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class VideoModerationJobHandler {
+
+    /**
+     * 视频审核任务Mapper
+     */
+    private final SecondVideoTaskMapper videoModerationTaskMapper;
+
+    /**
+     * 二级商品服务Feign客户端
+     */
+    private final SecondGoodsFeign secondGoodsFeign;
+    
+    /**
+     * 视频审核结果拉取任务
+     * 每30秒执行一次
+     */
+    @XxlJob("videoModerationResultJobHandler")
+    public ReturnT<String> videoModerationResultJobHandler(String param) {
+        try {
+            log.info("开始执行视频审核结果拉取任务");
+            
+            // 查询待处理的审核任务(状态为SUBMITTED或PROCESSING)
+            List<SecondVideoTask> pendingTasks = videoModerationTaskMapper.selectPendingTasks();
+            
+            if (pendingTasks.isEmpty()) {
+                log.info("没有待处理的视频审核任务");
+                return ReturnT.SUCCESS;
+            }
+            
+            log.info("共找到 {} 个待处理的视频审核任务", pendingTasks.size());
+            
+            // 处理每个任务
+            int successCount = 0;
+            for (SecondVideoTask task : pendingTasks) {
+                try {
+                    boolean success = secondGoodsFeign.processTask(task.getTaskId());
+                    if (success) {
+                        successCount++;
+                        // 处理视频审核结果,更新商品状态
+                        secondGoodsFeign.processVideoResult(task.getTaskId());
+                    }
+                } catch (Exception e) {
+                    log.error("处理视频审核任务时发生异常,任务ID: {}", task.getTaskId(), e);
+                }
+            }
+            
+            log.info("视频审核结果拉取任务执行完成,成功处理 {} 个任务", successCount);
+            return ReturnT.SUCCESS;
+        } catch (Exception e) {
+            log.error("执行视频审核结果拉取任务时发生异常", e);
+            return ReturnT.FAIL;
+        }
+    }
+}

+ 99 - 96
alien-job/src/main/java/shop/alien/job/second/SecondGoodsTradeXxlJob.java

@@ -53,19 +53,17 @@ public class SecondGoodsTradeXxlJob {
      */
     @XxlJob("secondTradeRemind")
     public void secondTradeRemind() throws Exception {
-        Date now = Date.from(LocalDateTime.now().plusMinutes(10).withSecond(0).withNano(0).atZone(ZoneId.systemDefault()).toInstant());
-
-        // 查询所有待交易
-        LambdaQueryWrapper<SecondTradeRecord> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(SecondTradeRecord::getTradeStatus, 3);
-        wrapper.eq(SecondTradeRecord::getTransactionTime, now);
-        List<SecondTradeRecord> tradeRecordList = secondTradeRecordMapper.selectList(wrapper);
-
-        for (SecondTradeRecord tradeRecord : tradeRecordList) {
-            // 十分钟前
-//            LocalDateTime tenMinutesAgo = tradeRecord.getTransactionTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().minusMinutes(10).withSecond(0).withNano(0);
-//            // 交易时间的十分钟前
-//            if (now.isEqual(tenMinutesAgo)) {
+        log.info("开始执行定时任务: 二手交易平台 - 10分钟后交易提醒 - secondTradeRemind");
+        try {
+            Date now = Date.from(LocalDateTime.now().plusMinutes(10).withSecond(0).withNano(0).atZone(ZoneId.systemDefault()).toInstant());
+
+            // 查询所有待交易
+            LambdaQueryWrapper<SecondTradeRecord> wrapper = new LambdaQueryWrapper<>();
+            wrapper.eq(SecondTradeRecord::getTradeStatus, 3);
+            wrapper.eq(SecondTradeRecord::getTransactionTime, now);
+            List<SecondTradeRecord> tradeRecordList = secondTradeRecordMapper.selectList(wrapper);
+
+            for (SecondTradeRecord tradeRecord : tradeRecordList) {
                 LifeUser buyer = lifeUserMapper.selectById(tradeRecord.getBuyerId());
                 LifeUser seller = lifeUserMapper.selectById(tradeRecord.getSellerId());
 
@@ -175,7 +173,9 @@ public class SecondGoodsTradeXxlJob {
                 webSocketVo.setText(JSONObject.from(lifeNotice).toJSONString());
                 webSocketVo.setMessageId(lifeMessage.getId());
                 alienStoreFeign.sendMsgToClientByPhoneId(sellerPhoneId, JSONObject.from(webSocketVo).toJSONString());
-//            }
+            }
+        } catch (Exception e) {
+            log.error("SecondGoodsTradeXxlJob.secondTradeRemind Error Msg={}", e.getMessage());
         }
     }
 
@@ -184,6 +184,7 @@ public class SecondGoodsTradeXxlJob {
      */
     @XxlJob("secondTradeConfirm")
     public void secondTradeConfirm() throws Exception {
+        log.info("开始执行定时任务: 二手交易平台 - 到达交易时间时,给买家和卖家发送交易确认提醒 - secondTradeConfirm");
         try {
             Date now = Date.from(LocalDateTime.now().withSecond(0).withNano(0).atZone(ZoneId.systemDefault()).toInstant());
 
@@ -194,70 +195,67 @@ public class SecondGoodsTradeXxlJob {
             List<SecondTradeRecord> tradeRecordList = secondTradeRecordMapper.selectList(wrapper);
 
             for (SecondTradeRecord tradeRecord : tradeRecordList) {
-//                LocalDateTime tenMinutesAgo = tradeRecord.getTransactionTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().withSecond(0).withNano(0);
-//                if (now.isEqual(tenMinutesAgo)) {
-                    LifeUser buyer = lifeUserMapper.selectById(tradeRecord.getBuyerId());
-                    LifeUser seller = lifeUserMapper.selectById(tradeRecord.getSellerId());
-                    SecondGoods goods = secondGoodsMapper.selectById(tradeRecord.getGoodsId());
-
-                    String buyerPhoneId = null == buyer ? "" : "user_" + buyer.getUserPhone();
-                    String sellerPhoneId = null == seller ? "" : "user_" + seller.getUserPhone();
-
-                    // 给买家发送通知
-                    LifeNotice lifeNotice = new LifeNotice();
-                    lifeNotice.setSenderId("system");
-                    lifeNotice.setReceiverId(buyerPhoneId);
-                    lifeNotice.setBusinessId(tradeRecord.getId());
-                    lifeNotice.setTitle("商品是否交易成功");
-                    lifeNotice.setNoticeType(1);
-                    // 封装通知信息
-                    JSONObject noticeMessage = new JSONObject();
-                    noticeMessage.put("goodsId", goods.getId());
-                    noticeMessage.put("goodsHomeImage", goods.getHomeImage());
-                    noticeMessage.put("goodsTitle", goods.getTitle());
-                    noticeMessage.put("tradeId", tradeRecord.getId());
-                    noticeMessage.put("transactionAmount", tradeRecord.getTransactionAmount());
-                    noticeMessage.put("transactionLatitudeLongitude", tradeRecord.getTransactionLatitudeLongitude());
-                    noticeMessage.put("transactionLatitudeLongitudeAddress", tradeRecord.getTransactionLatitudeLongitudeAddress());
-                    noticeMessage.put("transactionLocation", tradeRecord.getTransactionLocation());
-                    noticeMessage.put("transactionTime", tradeRecord.getTransactionTime());
-                    noticeMessage.put("tradeStatus", tradeRecord.getTradeStatus());
-                    noticeMessage.put("message", "您有一笔交易已完成, 请前往确认");
-                    lifeNotice.setContext(noticeMessage.toJSONString());
-                    lifeNoticeMapper.insert(lifeNotice);
-
-                    // 给买家推送通知
-                    WebSocketVo webSocketVo = new WebSocketVo();
-                    webSocketVo.setSenderId("system");
-                    webSocketVo.setReceiverId(buyerPhoneId);
-                    webSocketVo.setCategory("notice");
-                    webSocketVo.setNoticeType("1");
-                    webSocketVo.setType("5");
-                    webSocketVo.setIsRead(0);
-                    webSocketVo.setText(JSONObject.from(lifeNotice).toJSONString());
-                    alienStoreFeign.sendMsgToClientByPhoneId(buyerPhoneId, JSONObject.from(webSocketVo).toJSONString());
-
-                    // 给卖家发送通知
-                    lifeNotice = new LifeNotice();
-                    lifeNotice.setSenderId("system");
-                    lifeNotice.setReceiverId(sellerPhoneId);
-                    lifeNotice.setBusinessId(tradeRecord.getId());
-                    lifeNotice.setTitle("商品是否交易成功");
-                    lifeNotice.setNoticeType(1);
-                    lifeNotice.setContext(noticeMessage.toJSONString());
-                    lifeNoticeMapper.insert(lifeNotice);
-
-                    // 给卖家推送通知
-                    webSocketVo = new WebSocketVo();
-                    webSocketVo.setSenderId("system");
-                    webSocketVo.setReceiverId(sellerPhoneId);
-                    webSocketVo.setCategory("notice");
-                    webSocketVo.setNoticeType("1");
-                    webSocketVo.setType("5");
-                    webSocketVo.setIsRead(0);
-                    webSocketVo.setText(JSONObject.from(lifeNotice).toJSONString());
-                    alienStoreFeign.sendMsgToClientByPhoneId(sellerPhoneId, JSONObject.from(webSocketVo).toJSONString());
-//                }
+                LifeUser buyer = lifeUserMapper.selectById(tradeRecord.getBuyerId());
+                LifeUser seller = lifeUserMapper.selectById(tradeRecord.getSellerId());
+                SecondGoods goods = secondGoodsMapper.selectById(tradeRecord.getGoodsId());
+
+                String buyerPhoneId = null == buyer ? "" : "user_" + buyer.getUserPhone();
+                String sellerPhoneId = null == seller ? "" : "user_" + seller.getUserPhone();
+
+                // 给买家发送通知
+                LifeNotice lifeNotice = new LifeNotice();
+                lifeNotice.setSenderId("system");
+                lifeNotice.setReceiverId(buyerPhoneId);
+                lifeNotice.setBusinessId(tradeRecord.getId());
+                lifeNotice.setTitle("商品是否交易成功");
+                lifeNotice.setNoticeType(1);
+                // 封装通知信息
+                JSONObject noticeMessage = new JSONObject();
+                noticeMessage.put("goodsId", goods.getId());
+                noticeMessage.put("goodsHomeImage", goods.getHomeImage());
+                noticeMessage.put("goodsTitle", goods.getTitle());
+                noticeMessage.put("tradeId", tradeRecord.getId());
+                noticeMessage.put("transactionAmount", tradeRecord.getTransactionAmount());
+                noticeMessage.put("transactionLatitudeLongitude", tradeRecord.getTransactionLatitudeLongitude());
+                noticeMessage.put("transactionLatitudeLongitudeAddress", tradeRecord.getTransactionLatitudeLongitudeAddress());
+                noticeMessage.put("transactionLocation", tradeRecord.getTransactionLocation());
+                noticeMessage.put("transactionTime", tradeRecord.getTransactionTime());
+                noticeMessage.put("tradeStatus", tradeRecord.getTradeStatus());
+                noticeMessage.put("message", "您有一笔交易已完成, 请前往确认");
+                lifeNotice.setContext(noticeMessage.toJSONString());
+                lifeNoticeMapper.insert(lifeNotice);
+
+                // 给买家推送通知
+                WebSocketVo webSocketVo = new WebSocketVo();
+                webSocketVo.setSenderId("system");
+                webSocketVo.setReceiverId(buyerPhoneId);
+                webSocketVo.setCategory("notice");
+                webSocketVo.setNoticeType("1");
+                webSocketVo.setType("5");
+                webSocketVo.setIsRead(0);
+                webSocketVo.setText(JSONObject.from(lifeNotice).toJSONString());
+                alienStoreFeign.sendMsgToClientByPhoneId(buyerPhoneId, JSONObject.from(webSocketVo).toJSONString());
+
+                // 给卖家发送通知
+                lifeNotice = new LifeNotice();
+                lifeNotice.setSenderId("system");
+                lifeNotice.setReceiverId(sellerPhoneId);
+                lifeNotice.setBusinessId(tradeRecord.getId());
+                lifeNotice.setTitle("商品是否交易成功");
+                lifeNotice.setNoticeType(1);
+                lifeNotice.setContext(noticeMessage.toJSONString());
+                lifeNoticeMapper.insert(lifeNotice);
+
+                // 给卖家推送通知
+                webSocketVo = new WebSocketVo();
+                webSocketVo.setSenderId("system");
+                webSocketVo.setReceiverId(sellerPhoneId);
+                webSocketVo.setCategory("notice");
+                webSocketVo.setNoticeType("1");
+                webSocketVo.setType("5");
+                webSocketVo.setIsRead(0);
+                webSocketVo.setText(JSONObject.from(lifeNotice).toJSONString());
+                alienStoreFeign.sendMsgToClientByPhoneId(sellerPhoneId, JSONObject.from(webSocketVo).toJSONString());
             }
         } catch (Exception e) {
             log.error("SecondGoodsTradeXxlJob.secondTradeConfirm Error Mgs={}", e.getMessage());
@@ -269,24 +267,29 @@ public class SecondGoodsTradeXxlJob {
      */
     @XxlJob("secondTradeTimeoutCancel")
     private void secondTradeTimeoutCancel() {
-        LocalDateTime now = LocalDateTime.now().withSecond(0).withNano(0);
-
-        // 查询所有待确认
-        LambdaQueryWrapper<SecondTradeRecord> queryWrapper = new LambdaQueryWrapper<>();
-        queryWrapper.eq(SecondTradeRecord::getTradeStatus, 1);
-        List<SecondTradeRecord> tradeRecordList = secondTradeRecordMapper.selectList(queryWrapper);
-        List<Integer> tradeIdList = new ArrayList<>();
-        for (SecondTradeRecord tradeRecord : tradeRecordList) {
-            LocalDateTime tenMinutesAgo = tradeRecord.getTransactionTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().withSecond(0).withNano(0);
-            if (now.isEqual(tenMinutesAgo)) {
-                tradeIdList.add(tradeRecord.getId());
+        log.info("开始执行定时任务: 二手交易平台 - 交易超时未确认则自动取消 - secondTradeTimeoutCancel");
+        try {
+            LocalDateTime now = LocalDateTime.now().withSecond(0).withNano(0);
+
+            // 查询所有待确认
+            LambdaQueryWrapper<SecondTradeRecord> queryWrapper = new LambdaQueryWrapper<>();
+            queryWrapper.eq(SecondTradeRecord::getTradeStatus, 1);
+            List<SecondTradeRecord> tradeRecordList = secondTradeRecordMapper.selectList(queryWrapper);
+            List<Integer> tradeIdList = new ArrayList<>();
+            for (SecondTradeRecord tradeRecord : tradeRecordList) {
+                LocalDateTime tenMinutesAgo = tradeRecord.getTransactionTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().withSecond(0).withNano(0);
+                if (now.isEqual(tenMinutesAgo)) {
+                    tradeIdList.add(tradeRecord.getId());
+                }
             }
-        }
-        if (CollectionUtil.isNotEmpty(tradeIdList)) {
-            LambdaUpdateWrapper<SecondTradeRecord> updateWrapper = new LambdaUpdateWrapper<>();
-            updateWrapper.in(SecondTradeRecord::getId, tradeIdList)
-                    .set(SecondTradeRecord::getTradeStatus, 6);
-            secondTradeRecordMapper.update(null, updateWrapper);
+            if (CollectionUtil.isNotEmpty(tradeIdList)) {
+                LambdaUpdateWrapper<SecondTradeRecord> updateWrapper = new LambdaUpdateWrapper<>();
+                updateWrapper.in(SecondTradeRecord::getId, tradeIdList)
+                        .set(SecondTradeRecord::getTradeStatus, 6);
+                secondTradeRecordMapper.update(null, updateWrapper);
+            }
+        } catch (Exception e) {
+            log.error("SecondGoodsTradeXxlJob.secondTradeTimeoutCancel Error Mgs={}", e.getMessage());
         }
     }
 
@@ -294,8 +297,8 @@ public class SecondGoodsTradeXxlJob {
      * 二手交易平台 - 每分钟从redis中读取已读的消息id 并将数据库设为已读
      */
     @XxlJob("readMessage")
-    @Scheduled(cron = "0 * * * * ?")
     public void readMessage() {
+        log.info("开始执行定时任务: 二手交易平台 - 每分钟从redis中读取已读的消息id 并将数据库设为已读 - readMessage");
         try {
             if (CollectionUtil.isEmpty(baseRedisService.getList("readMessageIdKey"))) return;
 

+ 9 - 9
alien-store/src/main/java/shop/alien/store/job/DeliciousFoodJob.java → alien-job/src/main/java/shop/alien/job/store/DeliciousFoodJob.java

@@ -1,13 +1,13 @@
-package shop.alien.store.job;
+package shop.alien.job.store;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.xxl.job.core.handler.annotation.XxlJob;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
+import shop.alien.config.redis.BaseRedisService;
 import shop.alien.entity.store.*;
 import shop.alien.mapper.*;
-import shop.alien.store.config.BaseRedisService;
 
 import java.text.SimpleDateFormat;
 import java.time.LocalDate;
@@ -61,7 +61,7 @@ public class DeliciousFoodJob {
     /**
      * 美食筛选标签定时存储数据
      */
-//    @Scheduled(cron = "0 0 0/2 * * ?")
+    @XxlJob("deliciousFoodJob")
     public void deliciousFoodJob() {
         // 获取所有美食筛选
         List<EssentialModuleInformation> essentialModuleInformations = informationMapper.selectList(
@@ -486,7 +486,7 @@ public class DeliciousFoodJob {
     /**
      * 酒店和民宿筛选标签定时存储数据
      */
-//    @Scheduled(cron = "0 0 0/2 * * ?")
+    @XxlJob("hotelAndHomestayJob")
     public void hotelAndHomestayJob() {
         // 获取所有酒店民宿筛选
         List<EssentialModuleInformation> essentialModuleInformations = informationMapper.selectList(
@@ -1033,7 +1033,7 @@ public class DeliciousFoodJob {
     /**
      * 汗蒸洗浴筛选标签定时存储数据
      */
-//    @Scheduled(cron = "0 0 0/2 * * ?")
+    @XxlJob("takeABathAndSaunaJob")
     public void takeABathAndSaunaJob() {
         // 获取所有洗浴汗蒸筛选
         List<EssentialModuleInformation> essentialModuleInformations = informationMapper.selectList(
@@ -1284,7 +1284,7 @@ public class DeliciousFoodJob {
     /**
      * 丽人美发筛选标签定时存储数据
      */
-//    @Scheduled(cron = "0 0 0/2 * * ?")
+    @XxlJob("lirenHairdressingJob")
     public void lirenHairdressingJob() {
         // 获取所有丽人筛选
         List<EssentialModuleInformation> essentialModuleInformations = informationMapper.selectList(
@@ -1299,7 +1299,7 @@ public class DeliciousFoodJob {
     /**
      * 运动健身筛选标签定时存储数据
      */
-//    @Scheduled(cron = "0 0 0/2 * * ?")
+    @XxlJob("sportsAndFitnessJob")
     public void sportsAndFitnessJob() {
         // 获取所有的运动健身1级菜单
         List<EssentialModuleInformation> moduleInformations = informationMapper.selectList(
@@ -1385,7 +1385,7 @@ public class DeliciousFoodJob {
     /**
      * 医美医疗筛选标签定时存储数据
      */
-//    @Scheduled(cron = "0 0 0/2 * * ?")
+    @XxlJob("medicalAestheticsJob")
     public void medicalAestheticsJob() {
         // 获取所有医美医疗筛选标签
         List<EssentialModuleInformation> essentialModuleInformations = informationMapper.selectList(

+ 4 - 4
alien-store/src/main/java/shop/alien/store/job/KTVJob.java → alien-job/src/main/java/shop/alien/job/store/KTVJob.java

@@ -1,13 +1,13 @@
-package shop.alien.store.job;
+package shop.alien.job.store;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.xxl.job.core.handler.annotation.XxlJob;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
+import shop.alien.config.redis.BaseRedisService;
 import shop.alien.entity.store.*;
-import shop.alien.store.config.BaseRedisService;
 import shop.alien.mapper.EssentialModuleInformationMapper;
 import shop.alien.mapper.LifeCouponMapper;
 import shop.alien.mapper.StoreInfoMapper;
@@ -37,7 +37,7 @@ public class KTVJob {
 
     private final StoreLabelTypeMapper storeLabelTypeMapper;
 
-//    @Scheduled(cron = "0 0 0/2 * * ?")
+    @XxlJob("ktvJob")
     public void ktvJob() {
 
         // 获取所有的商家信息

+ 164 - 0
alien-job/src/main/java/shop/alien/job/store/LifeCouponJob.java

@@ -0,0 +1,164 @@
+package shop.alien.job.store;
+
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.xxl.job.core.handler.annotation.XxlJob;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import shop.alien.entity.store.LifeCoupon;
+import shop.alien.entity.store.LifeUserOrder;
+import shop.alien.mapper.LifeCouponMapper;
+import shop.alien.mapper.LifeUserOrderMapper;
+import shop.alien.util.common.AlipayTradeRefund;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 优惠券定时任务
+ *
+ * @author ssk
+ * @version 1.0
+ * @date 2025/8/6 14:19
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class LifeCouponJob {
+
+    private final LifeCouponMapper lifeCouponMapper;
+
+    private final LifeUserOrderMapper lifeUserOrderMapper;
+
+    private final AlipayTradeRefund alipayTradeRefund;
+
+    /**
+     * 该方法用于定时更新生活优惠券(LifeCoupon)的状态
+     */
+    @XxlJob("quanStatusUpdateTask")
+    public void quanStatusUpdateTask() {
+        //执行修改代金券状态
+        System.out.println("执行修改代金券状态 ===>");
+        // 获取当前时间
+        Date now = new Date();
+        // 创建一个 Calendar 实例,用于对日期进行操作
+        Calendar calendar = Calendar.getInstance();
+        // 将 Calendar 的时间设置为当前时间
+        calendar.setTime(now);
+        // 将 Calendar 的小时设置为 0
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        // 将 Calendar 的分钟设置为 0
+        calendar.set(Calendar.MINUTE, 0);
+        // 将 Calendar 的秒设置为 0
+        calendar.set(Calendar.SECOND, 0);
+        // 将 Calendar 的毫秒设置为 0
+        calendar.set(Calendar.MILLISECOND, 0);
+        // 获取处理后的时间,即当前日期的零点
+        now = calendar.getTime();
+
+        // 创建一个 LambdaUpdateWrapper 用于查询生活优惠券,这里实际上主要用于查询操作
+        LambdaUpdateWrapper<LifeCoupon> selectWrapper = new LambdaUpdateWrapper<>();
+        // 创建一个集合,用于存储要查询的优惠券状态值
+        List<Integer> ids = new ArrayList<>();
+        // 待审核
+        ids.add(0);
+        // 进行中
+        ids.add(1);
+        // 已暂停
+        ids.add(2);
+        // 设置查询条件,查询状态为 0、1 或 2 的生活优惠券
+        selectWrapper.in(LifeCoupon::getStatus, ids);
+        // 调用 lifeCouponMapper 的 selectList 方法,根据上述条件查询生活优惠券列表
+        List<LifeCoupon> jinxingzhongList = lifeCouponMapper.selectList(selectWrapper);
+        // 判断查询结果列表是否不为空
+        if (!jinxingzhongList.isEmpty()) {
+            // 遍历查询到的生活优惠券列表
+            for (LifeCoupon quan : jinxingzhongList) {
+                // 获取当前优惠券的结束日期
+                Date endTime = quan.getEndDate();
+                // 比较当前日期(零点)和优惠券的结束日期,如果当前日期大于结束日期  将状态变成已结束
+                if (now.compareTo(endTime) > 0) {
+                    // 创建一个 LambdaUpdateWrapper 用于更新生活优惠券的状态
+                    LambdaUpdateWrapper<LifeCoupon> updateWrapper = new LambdaUpdateWrapper<>();
+                    // 设置更新条件,根据优惠券的 ID 进行更新
+                    updateWrapper.eq(LifeCoupon::getId, quan.getId())
+                            // 设置要更新的字段,将优惠券的状态更新为 3
+                            .set(LifeCoupon::getStatus, 3);
+                    // 调用 lifeCouponMapper 的 update 方法,根据上述条件更新优惠券的状态
+                    lifeCouponMapper.update(null, updateWrapper);
+                }
+            }
+        }
+
+        // 创建另一个 LambdaUpdateWrapper 用于查询状态为 0 的生活优惠券
+        LambdaUpdateWrapper<LifeCoupon> selectWrapper2 = new LambdaUpdateWrapper<>();
+        // 设置查询条件,查询状态为 0 的生活优惠券
+        selectWrapper2.eq(LifeCoupon::getStatus, 0);
+        // 调用 lifeCouponMapper 的 selectList 方法,根据上述条件查询生活优惠券列表
+        List<LifeCoupon> weikaishiList = lifeCouponMapper.selectList(selectWrapper2);
+        // 判断查询结果列表是否不为空
+        if (!weikaishiList.isEmpty()) {
+            // 遍历查询到的生活优惠券列表
+            for (LifeCoupon quan : weikaishiList) {
+                // 获取当前优惠券的开始日期
+                Date startTime = quan.getStartDate();
+                // 获取当前优惠券的结束日期
+                Date endTime = quan.getEndDate();
+                // 判断当前日期(零点)是否在优惠券的开始日期和结束日期之间  将待使用变成进行中
+                if (now.compareTo(startTime) >= 0 && now.compareTo(endTime) <= 0) {
+                    // 创建一个 LambdaUpdateWrapper 用于更新生活优惠券的状态
+                    LambdaUpdateWrapper<LifeCoupon> updateWrapper = new LambdaUpdateWrapper<>();
+                    // 设置更新条件,根据优惠券的 ID 进行更新
+                    updateWrapper.eq(LifeCoupon::getId, quan.getId())
+                            // 设置要更新的字段,将优惠券的状态更新为 1
+                            .set(LifeCoupon::getStatus, 1);
+                    // 调用 lifeCouponMapper 的 update 方法,根据上述条件更新优惠券的状态
+                    lifeCouponMapper.update(null, updateWrapper);
+                }
+            }
+        }
+    }
+
+    /**
+     * 过期自动退
+     */
+    @XxlJob("orderStatusUpdateTask")
+    public void orderStatusUpdateTask() {
+        Date now = new Date();
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(now);
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+        now = calendar.getTime();
+        LambdaUpdateWrapper<LifeUserOrder> selectWrapper = new LambdaUpdateWrapper<>();
+        List<Integer> ids = new ArrayList<>();
+        ids.add(0);
+        ids.add(3);
+        selectWrapper.in(LifeUserOrder::getStatus, ids);
+        List<LifeUserOrder> orderList = lifeUserOrderMapper.selectList(selectWrapper);
+        if (!orderList.isEmpty()) {
+            for (LifeUserOrder order : orderList) {
+                Date payTime = order.getPayTime();
+                LifeCoupon quan = lifeCouponMapper.selectById(order.getQuanId());
+                calendar.setTime(payTime);
+                calendar.add(Calendar.DAY_OF_MONTH, quan.getExpirationDate());
+                Date guoqiDate = calendar.getTime();
+                Date endDate = quan.getEndDate();
+                if (now.compareTo(guoqiDate) > 0 || now.compareTo(endDate) > 0) {
+                    String result = alipayTradeRefund.processRefund(order.getOrderNo(), order.getFinalPrice(), "过期自动退");
+                    if (result.equals("调用成功")) {
+                        LambdaUpdateWrapper<LifeUserOrder> updateWrapper = new LambdaUpdateWrapper<>();
+                        updateWrapper.eq(LifeUserOrder::getId, order.getId()).set(LifeUserOrder::getStatus, 4).set(LifeUserOrder::getRefundTime, new Date());
+                        lifeUserOrderMapper.update(null, updateWrapper);
+                    }
+                }
+            }
+        }
+    }
+
+
+}

+ 79 - 0
alien-job/src/main/java/shop/alien/job/store/LifeReverseGroupBuyingJob.java

@@ -0,0 +1,79 @@
+package shop.alien.job.store;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.xxl.job.core.handler.annotation.XxlJob;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import shop.alien.entity.store.LifeMessage;
+import shop.alien.entity.store.LifeReverseGroupBuying;
+import shop.alien.entity.store.LifeUser;
+import shop.alien.entity.store.LifeUserOrder;
+import shop.alien.mapper.LifeMessageMapper;
+import shop.alien.mapper.LifeReverseGroupBuyingMapper;
+import shop.alien.mapper.LifeUserMapper;
+import shop.alien.mapper.LifeUserOrderMapper;
+import shop.alien.util.common.AlipayTradeRefund;
+import shop.alien.util.common.DateUtils;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 反向团购job
+ *
+ * @author ssk
+ * @version 1.0
+ * @date 2025/8/6 14:21
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class LifeReverseGroupBuyingJob {
+
+    private final LifeUserOrderMapper lifeUserOrderMapper;
+
+    private final AlipayTradeRefund alipayTradeRefund;
+
+    private final LifeReverseGroupBuyingMapper lifeReverseGroupBuyingMapper;
+
+    private final LifeMessageMapper lifeMessageMapper;
+
+    private final LifeUserMapper lifeUserMapper;
+
+    /**
+     * 反向团购订单自动退款
+     */
+    @XxlJob("reverseGroupOrder")
+    public void reverseGroupOrder() {
+        LambdaQueryWrapper<LifeReverseGroupBuying> wrapper = new LambdaQueryWrapper<>();
+        //状态, 0:待审核, 1:未通过, 2:已通过, 3:待接单, 4:未接单(已截止), 5:待使用, 6:已完成, 7:已退款
+        wrapper.eq(LifeReverseGroupBuying::getStatus, 4);
+        List<LifeReverseGroupBuying> list = lifeReverseGroupBuyingMapper.selectList(new LambdaQueryWrapper<>());
+        for (LifeReverseGroupBuying lifeReverseGroupBuying : list) {
+            //竞价结束
+            if (DateUtils.dateCompare(new Date(), lifeReverseGroupBuying.getBiddingEndTime())) {
+                LifeUserOrder lifeUserOrder = lifeUserOrderMapper.selectById(lifeReverseGroupBuying.getOrderId());
+                String s = alipayTradeRefund.processRefund(lifeUserOrder.getOrderNo(), new BigDecimal(lifeReverseGroupBuying.getGroupMoney()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString(), "用户反向团购, 未有商家接单");
+                if (s.contains("成功")) {
+                    //修改状态
+                    lifeReverseGroupBuying.setStatus(7);
+                    lifeReverseGroupBuyingMapper.updateById(lifeReverseGroupBuying);
+                } else {
+                    LifeUser lifeUser = lifeUserMapper.selectById(lifeUserOrder.getUserId());
+                    LifeMessage lifeMessage = new LifeMessage();
+                    lifeMessage.setSenderName("system");
+                    if (lifeUser != null) {
+                        lifeMessage.setReceiverId("user_" + lifeUser.getUserPhone());
+                        lifeMessage.setContent("你有一笔反向团购退款失败, 请联系管理员");
+                        lifeMessage.setType("2");
+                        lifeMessageMapper.insert(lifeMessage);
+                    }
+
+                }
+            }
+        }
+    }
+}

+ 14 - 32
alien-store/src/main/java/shop/alien/store/job/MassageFootBathJob.java → alien-job/src/main/java/shop/alien/job/store/MassageFootBathJob.java

@@ -1,15 +1,15 @@
-package shop.alien.store.job;
+package shop.alien.job.store;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.xxl.job.core.handler.annotation.XxlJob;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
+import shop.alien.config.redis.BaseRedisService;
 import shop.alien.entity.store.EssentialModuleInformation;
 import shop.alien.entity.store.LifeCoupon;
 import shop.alien.entity.store.StoreBusinessInfo;
 import shop.alien.entity.store.StoreLabelType;
-import shop.alien.store.config.BaseRedisService;
 import shop.alien.mapper.EssentialModuleInformationMapper;
 import shop.alien.mapper.LifeCouponMapper;
 import shop.alien.mapper.StoreBusinessInfoMapper;
@@ -49,12 +49,11 @@ public class MassageFootBathJob {
 
     private final StoreLabelTypeMapper storeLabelTypeMapper;
 
-//    @Scheduled(cron = "0 0 0/2 * * ?")
+    @XxlJob("MassageFootBathJob")
     public void MassageFootBathJob() {
 
         // 获取所有足浴按摩筛选
-        List<EssentialModuleInformation> essentialModuleInformations = informationMapper.selectList(
-                new LambdaQueryWrapper<EssentialModuleInformation>().eq(EssentialModuleInformation::getParentId, 1360));
+        List<EssentialModuleInformation> essentialModuleInformations = informationMapper.selectList(new LambdaQueryWrapper<EssentialModuleInformation>().eq(EssentialModuleInformation::getParentId, 1360));
 
         // 获取所有商家的营业时间
         List<StoreBusinessInfo> storeBusinessInfos = storeBusinessInfoMapper.selectBusinessInfo("按摩足浴");
@@ -68,8 +67,7 @@ public class MassageFootBathJob {
         for (EssentialModuleInformation essentialModuleInformation : essentialModuleInformations) {
             Integer informationId = essentialModuleInformation.getId();
             // 获取所有数据值
-            List<EssentialModuleInformation> businessHours = informationMapper.selectList(
-                    new LambdaQueryWrapper<EssentialModuleInformation>().eq(EssentialModuleInformation::getParentId, informationId));
+            List<EssentialModuleInformation> businessHours = informationMapper.selectList(new LambdaQueryWrapper<EssentialModuleInformation>().eq(EssentialModuleInformation::getParentId, informationId));
             switch (informationId) {
                 case 1587:
                     for (EssentialModuleInformation businessHour : businessHours) {
@@ -87,23 +85,15 @@ public class MassageFootBathJob {
                                 // 将字符串解析为 LocalTime 对象
                                 LocalTime localTime = LocalTime.parse(time);
                                 // 获取当前在营业的商家
-                                list = storeBusinessInfos.stream()
-                                        .filter(item -> localTime.isBefore(LocalTime.parse(item.getEndTime())))
-                                        .collect(Collectors.toList());
-                                storeIds = list.stream()
-                                        .map(item -> String.valueOf(item.getStoreId()))
-                                        .collect(Collectors.joining(","));
+                                list = storeBusinessInfos.stream().filter(item -> localTime.isBefore(LocalTime.parse(item.getEndTime()))).collect(Collectors.toList());
+                                storeIds = list.stream().map(item -> String.valueOf(item.getStoreId())).collect(Collectors.joining(","));
                                 // 将商家storeId添加到redis中
                                 baseRedisService.setString("1599", storeIds);
                                 break;
                             case 1600: // 24小时营业
-                                list = storeBusinessInfos.stream()
-                                        .filter(item -> ZERO_TIME.equals(item.getStartTime()) && TWENTY_FOUR_TIME.equals(item.getEndTime()))
-                                        .collect(Collectors.toList());
+                                list = storeBusinessInfos.stream().filter(item -> ZERO_TIME.equals(item.getStartTime()) && TWENTY_FOUR_TIME.equals(item.getEndTime())).collect(Collectors.toList());
                                 // 获取过滤后列表中每个对象的 storeId 字段,并用逗号连接成字符串
-                                storeIds = list.stream()
-                                        .map(item -> String.valueOf(item.getStoreId()))
-                                        .collect(Collectors.joining(","));
+                                storeIds = list.stream().map(item -> String.valueOf(item.getStoreId())).collect(Collectors.joining(","));
                                 // 将商家storeId添加到redis中
                                 baseRedisService.setString("1600", storeIds);
                                 break;
@@ -444,13 +434,9 @@ public class MassageFootBathJob {
      * @return
      */
     private String getLifeCoupons(List<LifeCoupon> lifeCoupons, Integer startNum, Integer endNum) {
-        List<LifeCoupon> list = lifeCoupons.stream()
-                .filter(item -> Integer.parseInt(item.getPrice()) >= startNum && Integer.parseInt(item.getPrice()) < endNum)
-                .collect(Collectors.toList());
+        List<LifeCoupon> list = lifeCoupons.stream().filter(item -> Integer.parseInt(item.getPrice()) >= startNum && Integer.parseInt(item.getPrice()) < endNum).collect(Collectors.toList());
         // 获取过滤后列表中每个对象的 storeId 字段,并用逗号连接成字符串
-        return list.stream()
-                .map(item -> String.valueOf(item.getStoreId()))
-                .collect(Collectors.joining(","));
+        return list.stream().map(item -> String.valueOf(item.getStoreId())).collect(Collectors.joining(","));
     }
 
     /**
@@ -461,12 +447,8 @@ public class MassageFootBathJob {
      * @return
      */
     private String getStoreLabelTypes(List<StoreLabelType> storeLabelTypes, String label) {
-        List<StoreLabelType> list = storeLabelTypes.stream()
-                .filter(item -> item.getLabel().contains(label))
-                .collect(Collectors.toList());
+        List<StoreLabelType> list = storeLabelTypes.stream().filter(item -> item.getLabel().contains(label)).collect(Collectors.toList());
         // 获取过滤后列表中每个对象的 storeId 字段,并用逗号连接成字符串
-        return list.stream()
-                .map(item -> String.valueOf(item.getStoreId()))
-                .collect(Collectors.joining(","));
+        return list.stream().map(item -> String.valueOf(item.getStoreId())).collect(Collectors.joining(","));
     }
 }

+ 118 - 0
alien-job/src/main/java/shop/alien/job/store/StoreIncomeDetailsJob.java

@@ -0,0 +1,118 @@
+package shop.alien.job.store;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.xxl.job.core.handler.annotation.XxlJob;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import shop.alien.entity.store.StoreAliPayLog;
+import shop.alien.entity.store.StoreCashOutRecord;
+import shop.alien.entity.store.StoreIncomeDetailsRecord;
+import shop.alien.entity.store.StoreUser;
+import shop.alien.job.feign.AlienStoreFeign;
+import shop.alien.mapper.StoreCashOutRecordMapper;
+import shop.alien.mapper.StoreIncomeDetailsRecordMapper;
+import shop.alien.mapper.StoreUserMapper;
+import shop.alien.util.common.DateUtils;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 我的钱包
+ *
+ * @author ssk
+ * @version 1.0
+ * @date 2025/8/6 14:21
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class StoreIncomeDetailsJob {
+
+    private final StoreIncomeDetailsRecordMapper storeIncomeDetailsRecordMapper;
+
+    private final StoreCashOutRecordMapper storeCashOutRecordService;
+
+    private final StoreUserMapper storeUserService;
+
+    private final AlienStoreFeign alienStoreFeign;
+
+    /**
+     * 我的钱包已到账期自动转账
+     */
+    @XxlJob("autoTransferAccounts")
+    public void autoTransferAccounts() {
+        //获取已到账期
+        LambdaQueryWrapper<StoreIncomeDetailsRecord> wrapper = new LambdaQueryWrapper<>();
+        wrapper.lt(StoreIncomeDetailsRecord::getCreatedTime, DateUtils.calcDays(new Date(), -28)).isNull(StoreIncomeDetailsRecord::getCashOutId);
+        List<StoreIncomeDetailsRecord> list = storeIncomeDetailsRecordMapper.selectList(wrapper);
+        // 根据 storeId 分组
+        Map<Integer, List<StoreIncomeDetailsRecord>> groupedByStoreId = list.stream()
+                .collect(Collectors.groupingBy(StoreIncomeDetailsRecord::getStoreId));
+        //获取账户余额
+        List<Integer> storeIds = new ArrayList<>();
+        Map<Integer, Integer> storeMoney = new HashMap<>();
+        Map<Integer, Integer> storeCommission = new HashMap<>();
+        groupedByStoreId.forEach((storeId, records) -> {
+            storeIds.add(storeId);
+            // 对每个 storeId 对应的 records 进行处理
+            int money = 0;
+            int commission = 0;
+            for (StoreIncomeDetailsRecord record : records) {
+                money += record.getMoney() - record.getCommission();
+                commission += record.getCommission();
+            }
+            storeMoney.put(storeId, money);
+            storeCommission.put(storeId, commission);
+        });
+        List<StoreUser> storeUserList = storeUserService.selectList(new LambdaUpdateWrapper<StoreUser>().in(StoreUser::getStoreId, storeIds));
+        //转账
+        storeMoney.forEach((storeId, money) -> {
+            if (money < 10) {
+                log.info("账户已到账期金额小于最小转账金额, 用户id: {},金额: {}", storeId, money);
+            } else {
+                List<StoreUser> userList = storeUserList.stream()
+                        .filter(storeUser -> storeUser.getStoreId().equals(storeId))
+                        .collect(Collectors.toList());
+                if (!userList.isEmpty()) {
+                    StoreUser filteredUsers = userList.get(0);
+                    JSONObject pay = alienStoreFeign.aliPay(filteredUsers.getName(), filteredUsers.getIdCard(), filteredUsers.getPhone(), new BigDecimal(money).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString());
+                    if (null == pay) {
+                        log.error("支付宝转账失败, 用户: {},金额: {}", filteredUsers.getPhone(), money);
+                    } else {
+                        StoreCashOutRecord storeCashOutRecord = new StoreCashOutRecord();
+                        //转账记录表
+                        StoreAliPayLog storeAliPayLog = JSONObject.parseObject(String.valueOf(pay), StoreAliPayLog.class);
+                        storeCashOutRecord.setStoreId(storeId)
+                                .setMoney(money)
+                                .setCommission(storeCommission.get(storeId))
+                                .setCashOutType(1)
+                                .setOrderNo(storeAliPayLog.getOutBizNo())
+                                .setAliOrderNo(storeAliPayLog.getOrderId())
+                                .setIncomeStartTime(groupedByStoreId.get(storeId).get(0).getCreatedTime())
+                                .setIncomeEndTime(groupedByStoreId.get(storeId).get(groupedByStoreId.get(storeId).size() - 1).getCreatedTime())
+                                .setPaymentDate(new Date());
+                        storeCashOutRecordService.insert(storeCashOutRecord);
+                        list.forEach(record -> {
+                            if (record.getStoreId().equals(storeId)) {
+                                record.setCashOutId(storeCashOutRecord.getId());
+                            }
+                            //增加记录
+                            storeIncomeDetailsRecordMapper.insert(record);
+                        });
+                        //减少金额
+                        filteredUsers.setMoney(filteredUsers.getMoney() - money);
+                        storeUserService.updateById(filteredUsers);
+                    }
+                }
+            }
+        });
+
+    }
+
+}

+ 9 - 10
alien-store/src/main/java/shop/alien/store/job/StoreMembershipCardJob.java → alien-job/src/main/java/shop/alien/job/store/StoreMembershipCardJob.java

@@ -1,14 +1,14 @@
-package shop.alien.store.job;
+package shop.alien.job.store;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.xxl.job.core.handler.annotation.XxlJob;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
+import shop.alien.config.redis.BaseRedisService;
 import shop.alien.entity.store.*;
-import shop.alien.store.config.BaseRedisService;
+import shop.alien.job.feign.AlienStoreFeign;
 import shop.alien.mapper.*;
-import shop.alien.store.service.NearMeService;
 
 import java.util.Calendar;
 import java.util.Date;
@@ -54,15 +54,14 @@ public class StoreMembershipCardJob {
 
     private final LifeUserMapper lifeUserMapper;
 
-    private final NearMeService nearMeService;
-
     private final LifeFansMapper lifeFansMapper;
 
+    private final AlienStoreFeign alienStoreFeign;
+
     /**
      * 会员卡状态及会员卡订单状态变更任务
      */
-//    @Scheduled(cron = "0 0 2 * * ?")
-//    @Scheduled(cron = "0/10 * * * * ?")
+    @XxlJob("storeMembershipCardStatusJob")
     public void storeMembershipCardStatusJob() {
         log.info("会员卡状态及会员卡订单状态变更任务执行: " + new Date());
 
@@ -120,7 +119,7 @@ public class StoreMembershipCardJob {
     /**
      * 定时清理已申请注销超过7天的商家与用户
      */
-//    @Scheduled(cron = "0 0 0 * * ?")
+    @XxlJob("cancellationOfBusinessJob")
     public void cancellationOfBusinessJob() {
         log.info("删除已申请注销超过7天的商家与用户: " + new Date());
 
@@ -140,7 +139,7 @@ public class StoreMembershipCardJob {
                 if (date.compareTo(sevenDay) >= 0) {
                     // 删除已过注销时间的商家
                     storeUserMapper.deleteById(storeUser.getId());
-                    nearMeService.removeGeolocation(Boolean.TRUE, storeUser.getId().toString());
+                    alienStoreFeign.delMer(Boolean.TRUE, storeUser.getId().toString());
                     //删除用户redis中的token
                     baseRedisService.delete("store_" + storeUser.getPhone());
                 }

+ 1 - 0
alien-job/src/main/resources/bootstrap-prod.yml

@@ -9,6 +9,7 @@ spring:
         server-addr: localhost:8848
         username: nacos
         password: ngfriend198092
+        namespace: 3cbb802a-b56e-47f7-b658-b5012ecafb1f
 
       #配置中心
       config:

+ 1 - 0
alien-job/src/main/resources/bootstrap-test.yml

@@ -9,6 +9,7 @@ spring:
         server-addr: 192.168.2.252:8848
         username: nacos
         password: ngfriend198092
+        namespace: 0e1e2d77-56e8-422c-8317-6f71d7285e59
 
       #配置中心
       config:

+ 1 - 1
alien-job/src/main/resources/logback-spring.xml

@@ -12,7 +12,7 @@
     <!-- 定义全局参数常量 -->
     <property name="log.level" value="debug"/>
     <property name="log.maxHistory" value="30"/><!-- 30表示30个 -->
-    <property name="logging.path" value="/javaLog/alienJobLog"/>
+    <springProperty scope="context" name="logging.path" source="logging.path"/>
     <!--输出文件前缀-->
     <property name="FILENAME" value="alien"/>
 

+ 2 - 0
alien-second/src/main/java/shop/alien/second/AlienSecondApplication.java

@@ -6,6 +6,7 @@ import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.cloud.openfeign.EnableFeignClients;
 import org.springframework.context.annotation.ComponentScan;
+import org.springframework.scheduling.annotation.EnableScheduling;
 
 //@ComponentScan("shop.alien.second.*")
 @EnableFeignClients(basePackages = {"shop.alien.second.feign"})
@@ -21,6 +22,7 @@ import org.springframework.context.annotation.ComponentScan;
         "shop.alien.mapper.second"})
 @EnableSwaggerBootstrapUI
 @SpringBootApplication
+@EnableScheduling
 public class AlienSecondApplication {
 
     public static void main(String[] args) {

+ 56 - 8
alien-second/src/main/java/shop/alien/second/controller/SecondGoodsController.java

@@ -2,19 +2,18 @@ package shop.alien.second.controller;
 
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.google.common.collect.Lists;
 import io.swagger.annotations.*;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.bind.annotation.*;
+import shop.alien.entity.SecondVideoTask;
 import shop.alien.entity.result.R;
 import shop.alien.entity.second.SecondGoods;
-import shop.alien.entity.second.SecondGoodsAudit;
 import shop.alien.entity.second.vo.SecondGoodsVo;
 import shop.alien.mapper.second.SecondGoodsAuditMapper;
 import shop.alien.second.service.SecondGoodsService;
+import shop.alien.second.service.VideoModerationService;
 import shop.alien.util.common.JwtUtil;
 import shop.alien.config.filter.NoRepeatSubmit;
 import shop.alien.util.common.safe.ImageModerationUtil;
@@ -23,7 +22,6 @@ import shop.alien.util.common.safe.TextModerationUtil;
 import shop.alien.util.common.safe.TextReviewServiceEnum;
 import shop.alien.util.common.safe.*;
 
-import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -38,8 +36,18 @@ import java.util.List;
 @RequiredArgsConstructor
 public class SecondGoodsController {
 
+    /**
+     * 视频审核服务
+     */
+    private final VideoModerationService videoModerationService;
+    /**
+     * 二手商品服务
+     */
     private final SecondGoodsService secondGoodsService;
 
+    /**
+     * 二手商品审核表
+     */
     private final SecondGoodsAuditMapper secondGoodsAuditMapper;
 
     // 注入文本审核工具
@@ -111,8 +119,15 @@ public class SecondGoodsController {
         log.info("SecondGoodsController.shelveSecondGoods?secondGoods={}", secondGoods.toString());
         // 修改商品状态为4 - 已下架
         secondGoods.setGoodsStatus(4);
-        secondGoodsService.updateById(secondGoods);
-        return R.success("上架成功");
+        boolean updateResult = secondGoodsService.updateById(secondGoods);
+        if (updateResult) {
+            // 获取最新的商品信息并记录操作历史
+            SecondGoods updatedGoods = secondGoodsService.getById(secondGoods.getId());
+            secondGoodsService.recordGoodsOperation(updatedGoods);
+            return R.success("下架成功");
+        } else {
+            return R.fail("下架失败");
+        }
     }
 
     /**
@@ -123,8 +138,20 @@ public class SecondGoodsController {
     @NoRepeatSubmit(expireTime = 3, message = "请勿重复提交删除商品请求")
     public R<Void> deleteSecondGoods(@ApiParam("删除二手商品") @RequestBody SecondGoodsVo secondGoods) {
         log.info("SecondGoodsController.deleteSecondGoods?secondGoods={}", secondGoods.toString());
-        secondGoodsService.removeById(secondGoods.getId());
-        return R.success("删除成功");
+        SecondGoods goods = secondGoodsService.getById(secondGoods.getId());
+        if (goods != null) {
+            boolean removeResult = secondGoodsService.removeById(secondGoods.getId());
+            if (removeResult) {
+                // 设置删除标记并记录操作历史
+                goods.setDeleteFlag(1);
+                secondGoodsService.recordGoodsOperation(goods);
+                return R.success("删除成功");
+            } else {
+                return R.fail("删除失败");
+            }
+        } else {
+            return R.fail("商品不存在");
+        }
     }
 
     /**
@@ -241,4 +268,25 @@ public class SecondGoodsController {
             return R.fail("图片审核异常: " + e.getMessage());
         }
     }
+
+    /**
+     * 处理视频审核结果
+     * @param taskId 视频审核任务ID
+     * @return 处理结果
+     */
+    @ApiOperation("处理视频审核结果")
+    @GetMapping("/processVideoResult")
+    public boolean processVideoResult(String taskId) {
+        try {
+            SecondVideoTask task = videoModerationService.getTaskByTaskId(taskId);
+            if (task == null) {
+                return false;
+            }
+            secondGoodsService.processVideoModerationResult(task);
+            return true;
+        } catch (Exception e) {
+            log.error("处理视频审核结果时发生异常,任务ID: {}", taskId, e);
+            return false;
+        }
+    }
 }

+ 20 - 7
alien-second/src/main/java/shop/alien/second/controller/SecondTradeRecordController.java

@@ -1,11 +1,12 @@
 package shop.alien.second.controller;
 
 
-import feign.Param;
+import com.alipay.api.kms.aliyun.utils.BackoffUtils;
 import io.swagger.annotations.*;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.bind.annotation.*;
+import shop.alien.entity.result.BusinessException;
 import shop.alien.entity.result.R;
 import shop.alien.entity.second.SecondTradeRecord;
 import shop.alien.entity.second.vo.SecondTradeRecordVo;
@@ -57,10 +58,16 @@ public class SecondTradeRecordController {
             @ApiImplicitParam(name = "messageId", value = "消息id", dataType = "Integer", paramType = "query", required = true),
             @ApiImplicitParam(name = "type", value = "0-拒绝  1-确认", dataType = "Integer", paramType = "query", required = true)})
     @GetMapping("/tradeConfirm")
-    public R<Boolean> tradeConfirm(@RequestParam int tradeId, @RequestParam int messageId, @RequestParam int type) throws Exception {
+    public R<Boolean> tradeConfirm(@RequestParam int tradeId, @RequestParam int messageId, @RequestParam int type) {
         log.info("SecondTradeRecordController.tradeConfirm?tradeId={}, messageId={}, type={}", tradeId, messageId, type);
-        if (secondTradeRecordService.tradeConfirm(tradeId, messageId, type)) return R.success("操作成功");
-        return R.fail("操作失败");
+        try {
+            secondTradeRecordService.tradeConfirm(tradeId, messageId, type);
+            return R.success("操作成功");
+        } catch (BusinessException e) {
+            return R.fail(e.getCause().getMessage());
+        }  catch (Exception e) {
+            return R.fail("系统繁忙,请稍后再试");
+        }
     }
 
     @ApiOperation("取消交易")
@@ -93,10 +100,16 @@ public class SecondTradeRecordController {
             @ApiImplicitParam(name = "signInLatitudeLongitude", value = "签到地点(经纬度)", dataType = "String", paramType = "query", required = true),
             @ApiImplicitParam(name = "signInLatitudeLongitudeAddress", value = "签到地点(经纬度地址)", dataType = "String", paramType = "query", required = true)})
     @GetMapping("/tradeSignIn")
-    public R<Boolean> tradeSignIn(@RequestParam int tradeId, int messageId, String signInLatitudeLongitude, String signInLatitudeLongitudeAddress) throws Exception {
+    public R<Boolean> tradeSignIn(@RequestParam int tradeId, int messageId, String signInLatitudeLongitude, String signInLatitudeLongitudeAddress) {
         log.info("SecondTradeRecordController.tradeSignIn?tradeId={}, messageId={}", tradeId, messageId);
-        if (secondTradeRecordService.tradeSignIn(tradeId, messageId, signInLatitudeLongitude, signInLatitudeLongitudeAddress)) return R.success("签到成功");
-        return R.fail("签到失败");
+        try {
+            secondTradeRecordService.tradeSignIn(tradeId, messageId, signInLatitudeLongitude, signInLatitudeLongitudeAddress);
+            return R.success("签到成功");
+        } catch (BusinessException e) {
+            return R.fail(e.getCause().getMessage());
+        }  catch (Exception e) {
+            return R.fail("系统繁忙,请稍后再试");
+        }
     }
 
     @ApiOperation("交易完成确认")

+ 77 - 0
alien-second/src/main/java/shop/alien/second/controller/VideoModerationController.java

@@ -0,0 +1,77 @@
+package shop.alien.second.controller;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+import shop.alien.entity.SecondVideoTask;
+import shop.alien.second.service.VideoModerationService;
+
+/**
+ * 视频审核控制器示例
+ */
+@Slf4j
+@RestController
+@RequestMapping("/video/moderation")
+@RequiredArgsConstructor
+public class VideoModerationController {
+    
+    private final VideoModerationService videoModerationService;
+    
+    /**
+     * 提交视频审核任务
+     * 
+     * @param videoUrl 视频URL
+     * @return 任务ID
+     */
+    @PostMapping("/submit")
+    public String submitVideoModerationTask(@RequestParam String videoUrl) {
+        try {
+            String taskId = videoModerationService.submitVideoModerationTask(videoUrl);
+            return "任务提交成功,任务ID: " + taskId;
+        } catch (Exception e) {
+            log.error("提交视频审核任务失败", e);
+            return "任务提交失败: " + e.getMessage();
+        }
+    }
+    
+    /**
+     * 查询视频审核结果
+     * 
+     * @param taskId 任务ID
+     * @return 审核结果
+     */
+    @GetMapping("/result")
+    public Object getVideoModerationResult(@RequestParam String taskId) {
+        try {
+            return videoModerationService.queryVideoModerationResult(taskId);
+        } catch (Exception e) {
+            log.error("查询视频审核结果失败", e);
+            return "查询失败: " + e.getMessage();
+        }
+    }
+
+
+    /**
+     * 处理单个视频审核任务
+     *
+     * @param taskId 任务ID
+     * @return 处理结果
+     */
+    @GetMapping("/processTask")
+    public boolean processTask(@RequestParam("taskId") String taskId) {
+        try {
+            // 根据任务ID查询任务详情
+            SecondVideoTask task = videoModerationService.getTaskByTaskId(taskId);
+            if (task == null) {
+                log.error("未找到任务ID为 {} 的视频审核任务", taskId);
+                return false;
+            }
+
+            // 处理任务
+            return videoModerationService.processTask(task);
+        } catch (Exception e) {
+            log.error("处理视频审核任务时发生异常,任务ID: {}", taskId, e);
+            return false;
+        }
+    }
+}

+ 1 - 1
alien-second/src/main/java/shop/alien/second/feign/AlienStoreFeign.java

@@ -5,7 +5,7 @@ import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 
-@FeignClient(url = "http://localhost:8888", name = "alien-store")
+@FeignClient(url = "${feign.alienStore.url}", name = "alien-store")
 public interface AlienStoreFeign {
 
     @GetMapping("/message/getMessageList")

+ 15 - 2
alien-second/src/main/java/shop/alien/second/service/SecondGoodsService.java

@@ -1,10 +1,11 @@
 package shop.alien.second.service;
 
-import com.baomidou.mybatisplus.extension.service.IService;
 import com.baomidou.mybatisplus.core.metadata.IPage;
-import io.swagger.models.auth.In;
+import com.baomidou.mybatisplus.extension.service.IService;
 import org.springframework.transaction.annotation.Transactional;
+import shop.alien.entity.SecondVideoTask;
 import shop.alien.entity.second.SecondGoods;
+import shop.alien.entity.second.SecondGoodsRecord;
 import shop.alien.entity.second.vo.SecondGoodsVo;
 import shop.alien.entity.second.vo.SellGoodsVo;
 
@@ -149,4 +150,16 @@ public interface SecondGoodsService extends IService<SecondGoods> {
     IPage<SellGoodsVo> getTransactionList(IPage<SellGoodsVo> page, Integer userId);
 
     List<SecondGoods> getGoodsListByUserId(Integer userId, Integer goodsStatus);
+
+    /**
+     * 处理视频审核结果
+     * @param task 视频审核任务
+     */
+    void processVideoModerationResult(SecondVideoTask task);
+    
+    /**
+     * 记录商品操作历史
+     * @param goods 商品信息
+     */
+    void recordGoodsOperation(SecondGoods goods);
 }

+ 3 - 3
alien-second/src/main/java/shop/alien/second/service/SecondTradeRecordService.java

@@ -2,7 +2,7 @@ package shop.alien.second.service;
 
 
 import com.baomidou.mybatisplus.extension.service.IService;
-import io.swagger.models.auth.In;
+import shop.alien.entity.result.BusinessException;
 import shop.alien.entity.second.SecondTradeRecord;
 import shop.alien.entity.second.vo.SecondTradeRecordVo;
 
@@ -21,13 +21,13 @@ public interface SecondTradeRecordService extends IService<SecondTradeRecord> {
 
     boolean goodsTradeConfirm(int goodsId) throws Exception;
 
-    boolean tradeConfirm(int tradeId, int messageId, int type) throws Exception;
+    boolean tradeConfirm(int tradeId, int messageId, int type) throws BusinessException, Exception;
 
     boolean cancelTrade(int tradeId, String cancelReason, String cancelReasonSupplement) throws Exception;
 
     boolean whetherCanSignIn(int tradeId) throws Exception;
 
-    boolean tradeSignIn(int tradeId, int messageId, String signInLatitudeLongitude, String signInLatitudeLongitudeAddress) throws Exception;
+    boolean tradeSignIn(int tradeId, int messageId, String signInLatitudeLongitude, String signInLatitudeLongitudeAddress) throws BusinessException, Exception;
 
     SecondTradeRecordVo getUserTradeStatus(int tradeId) throws Exception;
 

+ 35 - 0
alien-second/src/main/java/shop/alien/second/service/VideoModerationService.java

@@ -0,0 +1,35 @@
+package shop.alien.second.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import shop.alien.entity.SecondVideoTask;
+
+public interface VideoModerationService  extends IService<SecondVideoTask> {
+    /**
+     * 提交视频审核任务
+     *
+     * @param videoUrl 视频URL
+     * @return 任务ID
+     */
+    String submitVideoModerationTask(String videoUrl);
+    /**
+     * 查询视频审核结果
+     *
+     * @param taskId 任务ID
+     * @return 审核结果
+     */
+    SecondVideoTask queryVideoModerationResult(String taskId);
+    /**
+     * 处理视频审核结果
+     *
+     * @param task 视频审核任务
+     * @return 是否处理成功
+     */
+    boolean processTask(SecondVideoTask task);
+    /**
+     * 根据任务ID获取视频审核任务
+     *
+     * @param taskId 任务ID
+     * @return 视频审核任务
+     */
+    SecondVideoTask getTaskByTaskId(String taskId);
+}

+ 28 - 10
alien-second/src/main/java/shop/alien/second/service/impl/SecondGoodsReportingServiceImpl.java

@@ -97,19 +97,37 @@ public class SecondGoodsReportingServiceImpl implements SecondGoodsReportingServ
         secondReportingVo.setReportingTime(lifeNotice.getCreatedTime());
         secondReportingVo.setFeedbackTime(lifeNotice.getCreatedTime());
         List<Map<String, Object>> list = new ArrayList<>();
-        for (String row : lifeUserViolation.getReportEvidenceImg().split(",")) {
+        List<String> urlList = Arrays.asList(lifeUserViolation.getReportEvidenceImg().split(","));
+        // 存放已存在文件list
+        List<String> videoList = new ArrayList<>();
+
+        for (int i = 0; i < urlList.size(); i++) {
             Map<String, Object> map = new HashMap<>();
-            String fileType = row.substring(row.lastIndexOf(".") + 1);
-            if (videoFileType.contains(fileType.toLowerCase())) {
-                map.put("type", "video");
-                map.put("imgUrl", row);
-                map.put("videoUrl", row);
-            } else {
-                map.put("type", "image");
-                map.put("imgUrl", row);
+
+            // 查找最后一个点的位置
+            int lastDotIndex = urlList.get(i).lastIndexOf('.');
+
+            String fileType = urlList.get(i).substring(urlList.get(i).lastIndexOf(".") + 1);;
+            String contains = null;
+            if (lastDotIndex != -1) { // 确保存在
+                contains = urlList.get(i).substring(0, lastDotIndex);
             }
-            list.add(map);
+
+            if (!videoList.contains(contains)){
+                videoList.add(contains);
+                if (videoFileType.contains(fileType.toLowerCase())) {
+                    map.put("type", "video");
+                    map.put("imgUrl", urlList.get(i + 1));
+                    map.put("videoUrl", urlList.get(i));
+                } else {
+                    map.put("type", "image");
+                    map.put("imgUrl", urlList.get(i));
+                }
+                list.add(map);
+            }
+
         }
+
         secondReportingVo.setImgList(list);
         secondReportingVo.setReportContextType(lifeUserViolation.getReportContextType());
         secondReportingVo.setId(id);

+ 280 - 18
alien-second/src/main/java/shop/alien/second/service/impl/SecondGoodsServiceImpl.java

@@ -1,7 +1,10 @@
 package shop.alien.second.service.impl;
 
 import cn.hutool.core.collection.CollectionUtil;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONArray;
 import com.alibaba.fastjson2.JSONObject;
+import com.alibaba.nacos.api.config.annotation.NacosValue;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@@ -10,11 +13,16 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.google.common.collect.Lists;
 import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
 import org.springframework.stereotype.Service;
 import org.springframework.util.StringUtils;
+import shop.alien.entity.SecondVideoTask;
 import shop.alien.entity.second.SecondGoods;
 import shop.alien.entity.second.SecondGoodsAudit;
+import shop.alien.entity.second.SecondGoodsRecord;
 import shop.alien.entity.second.enums.SecondGoodsStatusEnum;
 import shop.alien.entity.second.vo.SecondGoodsVo;
 import shop.alien.entity.second.vo.SellGoodsVo;
@@ -24,12 +32,16 @@ import shop.alien.entity.store.vo.WebSocketVo;
 import shop.alien.mapper.*;
 import shop.alien.mapper.second.SecondGoodsAuditMapper;
 import shop.alien.mapper.second.SecondGoodsMapper;
+import shop.alien.mapper.second.SecondGoodsRecordMapper;
 import shop.alien.second.feign.AlienStoreFeign;
 import shop.alien.second.service.SecondGoodsService;
+import shop.alien.second.service.VideoModerationService;
 import shop.alien.util.common.Constants;
 import shop.alien.util.common.VideoUtils;
 import shop.alien.util.common.safe.*;
 
+import java.math.BigDecimal;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
 import java.util.List;
@@ -39,10 +51,26 @@ import java.util.stream.Collectors;
 /**
  * 二手商品服务实现类
  */
+@Slf4j
 @Service
 @RequiredArgsConstructor
 public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, SecondGoods> implements SecondGoodsService {
 
+
+    @Value("${video.moderation.enabled}")
+    private boolean videoModerationEnabled;
+    
+    @Value("${video.moderation.block-on-failure}")
+    private boolean videoModerationBlockOnFailure;
+
+    /**
+     * 视频审核服务
+     */
+    private final VideoModerationService videoModerationService;
+
+    /**
+     * 视频工具类
+     */
     private final VideoUtils videoUtils;
 
     /**
@@ -97,19 +125,77 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
 
     private final AlienStoreFeign alienStoreFeign;
     /**
+     * 商品操作历史记录Mapper
+     */
+    private final SecondGoodsRecordMapper secondGoodsRecordMapper;
+
+    /**
+     * 记录商品操作历史
+     * @param goods 商品信息
+     */
+    @Override
+    public void recordGoodsOperation(SecondGoods goods) {
+        try {
+            SecondGoodsRecord record = new SecondGoodsRecord();
+            record.setGoodsId(goods.getId());
+            record.setTitle(goods.getTitle());
+            record.setDescription(goods.getDescription());
+            // 价格转换
+            if (goods.getAmount() != null) {
+                record.setPrice(goods.getAmount());
+            } else if (goods.getPrice() != null && !goods.getPrice().isEmpty()) {
+                try {
+                    record.setPrice(new BigDecimal(goods.getPrice()));
+                } catch (Exception e) {
+                    log.warn("转换商品价格时出错: {}", e.getMessage());
+                }
+            }
+            record.setPosition(goods.getPosition());
+            record.setLikeCount(goods.getLikeCount());
+            record.setCollectCount(goods.getCollectCount());
+            record.setCategoryOneId(goods.getCategoryOneId());
+            record.setCategoryTwoId(goods.getCategoryTwoId());
+            record.setLabel(goods.getLabel());
+            record.setTopic(goods.getTopic());
+            record.setTradeId(goods.getTradeId());
+            record.setReleaseTime(goods.getReleaseTime());
+            record.setGoodsStatus(goods.getGoodsStatus());
+            record.setFailedReason(goods.getFailedReason());
+            record.setHomeImage(goods.getHomeImage());
+            record.setVideoTaskId(goods.getVideoTaskId());
+            record.setVideoFirstFrame(goods.getVideoFirstFrame());
+            record.setDeleteFlag(goods.getDeleteFlag());
+            record.setCreatedTime(goods.getCreatedTime());
+            record.setCreatedUserId(goods.getCreatedUserId());
+            record.setUpdatedTime(goods.getUpdatedTime());
+            record.setUpdatedUserId(goods.getUpdatedUserId());
+            record.setAddressText(goods.getAddressText());
+            
+            secondGoodsRecordMapper.insert(record);
+        } catch (Exception e) {
+            log.error("记录商品操作历史时发生异常", e);
+        }
+    }
+    
+    /**
      * 保存商品为草稿状态
      * @param goods 商品实体
      * @return 是否成功保存
      */
     @Override
     public boolean saveAsDraft(SecondGoodsVo goods) {
-        SecondGoods secondGoods = new SecondGoods();
-        BeanUtils.copyProperties(goods, secondGoods);
         // 设置商品状态为草稿
         goods.setGoodsStatus(SecondGoodsStatusEnum.DRAFT.getCode());
-        // 保存商品基本信息
-        if (!save(goods)) {
-            return false; // 保存失败直接返回
+        if (null != goods.getId()){
+            // 更新商品基本信息
+            if (!updateById(goods)) {
+                return false; // 保存失败直接返回
+            }
+        }else {
+            // 保存商品基本信息
+            if (!save(goods)) {
+                return false; // 保存失败直接返回
+            }
         }
         // 获取保存后的商品ID,用于后续业务处理
         Integer savedGoodsId = goods.getId();
@@ -128,18 +214,19 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
             SecondGoods goods = new SecondGoods();
             BeanUtils.copyProperties(goodsDTO, goods);
 
+            boolean saveResult;
             if (editFlag == 1) {
                 goods.setId(goodsDTO.getId());
-                goods = secondGoodsMapper.selectById(goodsDTO.getId());
+//                goods = secondGoodsMapper.selectById(goodsDTO.getId());
                 // 保存商品基本信息
-                if (!updateById(goods)) {
-                    return false; // 保存失败直接返回
-                }
+                saveResult = updateById(goods);
             } else {
                 // 保存商品基本信息
-                if (!save(goods)) {
-                    return false; // 保存失败直接返回
-                }
+                saveResult = save(goods);
+            }
+            
+            if (!saveResult) {
+                return false; // 保存失败直接返回
             }
 
             // 获取保存后的商品ID,用于后续业务处理
@@ -155,12 +242,11 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
             goods = secondGoodsMapper.selectById(savedGoodsId);
             // 执行内容审核(图片和文本)
             if (!performContentReviews(goods, goodsDTO)) {
+                // 审核不通过,记录操作历史
+                recordGoodsOperation(goods);
                 return true; // 审核不通过时已设置状态,返回成功但标记为审核失败
             }
 
-
-
-
             return true;
         } catch (Exception e) {
             // 记录异常日志
@@ -169,7 +255,7 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
         }
     }
     /**
-     * 执行内容审核(图片和文本
+     * 执行内容审核(图片、文本和视频
      * @param goods 商品信息
      * @param goodsDTO 商品DTO信息
      * @return 审核结果
@@ -179,7 +265,8 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
         servicesList.add(TextReviewServiceEnum.AD_COMPLIANCE_DETECTION_PRO.getService());
         servicesList.add(TextReviewServiceEnum.LLM_QUERY_MODERATION.getService());
         // 使用商品发布场景的审核服务
-        TextModerationResultVO textCheckResult = textModerationUtil.invokeFunction(goodsDTO.getDescription(), servicesList);
+        String test = goodsDTO.getDescription() + goodsDTO.getTitle() + goods.getLabel() + goods.getTopic();
+        TextModerationResultVO textCheckResult = textModerationUtil.invokeFunction(test, servicesList);
         
         if ("high".equals(textCheckResult.getRiskLevel())) {
             // 文本审核不通过或存在高风险
@@ -204,9 +291,10 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
                 // TODO 后续配置到数据库 中
                 imgServicesList.add(ImageReviewServiceEnum.TONALITY_IMPROVE.getService());
                 imgServicesList.add(ImageReviewServiceEnum.AIGC_CHECK.getService());
+//                imgServicesList.add(ImageReviewServiceEnum.IMG_QUERY_SECURITY_CHECK.getService());
                 ImageModerationResultVO response = imageModerationUtil.productPublishCheck(imageUrl,imgServicesList);
                 if ("high".equals(response.getRiskLevel())) {
-                    // 文本审核不通过或存在高风险
+                    // 图片审核不通过或存在高风险
                     goods.setGoodsStatus(SecondGoodsStatusEnum.REVIEW_FAILED.getCode()); // 审核失败
                     goods.setFailedReason("图片审核不通过:图片中包含" + (response.getDescriptions() != null ? response.getDescriptions() : "高风险内容"));
                     // 插入审核记录
@@ -217,6 +305,43 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
                 }
             }
         }
+        
+        // 视频审核
+        if (videoModerationEnabled) {
+            List<String> videoUrls = extractVideoUrls(goodsDTO.getImgUrl());
+            if (!videoUrls.isEmpty()) {
+                // 提交视频审核任务
+                List<String> taskIds = new ArrayList<>();
+                for (String videoUrl : videoUrls) {
+                    try {
+                        String taskId = videoModerationService.submitVideoModerationTask(videoUrl);
+                        taskIds.add(taskId);
+                    } catch (Exception e) {
+                        log.error("提交视频审核任务失败,视频URL: {}", videoUrl, e);
+                        if (videoModerationBlockOnFailure) {
+                            // 视频审核提交失败,设置为审核失败状态
+                            goods.setGoodsStatus(SecondGoodsStatusEnum.REVIEW_FAILED.getCode());
+                            goods.setFailedReason("视频审核提交失败: " + e.getMessage());
+                            createGoodsAudit(goods, "视频审核提交失败", Constants.AuditStatus.FAILED);
+                            sendFailedMsg(goods);
+                            return false;
+                        }
+                    }
+                }
+                
+                // 如果成功提交了视频审核任务,设置商品状态为审核中
+                if (!taskIds.isEmpty()) {
+                    goods.setGoodsStatus(SecondGoodsStatusEnum.UNDER_REVIEW.getCode()); // 审核中
+                    goods.setVideoTaskId(taskIds.get(0)); // 保存第一个任务ID到商品表
+                    goods.setFailedReason("");
+                    updateById(goods);
+                    createGoodsAudit(goods, "", SecondGoodsStatusEnum.UNDER_REVIEW.getCode());
+                    // 审核中,记录操作历史
+                    recordGoodsOperation(goods);
+                    return true; // 异步处理,直接返回
+                }
+            }
+        }
 
         // 如果所有审核都通过,设置为上架状态
         goods.setGoodsStatus(SecondGoodsStatusEnum.LISTED.getCode()); // 上架
@@ -227,8 +352,29 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
         createGoodsAudit(goods, "", Constants.AuditStatus.PASSED);
         // 发送审核成功消息
         sendMessage(goods);
+        // 审核成功,记录操作历史
+        recordGoodsOperation(goods);
         return true;
     }
+    
+    /**
+     * 从图片URL列表中提取视频URL
+     * @param imageUrls 图片URL列表
+     * @return 视频URL列表
+     */
+    private List<String> extractVideoUrls(List<String> imageUrls) {
+        if (CollectionUtil.isEmpty(imageUrls)) {
+            return Collections.emptyList();
+        }
+        
+        List<String> videoUrls = new ArrayList<>();
+        for (String url : imageUrls) {
+            if (isVideoUrl(url)) {
+                videoUrls.add(url);
+            }
+        }
+        return videoUrls;
+    }
 
     /**
      * 创建商品审核记录
@@ -740,6 +886,121 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
     }
 
     /**
+     * 处理视频审核结果
+     * @param task 视频审核任务
+     */
+    @Override
+    public void processVideoModerationResult(SecondVideoTask task) {
+        try {
+            // 查找关联的商品
+            QueryWrapper<SecondGoods> queryWrapper = new QueryWrapper<>();
+            queryWrapper.eq("video_task_id", task.getTaskId());
+            SecondGoods goods = getOne(queryWrapper);
+            
+            if (goods == null) {
+                log.warn("未找到关联的商品,任务ID: {}", task.getTaskId());
+                return;
+            }
+            
+            // 根据审核结果更新商品状态
+            if ("none".equals(task.getRiskLevel())) {
+                // 审核通过
+                goods.setGoodsStatus(SecondGoodsStatusEnum.LISTED.getCode());
+                goods.setFailedReason("");
+                goods.setReleaseTime(new Date());
+                updateById(goods);
+                
+                // 更新审核记录
+                createGoodsAudit(goods, "", Constants.AuditStatus.PASSED);
+                
+                // 发送审核成功消息
+                sendMessage(goods);
+            } else {
+                // 审核不通过
+                goods.setGoodsStatus(SecondGoodsStatusEnum.REVIEW_FAILED.getCode());
+                
+                // 解析审核结果,生成具体的失败原因
+                String failedReason = parseVideoModerationFailureReason(task);
+                goods.setFailedReason(failedReason);
+                updateById(goods);
+                
+                // 更新审核记录
+                createGoodsAudit(goods, failedReason, Constants.AuditStatus.FAILED);
+                
+                // 发送审核失败消息
+                sendFailedMsg(goods);
+            }
+        } catch (Exception e) {
+            log.error("处理视频审核结果时发生异常,任务ID: {}", task.getTaskId(), e);
+        }
+    }
+    
+    /**
+     * 解析视频审核失败原因
+     * @param task 视频审核任务
+     * @return 失败原因
+     */
+    private String parseVideoModerationFailureReason(SecondVideoTask task) {
+        StringBuilder reasonBuilder = new StringBuilder("视频审核不通过,风险等级: " + task.getRiskLevel());
+        
+        try {
+            // 解析审核结果JSON
+            JSONObject resultJson = JSON.parseObject(task.getResult());
+            if (resultJson != null && resultJson.containsKey("data")) {
+                JSONObject data = resultJson.getJSONObject("data");
+                
+                // 处理帧结果(视频画面)
+                if (data.containsKey("FrameResult")) {
+                    JSONObject frameResult = data.getJSONObject("FrameResult");
+                    if (frameResult != null && frameResult.containsKey("FrameSummarys")) {
+                        JSONArray frameSummarys = frameResult.getJSONArray("FrameSummarys");
+                        if (frameSummarys != null && !frameSummarys.isEmpty()) {
+                            reasonBuilder.append("。检测到违规内容:");
+                            for (int i = 0; i < frameSummarys.size(); i++) {
+                                JSONObject summary = frameSummarys.getJSONObject(i);
+                                String label = summary.getString("Label");
+                                String description = summary.getString("Description");
+                                Integer labelSum = summary.getInteger("LabelSum");
+                                
+                                if (label != null && !label.isEmpty()) {
+                                    reasonBuilder.append("[").append(description != null ? description : label)
+                                            .append("]出现").append(labelSum != null ? labelSum : 1).append("次;");
+                                }
+                            }
+                        }
+                    }
+                }
+                
+                // 处理音频结果
+                if (data.containsKey("AudioResult")) {
+                    JSONObject audioResult = data.getJSONObject("AudioResult");
+                    if (audioResult != null && audioResult.containsKey("AudioSummarys")) {
+                        JSONArray audioSummarys = audioResult.getJSONArray("AudioSummarys");
+                        if (audioSummarys != null && !audioSummarys.isEmpty()) {
+                            reasonBuilder.append("。检测到违规音频:");
+                            for (int i = 0; i < audioSummarys.size(); i++) {
+                                JSONObject summary = audioSummarys.getJSONObject(i);
+                                String label = summary.getString("Label");
+                                String description = summary.getString("Description");
+                                Integer labelSum = summary.getInteger("LabelSum");
+                                
+                                if (label != null && !label.isEmpty()) {
+                                    reasonBuilder.append("[").append(description != null ? description : label)
+                                            .append("]出现").append(labelSum != null ? labelSum : 1).append("次;");
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            log.warn("解析视频审核结果失败,使用默认原因,任务ID: {}", task.getTaskId(), e);
+        }
+        
+        return reasonBuilder.toString();
+    }
+
+    /**
      * 查询搜索结果
      * @param page 分页参数
      * @param secondGoodsVo 查询参数
@@ -891,4 +1152,5 @@ public class SecondGoodsServiceImpl extends ServiceImpl<SecondGoodsMapper, Secon
             }
         }
     }
+
 }

+ 3 - 1
alien-second/src/main/java/shop/alien/second/service/impl/SecondRecommendServiceImpl.java

@@ -86,13 +86,15 @@ public class SecondRecommendServiceImpl extends ServiceImpl<SecondRecommendMappe
         try {
             JSONObject data = JwtUtil.getCurrentUserInfo();
             String phoneId = null;
+            Integer userId = null;
             if (data != null) {
                 phoneId = data.getString("phone");
+                userId = data.getInteger("userId");
             }
             if (StringUtil.isBlank(phoneId)) {
                 return null;
             }
-            IPage<SecondGoodsRecommendVo> list = mapper.querySecondConcernByPage(page, "user_" + phoneId, position);
+            IPage<SecondGoodsRecommendVo> list = mapper.querySecondConcernByPage(page, userId, "user_" + phoneId, position);
             List<Integer> idList = list.getRecords().stream() // 创建流
                     .map(obj -> obj.getId())   // 提取每个元素的 ID
                     .collect(Collectors.toList());

+ 43 - 28
alien-second/src/main/java/shop/alien/second/service/impl/SecondTradeRecordServiceImpl.java

@@ -8,6 +8,7 @@ import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import shop.alien.entity.result.BusinessException;
 import shop.alien.entity.second.SecondGoods;
 import shop.alien.entity.second.SecondTradeRecord;
 import shop.alien.entity.second.vo.SecondTradeRecordVo;
@@ -24,6 +25,7 @@ import shop.alien.second.feign.AlienStoreFeign;
 import shop.alien.second.service.SecondTradeRecordService;
 import shop.alien.util.common.JwtUtil;
 
+import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
 import java.util.Date;
@@ -50,10 +52,20 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
     private final AlienStoreFeign alienStoreFeign;
     private final StoreDictionaryMapper storeDictionaryMapper;
 
+    private final Object lock = new Object();
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public boolean createTrade(SecondTradeRecord trade) throws Exception {
         try {
+            synchronized (lock) {
+                LocalDate now = LocalDate.now();
+                LambdaQueryWrapper<SecondTradeRecord> wrapper = new LambdaQueryWrapper<>();
+                wrapper.between(SecondTradeRecord::getCreatedTime, now + " 00:00:00", now + " 23:59:59");
+                int count = secondTradeRecordMapper.selectCount(wrapper);
+                String tradeNo = "S" + now.toString().replace("-", "") + String.format("%05d", count);
+                trade.setTradeNo(tradeNo);
+            }
             // 保存交易记录
             secondTradeRecordMapper.insert(trade);
 
@@ -71,7 +83,7 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
 
             return true;
         } catch (Exception e) {
-            log.error("SecondTradeRecordServiceImpl.createTrade Error Mgs={}", e.getMessage());
+            log.error("SecondTradeRecordServiceImpl.createTrade(): Error Msg={}", e.getMessage());
             throw new Exception(e);
         }
     }
@@ -139,9 +151,6 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
 
         alienStoreFeign.sendMsgToClientByPhoneId(phoneId, JSONObject.from(webSocketVo).toJSONString());
         alienStoreFeign.sendMsgToClientByPhoneId(receiverId, JSONObject.from(webSocketVo).toJSONString());
-
-//        alienStoreFeign.sendMsgToClientByPhoneId(phoneId, phoneId, receiverId, "message", messageType, message.toJSONString(), lifeMessage.getId());
-//        alienStoreFeign.sendMsgToClientByPhoneId(receiverId, phoneId, receiverId, "message", messageType, message.toJSONString(), lifeMessage.getId());
     }
 
     @Override
@@ -149,31 +158,34 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
         try {
             LambdaQueryWrapper<SecondTradeRecord> queryWrapper = new LambdaQueryWrapper<>();
             queryWrapper.eq(SecondTradeRecord::getGoodsId, goodsId);
-            queryWrapper.in(SecondTradeRecord::getTradeStatus, 1, 3, 4);
+            queryWrapper.in(SecondTradeRecord::getTradeStatus, 3, 4);
             return secondTradeRecordMapper.selectCount(queryWrapper) == 0;
         } catch (Exception e) {
-            log.error("SecondTradeRecordServiceImpl.goodsTrade Error Mgs={}", e.getMessage());
+            log.error("SecondTradeRecordServiceImpl.goodsTrade(): Error Msg={}", e.getMessage());
             throw new Exception(e);
         }
     }
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public boolean tradeConfirm(int tradeId, int messageId, int type) throws Exception {
+    public boolean tradeConfirm(int tradeId, int messageId, int type) throws BusinessException, Exception {
         try {
+            // 交易信息
+            SecondTradeRecord trade = secondTradeRecordMapper.selectById(tradeId);
+            if (trade.getTradeStatus() == 6) throw new BusinessException("该交易已取消,不可操作");
+
             // 修改交易状态
             SecondTradeRecord tradeRecord = new SecondTradeRecord();
             tradeRecord.setId(tradeId);
             if (type == 1) {
                 tradeRecord.setTradeStatus(3);
+                trade.setTradeStatus(3);
             } else {
                 tradeRecord.setTradeStatus(2);
+                trade.setTradeStatus(2);
             }
             secondTradeRecordMapper.updateById(tradeRecord);
 
-            // 交易信息
-            SecondTradeRecord trade = secondTradeRecordMapper.selectById(tradeId);
-
             // 商品信息
             SecondGoods goods = secondGoodsMapper.selectById(trade.getGoodsId());
 
@@ -212,12 +224,11 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
             alienStoreFeign.sendMsgToClientByPhoneId(phoneId, JSONObject.from(webSocketVo).toJSONString());
             alienStoreFeign.sendMsgToClientByPhoneId(receiverId, JSONObject.from(webSocketVo).toJSONString());
 
-//            alienStoreFeign.sendMsgToClientByPhoneId(phoneId, phoneId, receiverId, "message", "4", lastMessageContent.toJSONString(), lastMessage.getId());
-//            alienStoreFeign.sendMsgToClientByPhoneId(receiverId, phoneId, receiverId, "message", "4", lastMessageContent.toJSONString(), lastMessage.getId());
-
             return true;
+        } catch (BusinessException e) {
+            throw new BusinessException(e);
         } catch (Exception e) {
-            log.error("SecondTradeRecordServiceImpl.tradeConfirm Error Mgs={}", e.getMessage());
+            log.error("SecondTradeRecordServiceImpl.tradeConfirm(): Error Msg={}", e.getMessage());
             throw new Exception(e);
         }
     }
@@ -246,7 +257,7 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
 
             return true;
         } catch (Exception e) {
-            log.error("SecondTradeRecordServiceImpl.cancelTrade Error Mgs={}", e.getMessage());
+            log.error("SecondTradeRecordServiceImpl.cancelTrade(): Error Msg={}", e.getMessage());
             throw new Exception(e);
         }
     }
@@ -261,7 +272,7 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
             if (userId == trade.getBuyerId() && 0 == trade.getBuyerSignIn()) return true;
             if (userId == trade.getSellerId() && 0 == trade.getSellerSignIn()) return true;
         } catch (Exception e) {
-            log.error("SecondTradeRecordServiceImpl.whetherCanSignIn Error Mgs={}", e.getMessage());
+            log.error("SecondTradeRecordServiceImpl.whetherCanSignIn(): Error Msg={}", e.getMessage());
             throw new Exception(e);
         }
         return false;
@@ -269,10 +280,11 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public boolean tradeSignIn(int tradeId, int messageId, String signInLatitudeLongitude, String signInLatitudeLongitudeAddress) throws Exception {
+    public boolean tradeSignIn(int tradeId, int messageId, String signInLatitudeLongitude, String signInLatitudeLongitudeAddress) throws BusinessException, Exception {
         try {
             SecondTradeRecord trade = secondTradeRecordMapper.selectById(tradeId);
             if (null == trade) return false;
+            if (trade.getTradeStatus() != 3) return false;
 
             // 发起交易人信息
             int userId = Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getInteger("userId");
@@ -287,23 +299,26 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
             record.setId(tradeId);
             Date now = Date.from(LocalDateTime.now().withSecond(0).withNano(0).atZone(ZoneId.systemDefault()).toInstant());
             if (userId == trade.getBuyerId()) {
+                if (1 == trade.getBuyerSignIn()) throw new BusinessException("该交易已签到,无需再次签到");
                 record.setBuyerSignIn(1);
                 record.setBuyerSignInTime(now);
                 record.setBuyerSignInLatitudeLongitude(signInLatitudeLongitude);
                 record.setBuyerSignInLatitudeLongitudeAddress(signInLatitudeLongitudeAddress);
             } else if (userId == trade.getSellerId()) {
+                if (1 == trade.getSellerSignIn()) throw new BusinessException("该交易已签到,无需再次签到");
                 record.setSellerSignIn(1);
                 record.setSellerSignInTime(now);
                 record.setSellerSignInLatitudeLongitude(signInLatitudeLongitude);
                 record.setSellerSignInLatitudeLongitudeAddress(signInLatitudeLongitudeAddress);
             } else {
-                return false;
+                log.error("SecondTradeRecordServiceImpl.tradeSignIn(): Error Msg={}", "userId无效");
+                throw new Exception();
             }
             secondTradeRecordMapper.updateById(record);
 
             // 删除签到提醒
             LifeMessage signInMessage = lifeMessageMapper.selectById(messageId);
-            if (null == signInMessage) throw new Exception("该交易已签到,无需再次签到");
+            if (null == signInMessage) throw new BusinessException("该交易已签到,无需再次签到");
             lifeMessageMapper.deleteById(messageId);
 
             // 发送已签到消息
@@ -332,12 +347,9 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
             alienStoreFeign.sendMsgToClientByPhoneId(phoneId, JSONObject.from(webSocketVo).toJSONString());
             alienStoreFeign.sendMsgToClientByPhoneId(receiverId, JSONObject.from(webSocketVo).toJSONString());
 
-//            alienStoreFeign.sendMsgToClientByPhoneId(phoneId, phoneId, receiverId, "message", "6", messageContent.toJSONString(), message.getId());
-//            alienStoreFeign.sendMsgToClientByPhoneId(receiverId, phoneId, receiverId, "message", "6", messageContent.toJSONString(), message.getId());
-
             return true;
         } catch (Exception e) {
-            log.error("SecondTradeRecordServiceImpl.tradeSignIn Error Mgs={}", e.getMessage());
+            log.error("SecondTradeRecordServiceImpl.tradeSignIn(): Error Msg={}", e.getMessage());
             throw new Exception(e);
         }
     }
@@ -349,6 +361,8 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
             SecondTradeRecordVo recordVo = new SecondTradeRecordVo();
             int userId = Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getInteger("userId");
             SecondTradeRecord tradeRecord = secondTradeRecordMapper.selectById(tradeId);
+            if (null == tradeRecord) return new SecondTradeRecordVo();
+
             if (userId == tradeRecord.getBuyerId()) {
                 recordVo.setUserTransactionStatus(tradeRecord.getBuyerTransactionStatus());
                 recordVo.setUserEvaluate(tradeRecord.getBuyerEvaluate());
@@ -358,7 +372,7 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
             }
             return recordVo;
         } catch (Exception e) {
-            log.error("SecondTradeRecordServiceImpl.getUserTradeStatus Error Mgs={}", e.getMessage());
+            log.error("SecondTradeRecordServiceImpl.getUserTradeStatus(): Error Msg={}", e.getMessage());
             throw new Exception(e);
         }
     }
@@ -383,7 +397,7 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
                 record.setSellerEvaluate(evaluate);
                 record.setTradeStatus(1 == type ? 4 : 5);
                 // 卖家如果选择交易成功  同步修改商品表
-                if (1 == tradeRecord.getBuyerTransactionStatus()) {
+                if (1 == type) {
                     SecondGoods goods = new SecondGoods();
                     goods.setId(tradeRecord.getGoodsId());
                     goods.setGoodsStatus(5);
@@ -395,7 +409,7 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
             secondTradeRecordMapper.updateById(record);
             return true;
         } catch (Exception e) {
-            log.error("SecondTradeRecordServiceImpl.tradeCompleteConfirm Error Mgs={}", e.getMessage());
+            log.error("SecondTradeRecordServiceImpl.tradeCompleteConfirm(): Error Msg={}", e.getMessage());
             throw new Exception(e);
         }
     }
@@ -405,11 +419,12 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
         try {
             int userId = Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getInteger("userId");
             QueryWrapper<SecondTradeRecord> wrapper = new QueryWrapper<>();
-            wrapper.apply("(trade.buyer_id = '" + sideId + "' and trade.seller_id = '" + userId + "') || (trade.buyer_id = '" + userId + "' and trade.seller_id = '" + sideId + "')");
+            wrapper.eq("trade.delete_flag", 0);
+            wrapper.apply("((trade.buyer_id = '" + sideId + "' and trade.seller_id = '" + userId + "') || (trade.buyer_id = '" + userId + "' and trade.seller_id = '" + sideId + "'))");
             wrapper.orderByDesc("trade.created_time");
             return secondTradeRecordMapper.getTradeRecord(wrapper);
         } catch (Exception e) {
-            log.error("SecondTradeRecordServiceImpl.getTradeRecord Error Mgs={}", e.getMessage());
+            log.error("SecondTradeRecordServiceImpl.getTradeRecord(): Error Msg={}", e.getMessage());
             throw new Exception(e);
         }
     }

+ 204 - 0
alien-second/src/main/java/shop/alien/second/service/impl/VideoModerationServiceImpl.java

@@ -0,0 +1,204 @@
+package shop.alien.second.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.aliyun.green20220302.models.VideoModerationResponse;
+import com.aliyun.green20220302.models.VideoModerationResultResponse;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import shop.alien.entity.SecondVideoTask;
+import shop.alien.mapper.system.SecondVideoTaskMapper;
+import shop.alien.second.service.VideoModerationService;
+import shop.alien.util.common.safe.video.VideoModerationUtil;
+
+import java.util.Date;
+import java.util.UUID;
+
+/**
+ * 视频审核业务服务类
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class VideoModerationServiceImpl extends ServiceImpl<SecondVideoTaskMapper, SecondVideoTask> implements VideoModerationService {
+
+    /**
+     * 视频审核工具类
+     */
+    private final VideoModerationUtil videoModerationUtil;
+
+    /**
+     * 视频审核任务Mapper
+     */
+    private final SecondVideoTaskMapper videoModerationTaskMapper;
+
+    /**
+     * 提交视频审核任务
+     *
+     * @param videoUrl 视频URL
+     * @return 任务ID
+     */
+    public String submitVideoModerationTask(String videoUrl) {
+        try {
+            // 生成dataId
+            String dataId = "video_" + UUID.randomUUID().toString().replace("-", "");
+
+            // 调用阿里云接口提交任务
+            VideoModerationResponse response = videoModerationUtil.submitVideoModerationTask(videoUrl, dataId);
+
+            if (response.getStatusCode() == 200 && response.getBody() != null &&
+                    response.getBody().getCode() != null && response.getBody().getCode() == 200) {
+
+                // 保存任务信息到数据库
+                SecondVideoTask task = new SecondVideoTask();
+                task.setDataId(dataId);
+                task.setVideoUrl(videoUrl);
+                task.setTaskId(response.getBody().getData().getTaskId());
+                task.setStatus("SUBMITTED");
+                task.setCreateTime(new Date());
+                task.setUpdateTime(new Date());
+
+                videoModerationTaskMapper.insert(task);
+
+                log.info("视频审核任务提交成功,任务ID: {}", task.getTaskId());
+                return task.getTaskId();
+            } else {
+                log.error("提交视频审核任务失败,响应: {}", JSON.toJSONString(response));
+                throw new RuntimeException("提交视频审核任务失败: " + (response.getBody() != null ? response.getBody().getMessage() : "未知错误"));
+            }
+        } catch (Exception e) {
+            log.error("提交视频审核任务异常", e);
+            throw new RuntimeException("提交视频审核任务异常: " + e.getMessage());
+        }
+    }
+
+    /**
+     * 根据任务ID查询任务详情
+     *
+     * @param taskId 任务ID
+     * @return 任务详情
+     */
+    public SecondVideoTask getTaskByTaskId(String taskId) {
+        try {
+            return videoModerationTaskMapper.selectByTaskId(taskId);
+        } catch (Exception e) {
+            log.error("查询视频审核任务详情异常,任务ID: {}", taskId, e);
+            throw new RuntimeException("查询视频审核任务详情异常: " + e.getMessage());
+        }
+    }
+    
+    /**
+     * 根据任务ID查询任务详情
+     * 
+     * @param taskId 任务ID
+     * @return 任务详情
+     */
+    public SecondVideoTask getTaskById(String taskId) {
+        try {
+            return videoModerationTaskMapper.selectByTaskId(taskId);
+        } catch (Exception e) {
+            log.error("查询视频审核任务详情异常,任务ID: {}", taskId, e);
+            throw new RuntimeException("查询视频审核任务详情异常: " + e.getMessage());
+        }
+    }
+
+    /**
+     * 查询视频审核结果
+     *
+     * @param taskId 任务ID
+     * @return 审核结果
+     */
+    public SecondVideoTask queryVideoModerationResult(String taskId) {
+        try {
+            // 查询数据库中的任务
+            SecondVideoTask task = videoModerationTaskMapper.selectByTaskId(taskId);
+            if (task == null) {
+                throw new RuntimeException("未找到任务ID为 " + taskId + " 的审核任务");
+            }
+
+            // 调用阿里云接口获取审核结果
+            VideoModerationResultResponse response = videoModerationUtil.getVideoModerationResult(taskId);
+
+            if (response.getStatusCode() == 200 && response.getBody() != null &&
+                    response.getBody().getCode() != null && response.getBody().getCode() == 200) {
+
+                // 更新数据库中的任务结果
+                String status = "SUCCESS";
+                String riskLevel = response.getBody().getData().getRiskLevel();
+                String result = JSON.toJSONString(response.getBody().getData());
+
+                videoModerationTaskMapper.updateTaskResult(taskId, status, riskLevel, result);
+
+                // 更新任务对象并返回
+                task.setStatus(status);
+                task.setRiskLevel(riskLevel);
+                task.setResult(result);
+                task.setUpdateTime(new Date());
+
+                log.info("获取视频审核结果成功,任务ID: {}", taskId);
+                return task;
+            } else {
+                log.error("获取视频审核结果失败,响应: {}", JSON.toJSONString(response));
+                throw new RuntimeException("获取视频审核结果失败: " + (response.getBody() != null ? response.getBody().getMessage() : "未知错误"));
+            }
+        } catch (Exception e) {
+            log.error("获取视频审核结果异常,任务ID: {}", taskId, e);
+            throw new RuntimeException("获取视频审核结果异常: " + e.getMessage());
+        }
+    }
+
+    /**
+     * 处理单个审核任务
+     *
+     * @param task 审核任务
+     * @return 是否处理成功
+     */
+    public boolean processTask(SecondVideoTask task) {
+        try {
+            // 调用阿里云接口获取审核结果
+            VideoModerationResultResponse response = videoModerationUtil.getVideoModerationResult(task.getTaskId());
+
+            if (response.getStatusCode() == 200 && response.getBody() != null) {
+                Integer code = response.getBody().getCode();
+                if (code != null && code == 200) {
+                    // 审核完成,更新任务结果
+                    String status = "SUCCESS";
+                    String riskLevel = response.getBody().getData().getRiskLevel();
+                    String result = JSON.toJSONString(response.getBody().getData());
+
+                    videoModerationTaskMapper.updateTaskResult(task.getTaskId(), status, riskLevel, result);
+
+                    log.info("视频审核任务处理成功,任务ID: {}", task.getTaskId());
+                    return true;
+                } else if (code != null && code == 500) {
+                    // 审核仍在进行中,更新状态
+                    videoModerationTaskMapper.updateTaskStatus(task.getTaskId(), "PROCESSING");
+                    log.info("视频审核任务仍在处理中,任务ID: {}", task.getTaskId());
+                    return false;
+                } else {
+                    // 审核失败
+                    videoModerationTaskMapper.updateTaskStatus(task.getTaskId(), "FAILED");
+                    log.error("视频审核任务处理失败,任务ID: {},错误信息: {}", task.getTaskId(), response.getBody().getMessage());
+                    return false;
+                }
+            } else {
+                // HTTP请求失败
+                log.error("获取视频审核结果HTTP请求失败,任务ID: {},状态码: {}", task.getTaskId(), response.getStatusCode());
+                return false;
+            }
+        } catch (Exception e) {
+            log.error("处理视频审核任务异常,任务ID: {}", task.getTaskId(), e);
+
+            // 增加重试次数
+            videoModerationTaskMapper.incrementRetryCount(task.getId());
+
+            // 如果重试次数超过3次,标记为失败
+            if (task.getRetryCount() >= 3) {
+                videoModerationTaskMapper.updateTaskStatus(task.getTaskId(), "FAILED");
+            }
+
+            return false;
+        }
+    }
+}

+ 335 - 0
alien-second/src/main/java/shop/alien/second/task/Task.java

@@ -0,0 +1,335 @@
+package shop.alien.second.task;
+
+import cn.hutool.core.collection.CollectionUtil;
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+import shop.alien.config.redis.BaseRedisService;
+import shop.alien.entity.second.SecondGoods;
+import shop.alien.entity.second.SecondTradeRecord;
+import shop.alien.entity.store.LifeMessage;
+import shop.alien.entity.store.LifeNotice;
+import shop.alien.entity.store.LifeUser;
+import shop.alien.entity.store.vo.WebSocketVo;
+import shop.alien.mapper.LifeMessageMapper;
+import shop.alien.mapper.LifeNoticeMapper;
+import shop.alien.mapper.LifeUserMapper;
+import shop.alien.mapper.second.SecondGoodsMapper;
+import shop.alien.mapper.second.SecondTradeRecordMapper;
+import shop.alien.second.feign.AlienStoreFeign;
+
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class Task {
+
+    private final SecondTradeRecordMapper secondTradeRecordMapper;
+
+    private final LifeNoticeMapper lifeNoticeMapper;
+
+    private final LifeUserMapper lifeUserMapper;
+
+    private final LifeMessageMapper lifeMessageMapper;
+
+    private final AlienStoreFeign alienStoreFeign;
+
+    private final BaseRedisService baseRedisService;
+
+    private final SecondGoodsMapper secondGoodsMapper;
+
+    @Value("${ScheduledTask.enabled}")
+    private boolean isEnable;
+
+    /**
+     * 二手交易平台 - 交易时间前的十分钟之前  给买家和卖家发送通知提醒
+     */
+    @Scheduled(cron = "0 * * * * ?")
+    public void secondTradeRemind() throws Exception {
+        if (!isEnable) {
+            return;
+        }
+
+        log.info("开始执行定时任务: 二手交易平台 - 10分钟后交易提醒 - secondTradeRemind");
+        try {
+            Date now = Date.from(LocalDateTime.now().plusMinutes(10).withSecond(0).withNano(0).atZone(ZoneId.systemDefault()).toInstant());
+
+            // 查询所有待交易
+            LambdaQueryWrapper<SecondTradeRecord> wrapper = new LambdaQueryWrapper<>();
+            wrapper.eq(SecondTradeRecord::getTradeStatus, 3);
+            wrapper.eq(SecondTradeRecord::getTransactionTime, now);
+            List<SecondTradeRecord> tradeRecordList = secondTradeRecordMapper.selectList(wrapper);
+
+            for (SecondTradeRecord tradeRecord : tradeRecordList) {
+                LifeUser buyer = lifeUserMapper.selectById(tradeRecord.getBuyerId());
+                LifeUser seller = lifeUserMapper.selectById(tradeRecord.getSellerId());
+
+                String buyerPhoneId = null == buyer ? "" : "user_" + buyer.getUserPhone();
+                String sellerPhoneId = null == seller ? "" : "user_" + seller.getUserPhone();
+
+                // 封装交易信息
+                JSONObject message = new JSONObject();
+                message.put("tradeId", tradeRecord.getId());
+                message.put("transactionAmount", tradeRecord.getTransactionAmount());
+                message.put("transactionLatitudeLongitude", tradeRecord.getTransactionLatitudeLongitude());
+                message.put("transactionLatitudeLongitudeAddress", tradeRecord.getTransactionLatitudeLongitudeAddress());
+                message.put("transactionLocation", tradeRecord.getTransactionLocation());
+                message.put("transactionTime", tradeRecord.getTransactionTime());
+                message.put("tradeStatus", tradeRecord.getTradeStatus());
+
+                // 给买家发送消息
+                LifeMessage lifeMessage = new LifeMessage();
+                lifeMessage.setSenderId(sellerPhoneId);
+                lifeMessage.setReceiverId(buyerPhoneId);
+                lifeMessage.setContent(message.toJSONString());
+                lifeMessage.setType("5");
+                lifeMessageMapper.insert(lifeMessage);
+
+                // 给买家推送消息
+                WebSocketVo webSocketVo = new WebSocketVo();
+                webSocketVo.setSenderId(sellerPhoneId);
+                webSocketVo.setReceiverId(buyerPhoneId);
+                webSocketVo.setCategory("message");
+                webSocketVo.setType("5");
+                webSocketVo.setText(message.toJSONString());
+                webSocketVo.setMessageId(lifeMessage.getId());
+                alienStoreFeign.sendMsgToClientByPhoneId(buyerPhoneId, JSONObject.from(webSocketVo).toJSONString());
+
+                // 给买家发送通知
+                LifeNotice lifeNotice = new LifeNotice();
+                lifeNotice.setSenderId("system");
+                lifeNotice.setReceiverId(buyerPhoneId);
+                lifeNotice.setBusinessId(tradeRecord.getId());
+                lifeNotice.setTitle("商品交易签到");
+                lifeNotice.setNoticeType(1);
+                // 封装通知信息
+                JSONObject noticeMessage = new JSONObject();
+                noticeMessage.put("tradeId", tradeRecord.getId());
+                noticeMessage.put("otherSideUserId", tradeRecord.getSellerId());
+                noticeMessage.put("otherSidePhoneId", sellerPhoneId);
+                noticeMessage.put("otherSideName", null == seller ? "" : seller.getUserName());
+                noticeMessage.put("otherSideImage", null == seller ? "" : seller.getUserImage());
+                noticeMessage.put("message", "您有一笔交易即将开始, 请及时前往查看");
+                lifeNotice.setContext(noticeMessage.toJSONString());
+                lifeNoticeMapper.insert(lifeNotice);
+
+                // 给买家推送通知
+                webSocketVo = new WebSocketVo();
+                webSocketVo.setSenderId("system");
+                webSocketVo.setReceiverId(buyerPhoneId);
+                webSocketVo.setCategory("notice");
+                webSocketVo.setNoticeType("1");
+                webSocketVo.setType("5");
+                webSocketVo.setText(JSONObject.from(lifeNotice).toJSONString());
+                webSocketVo.setMessageId(lifeMessage.getId());
+                alienStoreFeign.sendMsgToClientByPhoneId(buyerPhoneId, JSONObject.from(webSocketVo).toJSONString());
+
+                // 给卖家发送消息
+                lifeMessage = new LifeMessage();
+                lifeMessage.setSenderId(buyerPhoneId);
+                lifeMessage.setReceiverId(sellerPhoneId);
+                lifeMessage.setContent(message.toJSONString());
+                lifeMessage.setType("5");
+                lifeMessageMapper.insert(lifeMessage);
+
+                // 给卖家推送消息
+                webSocketVo = new WebSocketVo();
+                webSocketVo.setSenderId(buyerPhoneId);
+                webSocketVo.setReceiverId(sellerPhoneId);
+                webSocketVo.setCategory("message");
+                webSocketVo.setType("5");
+                webSocketVo.setText(message.toJSONString());
+                webSocketVo.setMessageId(lifeMessage.getId());
+                alienStoreFeign.sendMsgToClientByPhoneId(sellerPhoneId, JSONObject.from(webSocketVo).toJSONString());
+
+                // 给卖家发送通知
+                lifeNotice = new LifeNotice();
+                lifeNotice.setSenderId("system");
+                lifeNotice.setReceiverId(sellerPhoneId);
+                lifeNotice.setBusinessId(tradeRecord.getId());
+                lifeNotice.setTitle("商品交易签到");
+                lifeNotice.setNoticeType(1);
+                // 封装通知信息
+                noticeMessage = new JSONObject();
+                noticeMessage.put("tradeId", tradeRecord.getId());
+                noticeMessage.put("otherSideUserId", tradeRecord.getBuyerId());
+                noticeMessage.put("otherSidePhoneId", buyerPhoneId);
+                noticeMessage.put("otherSideName", null == buyer ? "" : buyer.getUserName());
+                noticeMessage.put("otherSideImage", null == buyer ? "" : buyer.getUserImage());
+                noticeMessage.put("message", "您有一笔交易即将开始, 请及时前往查看");
+                lifeNotice.setContext(noticeMessage.toJSONString());
+                lifeNoticeMapper.insert(lifeNotice);
+
+                // 给卖家推送通知
+                webSocketVo = new WebSocketVo();
+                webSocketVo.setSenderId("system");
+                webSocketVo.setReceiverId(sellerPhoneId);
+                webSocketVo.setCategory("notice");
+                webSocketVo.setNoticeType("1");
+                webSocketVo.setType("5");
+                webSocketVo.setText(JSONObject.from(lifeNotice).toJSONString());
+                webSocketVo.setMessageId(lifeMessage.getId());
+                alienStoreFeign.sendMsgToClientByPhoneId(sellerPhoneId, JSONObject.from(webSocketVo).toJSONString());
+            }
+        } catch (Exception e) {
+            log.error("SecondGoodsTradeXxlJob.secondTradeRemind Error Msg={}", e.getMessage());
+        }
+    }
+
+    /**
+     * 二手交易平台 - 到达交易时间时,给买家和卖家发送交易确认提醒
+     */
+    @Scheduled(cron = "0 * * * * ?")
+    public void secondTradeConfirm() throws Exception {
+        if (!isEnable) {
+            return;
+        }
+
+        log.info("开始执行定时任务: 二手交易平台 - 到达交易时间时,给买家和卖家发送交易确认提醒 - secondTradeConfirm");
+        try {
+            Date now = Date.from(LocalDateTime.now().withSecond(0).withNano(0).atZone(ZoneId.systemDefault()).toInstant());
+
+            // 查询所有待交易
+            LambdaQueryWrapper<SecondTradeRecord> wrapper = new LambdaQueryWrapper<>();
+            wrapper.eq(SecondTradeRecord::getTradeStatus, 3);
+            wrapper.eq(SecondTradeRecord::getTransactionTime, now);
+            List<SecondTradeRecord> tradeRecordList = secondTradeRecordMapper.selectList(wrapper);
+
+            for (SecondTradeRecord tradeRecord : tradeRecordList) {
+                LifeUser buyer = lifeUserMapper.selectById(tradeRecord.getBuyerId());
+                LifeUser seller = lifeUserMapper.selectById(tradeRecord.getSellerId());
+                SecondGoods goods = secondGoodsMapper.selectById(tradeRecord.getGoodsId());
+
+                String buyerPhoneId = null == buyer ? "" : "user_" + buyer.getUserPhone();
+                String sellerPhoneId = null == seller ? "" : "user_" + seller.getUserPhone();
+
+                // 给买家发送通知
+                LifeNotice lifeNotice = new LifeNotice();
+                lifeNotice.setSenderId("system");
+                lifeNotice.setReceiverId(buyerPhoneId);
+                lifeNotice.setBusinessId(tradeRecord.getId());
+                lifeNotice.setTitle("商品是否交易成功");
+                lifeNotice.setNoticeType(1);
+                // 封装通知信息
+                JSONObject noticeMessage = new JSONObject();
+                noticeMessage.put("goodsId", goods.getId());
+                noticeMessage.put("goodsHomeImage", goods.getHomeImage());
+                noticeMessage.put("goodsTitle", goods.getTitle());
+                noticeMessage.put("tradeId", tradeRecord.getId());
+                noticeMessage.put("transactionAmount", tradeRecord.getTransactionAmount());
+                noticeMessage.put("transactionLatitudeLongitude", tradeRecord.getTransactionLatitudeLongitude());
+                noticeMessage.put("transactionLatitudeLongitudeAddress", tradeRecord.getTransactionLatitudeLongitudeAddress());
+                noticeMessage.put("transactionLocation", tradeRecord.getTransactionLocation());
+                noticeMessage.put("transactionTime", tradeRecord.getTransactionTime());
+                noticeMessage.put("tradeStatus", tradeRecord.getTradeStatus());
+                noticeMessage.put("message", "您有一笔交易已完成, 请前往确认");
+                lifeNotice.setContext(noticeMessage.toJSONString());
+                lifeNoticeMapper.insert(lifeNotice);
+
+                // 给买家推送通知
+                WebSocketVo webSocketVo = new WebSocketVo();
+                webSocketVo.setSenderId("system");
+                webSocketVo.setReceiverId(buyerPhoneId);
+                webSocketVo.setCategory("notice");
+                webSocketVo.setNoticeType("1");
+                webSocketVo.setType("5");
+                webSocketVo.setIsRead(0);
+                webSocketVo.setText(JSONObject.from(lifeNotice).toJSONString());
+                alienStoreFeign.sendMsgToClientByPhoneId(buyerPhoneId, JSONObject.from(webSocketVo).toJSONString());
+
+                // 给卖家发送通知
+                lifeNotice = new LifeNotice();
+                lifeNotice.setSenderId("system");
+                lifeNotice.setReceiverId(sellerPhoneId);
+                lifeNotice.setBusinessId(tradeRecord.getId());
+                lifeNotice.setTitle("商品是否交易成功");
+                lifeNotice.setNoticeType(1);
+                lifeNotice.setContext(noticeMessage.toJSONString());
+                lifeNoticeMapper.insert(lifeNotice);
+
+                // 给卖家推送通知
+                webSocketVo = new WebSocketVo();
+                webSocketVo.setSenderId("system");
+                webSocketVo.setReceiverId(sellerPhoneId);
+                webSocketVo.setCategory("notice");
+                webSocketVo.setNoticeType("1");
+                webSocketVo.setType("5");
+                webSocketVo.setIsRead(0);
+                webSocketVo.setText(JSONObject.from(lifeNotice).toJSONString());
+                alienStoreFeign.sendMsgToClientByPhoneId(sellerPhoneId, JSONObject.from(webSocketVo).toJSONString());
+            }
+        } catch (Exception e) {
+            log.error("SecondGoodsTradeXxlJob.secondTradeConfirm Error Mgs={}", e.getMessage());
+        }
+    }
+
+    /**
+     * 二手交易平台 - 交易超时未确认则自动取消
+     */
+    @Scheduled(cron = "0 * * * * ?")
+    private void secondTradeTimeoutCancel() {
+        if (!isEnable) {
+            return;
+        }
+
+        log.info("开始执行定时任务: 二手交易平台 - 交易超时未确认则自动取消 - secondTradeTimeoutCancel");
+        try {
+            LocalDateTime now = LocalDateTime.now().withSecond(0).withNano(0);
+
+            // 查询所有待确认
+            LambdaQueryWrapper<SecondTradeRecord> queryWrapper = new LambdaQueryWrapper<>();
+            queryWrapper.eq(SecondTradeRecord::getTradeStatus, 1);
+            List<SecondTradeRecord> tradeRecordList = secondTradeRecordMapper.selectList(queryWrapper);
+            List<Integer> tradeIdList = new ArrayList<>();
+            for (SecondTradeRecord tradeRecord : tradeRecordList) {
+                LocalDateTime tenMinutesAgo = tradeRecord.getTransactionTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().withSecond(0).withNano(0);
+                if (now.isEqual(tenMinutesAgo)) {
+                    tradeIdList.add(tradeRecord.getId());
+                }
+            }
+            if (CollectionUtil.isNotEmpty(tradeIdList)) {
+                LambdaUpdateWrapper<SecondTradeRecord> updateWrapper = new LambdaUpdateWrapper<>();
+                updateWrapper.in(SecondTradeRecord::getId, tradeIdList)
+                        .set(SecondTradeRecord::getTradeStatus, 6);
+                secondTradeRecordMapper.update(null, updateWrapper);
+            }
+        } catch (Exception e) {
+            log.error("SecondGoodsTradeXxlJob.secondTradeTimeoutCancel Error Mgs={}", e.getMessage());
+        }
+    }
+
+    /**
+     * 二手交易平台 - 每分钟从redis中读取已读的消息id 并将数据库设为已读
+     */
+    @Scheduled(cron = "0 * * * * ?")
+    public void readMessage() {
+        if (!isEnable) {
+            return;
+        }
+
+        log.info("开始执行定时任务: 二手交易平台 - 每分钟从redis中读取已读的消息id 并将数据库设为已读 - readMessage");
+        try {
+            if (CollectionUtil.isEmpty(baseRedisService.getList("readMessageIdKey"))) return;
+
+            List<String> dataList = baseRedisService.popBatchFromList("readMessageIdKey");
+            if (CollectionUtil.isNotEmpty(dataList)) {
+                LambdaUpdateWrapper<LifeMessage> wrapper = new LambdaUpdateWrapper<>();
+                wrapper.in(LifeMessage::getId, dataList)
+                        .set(LifeMessage::getIsRead, 1);
+                lifeMessageMapper.update(null, wrapper);
+            }
+        } catch (Exception e) {
+            log.error("ScheduledTask.readMessage Error Mgs={}", e.getMessage());
+        }
+    }
+}

+ 1 - 0
alien-second/src/main/resources/bootstrap-prod.yml

@@ -9,6 +9,7 @@ spring:
         server-addr: localhost:8848
         username: nacos
         password: ngfriend198092
+        namespace: 3cbb802a-b56e-47f7-b658-b5012ecafb1f
 
       #配置中心
       config:

+ 1 - 0
alien-second/src/main/resources/bootstrap-test.yml

@@ -9,6 +9,7 @@ spring:
         server-addr: 192.168.2.252:8848
         username: nacos
         password: ngfriend198092
+        namespace: 0e1e2d77-56e8-422c-8317-6f71d7285e59
 
       #配置中心
       config:

+ 1 - 1
alien-second/src/main/resources/logback-spring.xml

@@ -12,7 +12,7 @@
     <!-- 定义全局参数常量 -->
     <property name="log.level" value="debug"/>
     <property name="log.maxHistory" value="30"/><!-- 30表示30个 -->
-    <property name="logging.path" value="/javaLog/alienSecondLog"/>
+    <springProperty scope="context" name="logging.path" source="logging.path"/>
     <!--输出文件前缀-->
     <property name="FILENAME" value="alien"/>
 

+ 14 - 8
alien-store/src/main/java/shop/alien/store/config/WebSocketProcess.java

@@ -4,9 +4,7 @@ import cn.hutool.core.collection.CollectionUtil;
 import com.alibaba.fastjson2.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.google.common.collect.Lists;
-import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
 import org.springframework.stereotype.Component;
@@ -21,7 +19,6 @@ import shop.alien.util.common.safe.TextModerationResultVO;
 import shop.alien.util.common.safe.TextModerationUtil;
 import shop.alien.util.common.safe.TextReviewServiceEnum;
 
-import javax.annotation.Resource;
 import javax.websocket.*;
 import javax.websocket.server.PathParam;
 import javax.websocket.server.ServerEndpoint;
@@ -128,6 +125,9 @@ public class WebSocketProcess implements ApplicationContextAware {
                 return;
             }
 
+            log.info("websocketVo----------------{}",JSONObject.from(websocketVo).toJSONString());
+            log.info("concurrentHashMap----------{}",concurrentHashMap.keySet());
+
             // 保存消息记录
             LifeMessage lifeMessage = new LifeMessage();
             lifeMessage.setSenderId(websocketVo.getSenderId());
@@ -140,12 +140,16 @@ public class WebSocketProcess implements ApplicationContextAware {
                 if (blackList.contains(websocketVo.getReceiverId())) {
                     lifeMessage.setDeletePhoneId(websocketVo.getReceiverId());
                     lifeMessageMapper.insert(lifeMessage);
+                    // 发送消息
+                    websocketVo.setMessageId(lifeMessage.getId());
+                    websocketVo.setCategory("message");
+                    websocketVo.setCreatedTime(lifeMessage.getCreatedTime());
+                    sendMessage(websocketVo.getSenderId(), JSONObject.from(websocketVo).toJSONString());
                     return;
                 }
-            } else {
-                lifeMessageMapper.insert(lifeMessage);
             }
 
+            lifeMessageMapper.insert(lifeMessage);
             // 发送消息
             websocketVo.setMessageId(lifeMessage.getId());
             websocketVo.setCategory("message");
@@ -153,7 +157,7 @@ public class WebSocketProcess implements ApplicationContextAware {
             sendMessage(websocketVo.getSenderId(), JSONObject.from(websocketVo).toJSONString());
             sendMessage(websocketVo.getReceiverId(), JSONObject.from(websocketVo).toJSONString());
         } catch (Exception e) {
-            log.error("WebSocketProcess.onMessage() Error Mgs={}", e.getMessage());
+            log.error("WebSocketProcess.onMessage()----error----Msg={}", e.getMessage());
         }
     }
 
@@ -180,17 +184,19 @@ public class WebSocketProcess implements ApplicationContextAware {
      * 发送消息到指定客户端
      */
     public void sendMessage(String id, String message) throws Exception {
+        log.info("WebSocketProcess.sendMessage()--ready----id={},message={}", id, message);
         //根据id,从map中获取存储的webSocket对象
         WebSocketProcess webSocketProcess = concurrentHashMap.get(id);
         if (!ObjectUtils.isEmpty(webSocketProcess)) {
             //当客户端是Open状态时,才能发送消息
             if (webSocketProcess.session.isOpen()) {
                 webSocketProcess.session.getBasicRemote().sendText(message);
+                log.info("WebSocketProcess.sendMessage()---success---id={},message={}", id, message);
             } else {
-                log.error("WebSocketProcess.sendMessage() websocket session={} is closed ", id);
+                log.error("WebSocketProcess.sendMessage()---error----websocket session:{} is closed ", id);
             }
         } else {
-            log.error("WebSocketProcess.sendMessage() websocket session={} is not exit ", id);
+            log.error("WebSocketProcess.sendMessage()---error----websocket session:{} is not exit ", id);
         }
     }
 

+ 4 - 2
alien-store/src/main/java/shop/alien/store/controller/AliController.java

@@ -7,6 +7,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 import shop.alien.entity.result.R;
+import shop.alien.entity.store.StoreAliPayLog;
 import shop.alien.store.service.AliService;
 import shop.alien.store.util.ali.AliApi;
 import shop.alien.store.util.ali.AliSms;
@@ -73,8 +74,9 @@ public class AliController {
     @GetMapping("/pay")
     public R pay(String name, String idCard, String phone, String money) {
         log.info("AliController.pay?name={}&idCard={}&phone={}&money={}", name, idCard, phone, money);
-        if (null != aliPayConfig.pay(name, idCard, phone, money)) {
-            return R.success("转账成功");
+        StoreAliPayLog pay = aliPayConfig.pay(name, idCard, phone, money);
+        if (null != pay) {
+            return R.data(pay);
         }
         return R.fail("转账失败");
     }

+ 11 - 0
alien-store/src/main/java/shop/alien/store/controller/LifeCollectController.java

@@ -1,5 +1,6 @@
 package shop.alien.store.controller;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -15,6 +16,7 @@ import shop.alien.entity.second.SecondGoods;
 import shop.alien.entity.store.LifeCollect;
 import shop.alien.entity.store.LifeCoupon;
 import shop.alien.entity.store.StoreImg;
+import shop.alien.entity.store.StoreInfo;
 import shop.alien.entity.store.vo.StoreInfoVo;
 import shop.alien.mapper.*;
 import shop.alien.mapper.second.SecondGoodsMapper;
@@ -215,6 +217,15 @@ public class LifeCollectController {
             lambdaUpdateWrapper.setSql("collect_count = collect_count + 1");
             secondGoodsMapper.update(null, lambdaUpdateWrapper);
         }
+
+        //同步店铺收藏数量
+        if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotEmpty(lifeCollect.getStoreId())) {
+            LambdaQueryWrapper<LifeCollect> queryWrapper = new LambdaQueryWrapper<>();
+            queryWrapper.eq(LifeCollect::getStoreId, lifeCollect.getStoreId());
+            storeInfoMapper.update(null, new LambdaUpdateWrapper<StoreInfo>().eq(StoreInfo::getId, lifeCollect.getStoreId()).set(StoreInfo::getCollectNum, lifeCollectMapper.selectCount(queryWrapper)));
+        }
+
+
         if (num == 0) {
             return R.fail("收藏失败");
         }

+ 11 - 9
alien-store/src/main/java/shop/alien/store/controller/LifeDiscountCouponController.java

@@ -80,8 +80,8 @@ public class LifeDiscountCouponController {
     public R<Boolean> deleteDiscountCoupon(@PathVariable("id") Integer id) {
         log.info("LifeDiscountCouponController.deleteDiscountCoupon?id={}", id);
         try {
-            boolean deleteed = lifeDiscountCouponService.deleteDiscountCoupon(id);
-            if (!deleteed) {
+            boolean deleted = lifeDiscountCouponService.deleteDiscountCoupon(id);
+            if (!deleted) {
                 return R.fail("删除失败");
             }
         } catch (Exception e) {
@@ -181,7 +181,7 @@ public class LifeDiscountCouponController {
     @GetMapping("/getUserCouponList")
     @ApiImplicitParams({@ApiImplicitParam(name = "page", value = "分页页数", dataType = "String", paramType = "query", required = true),
             @ApiImplicitParam(name = "size", value = "分页条数", dataType = "String", paramType = "query", required = true),
-            @ApiImplicitParam(name = "tabType", value = "分页类型(0:全部,1:即将过期,2:已使用,3:已过期)", dataType = "String", paramType = "query", required = true)
+            @ApiImplicitParam(name = "tabType", value = "分页类型(0:全部(未使用),1:即将过期,2:已使用,3:已过期)", dataType = "String", paramType = "query", required = true)
     })
     public R<List<LifeDiscountCouponVo>> getUserCouponList(@ApiIgnore @TokenInfo UserLoginInfo userLoginInfo,
                                                            @RequestParam(value = "tabType") String tabType,
@@ -213,11 +213,12 @@ public class LifeDiscountCouponController {
                                                                 @RequestParam(value = "storeId") String storeId,
                                                                 @RequestParam(value = "couponName", required = false) String couponName,
                                                                 @RequestParam(value = "tab") String tab,
-                                                                @RequestParam(value = "couponsFromType", defaultValue = "1") int couponsFromType
+                                                                @RequestParam(value = "couponsFromType", defaultValue = "1") int couponsFromType,
+                                                                @RequestParam(value = "couponStatus", defaultValue = "1",required = false) int couponStatus
     ) {
-        log.info("LifeDiscountCouponController.getStoreAllCouponList?storeId={}, couponName={}, tab={}, page={}, size={}", storeId, couponName, tab, page, size);
+        log.info("LifeDiscountCouponController.getStoreAllCouponList?storeId={}, couponName={}, tab={}, page={}, size={}, couponStatus={}", storeId, couponName, tab, page, size, couponStatus);
         try {
-            IPage<LifeDiscountCouponVo> storeCouponList = lifeDiscountCouponService.getStoreAllCouponList(storeId, userLoginInfo, page, size, couponName, tab, couponsFromType);
+            IPage<LifeDiscountCouponVo> storeCouponList = lifeDiscountCouponService.getStoreAllCouponList(storeId, userLoginInfo, page, size, couponName, tab, couponsFromType, couponStatus);
             return R.data(storeCouponList);
         } catch (Exception e) {
             log.error("LifeDiscountCouponController.getStoreCouponList ERROR Msg={}", e.getMessage());
@@ -233,11 +234,12 @@ public class LifeDiscountCouponController {
     })
     public R<List<LifeDiscountCouponVo>> getStoreAllCouponListPaginateNot(@ApiIgnore @TokenInfo UserLoginInfo userLoginInfo,
                                                                           @RequestParam(value = "storeId") String storeId,
-                                                                          @RequestParam(value = "status", required = false) String status
+                                                                          @RequestParam(value = "status", required = false) String status,
+                                                                          @RequestParam(value = "couponStatus", defaultValue = "1",required = false) int couponStatus
     ) {
-        log.info("LifeDiscountCouponController.getStoreAllCouponListPaginateNot?storeId={},status={}", storeId, status);
+        log.info("LifeDiscountCouponController.getStoreAllCouponListPaginateNot?storeId={},status={}, couponStatus={}", storeId, status, couponStatus);
         try {
-            List<LifeDiscountCouponVo> storeCouponList = lifeDiscountCouponService.getStoreAllCouponListPaginateNot(status, storeId, userLoginInfo);
+            List<LifeDiscountCouponVo> storeCouponList = lifeDiscountCouponService.getStoreAllCouponListPaginateNot(status, storeId, userLoginInfo, couponStatus);
             return R.data(storeCouponList);
         } catch (Exception e) {
             log.error("LifeDiscountCouponController.getStoreAllCouponListPaginateNot ERROR Msg={}", e.getMessage());

+ 15 - 21
alien-store/src/main/java/shop/alien/store/controller/LifeMessageController.java

@@ -6,9 +6,9 @@ import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.bind.annotation.*;
 import shop.alien.entity.result.R;
+import shop.alien.entity.store.vo.LifeFansVo;
 import shop.alien.entity.store.vo.LifeMessageVo;
 import shop.alien.store.service.LifeMessageService;
-import shop.alien.store.task.ScheduledTask;
 
 import java.util.List;
 
@@ -24,18 +24,12 @@ import java.util.List;
 public class LifeMessageController {
 
     private final LifeMessageService lifeMessageService;
-    private final ScheduledTask scheduledTask;
 
     @ApiOperation("消息列表")
     @ApiOperationSupport(order = 1)
-    @ApiImplicitParams({
-            @ApiImplicitParam(name = "receiverId", value = "当前登录人", dataType = "String", paramType = "query"),
-            @ApiImplicitParam(name = "friendType", value = "聊天类型  0-搜索 1-聊过 2-未聊过", dataType = "Integer", paramType = "query"),
-            @ApiImplicitParam(name = "search", value = "搜索字段", dataType = "Integer", paramType = "query")})
+    @ApiImplicitParams({@ApiImplicitParam(name = "receiverId", value = "当前登录人", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "friendType", value = "聊天类型  0-搜索 1-聊过 2-未聊过", dataType = "Integer", paramType = "query"), @ApiImplicitParam(name = "search", value = "搜索字段", dataType = "Integer", paramType = "query")})
     @GetMapping("/getMessageList")
-    public R<List<LifeMessageVo>> getMessageList(@RequestParam String receiverId,
-                                                  @RequestParam int friendType,
-                                                  String search) throws Exception {
+    public R<List<LifeMessageVo>> getMessageList(@RequestParam String receiverId, @RequestParam int friendType, String search) throws Exception {
         log.info("LifeMessageController.getMessageList?receiverId={}, friendType={}, search={}", receiverId, friendType, search);
         return R.data(lifeMessageService.getMessageList(receiverId, friendType, search));
     }
@@ -60,9 +54,7 @@ public class LifeMessageController {
 
     @ApiOperation("消息详情")
     @ApiOperationSupport(order = 4)
-    @ApiImplicitParams({
-            @ApiImplicitParam(name = "receiverId", value = "当前登录人", dataType = "String", paramType = "query"),
-            @ApiImplicitParam(name = "senderId", value = "聊天对方", dataType = "String", paramType = "query")})
+    @ApiImplicitParams({@ApiImplicitParam(name = "receiverId", value = "当前登录人", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "senderId", value = "聊天对方", dataType = "String", paramType = "query")})
     @GetMapping("/getMessageListByReceiverId")
     public R<JSONObject> getMessageListByReceiverId(@RequestParam String receiverId, @RequestParam String senderId) throws Exception {
         log.info("LifeMessageController.getMessageListByReceiverId?receiverId={}, senderId={}", receiverId, senderId);
@@ -71,9 +63,7 @@ public class LifeMessageController {
 
     @ApiOperation("是否是陌生人")
     @ApiOperationSupport(order = 5)
-    @ApiImplicitParams({
-            @ApiImplicitParam(name = "receiverId", value = "当前登录人", dataType = "String", paramType = "query"),
-            @ApiImplicitParam(name = "senderId", value = "聊天对方", dataType = "String", paramType = "query")})
+    @ApiImplicitParams({@ApiImplicitParam(name = "receiverId", value = "当前登录人", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "senderId", value = "聊天对方", dataType = "String", paramType = "query")})
     @GetMapping("/isStranger")
     public R<String> isStranger(@RequestParam String receiverId, @RequestParam String senderId) throws Exception {
         log.info("LifeMessageController.isStranger?receiverId={}, senderId={}", receiverId, senderId);
@@ -82,9 +72,7 @@ public class LifeMessageController {
 
     @ApiOperation("消息已读")
     @ApiOperationSupport(order = 6)
-    @ApiImplicitParams({
-            @ApiImplicitParam(name = "receiverId", value = "当前登录人", dataType = "String", paramType = "query"),
-            @ApiImplicitParam(name = "senderId", value = "聊天对方", dataType = "String", paramType = "query")})
+    @ApiImplicitParams({@ApiImplicitParam(name = "receiverId", value = "当前登录人", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "senderId", value = "聊天对方", dataType = "String", paramType = "query")})
     @GetMapping("/read")
     public R<Boolean> read(@RequestParam String receiverId, @RequestParam String senderId) throws Exception {
         log.info("LifeMessageController.read?receiverId={}, senderId={}", receiverId, senderId);
@@ -94,9 +82,7 @@ public class LifeMessageController {
 
     @ApiOperation("删除消息")
     @ApiOperationSupport(order = 7)
-    @ApiImplicitParams({
-            @ApiImplicitParam(name = "senderId", value = "聊天对方", dataType = "String", paramType = "query"),
-            @ApiImplicitParam(name = "receiverId", value = "当前登录人", dataType = "String", paramType = "query")})
+    @ApiImplicitParams({@ApiImplicitParam(name = "senderId", value = "聊天对方", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "receiverId", value = "当前登录人", dataType = "String", paramType = "query")})
     @GetMapping("/deleteMessageByPhoneId")
     public R<Integer> deleteMessageByPhoneId(@RequestParam String senderId, @RequestParam String receiverId) throws Exception {
         log.info("LifeMessageController.deleteMessageByPhoneId?senderId={},receiverId={}", senderId, receiverId);
@@ -120,4 +106,12 @@ public class LifeMessageController {
         log.info("LifeMessageController.noReadCount?receiverId={}", receiverId);
         return R.data(lifeMessageService.noReadCount(receiverId));
     }
+
+    @ApiOperation("聊过天的用户信息")
+    @ApiOperationSupport(order = 10)
+    @GetMapping("/getTalkedUserList")
+    public R<List<LifeFansVo>> getTalkedUserList() throws Exception {
+        log.info("LifeMessageController.getTalkedUserList");
+        return R.data(lifeMessageService.getTalkedUserList());
+    }
 }

+ 47 - 8
alien-store/src/main/java/shop/alien/store/controller/PlatformStoreCouponController.java

@@ -7,7 +7,9 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.bind.annotation.*;
 import shop.alien.entity.result.R;
 import shop.alien.entity.store.LifeCoupon;
+import shop.alien.entity.store.LifeGroupBuyMain;
 import shop.alien.entity.store.vo.LifeCouponVo;
+import shop.alien.entity.store.vo.LifeGroupBuyMainVo;
 import shop.alien.store.service.PlatformStoreCouponService;
 
 import java.io.IOException;
@@ -22,7 +24,7 @@ public class PlatformStoreCouponController {
 
     private final PlatformStoreCouponService platformStoreCouponService;
 
-    @ApiOperation("套餐/代金券列表")
+    @ApiOperation("代金券列表")
     @ApiOperationSupport(order = 1)
     @ApiImplicitParams({@ApiImplicitParam(name = "page", value = "分页页数", dataType = "Integer", paramType = "query", required = true),
             @ApiImplicitParam(name = "size", value = "分页条数", dataType = "Integer", paramType = "query", required = true),
@@ -38,6 +40,33 @@ public class PlatformStoreCouponController {
         return R.data(platformStoreCouponService.getCouponList(page, size, storeName, status, createdTime, phone, type));
     }
 
+    @ApiOperation("web-新套餐列表/查询套餐状态")
+    @ApiOperationSupport(order = 14)
+    @ApiImplicitParams({@ApiImplicitParam(name = "page", value = "分页页数", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "size", value = "分页条数", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "storeName", value = "商家名称", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "phone", value = "手机号", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "createdTime", value = "创建时间", dataType = "Date", paramType = "query"),
+            @ApiImplicitParam(name = "status", value = "审核状态", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "expiredState", value = "过期状态", dataType = "String", paramType = "query")
+    })
+    @GetMapping("/getLifeGroupBuyMainList")
+    public R<IPage<LifeGroupBuyMainVo>> getLifeGroupBuyMainList(Integer page, Integer size, String storeName, String status, @RequestParam(value = "createdTime", required = false) String createdTime, String phone, String expiredState) {
+        log.info("PlatformStoreCouponController.getLifeGroupBuyMainList?page={},size={},name={},status={},createdTime={}", page, size, storeName, status, createdTime, phone, expiredState);
+        return R.data(platformStoreCouponService.getLifeGroupBuyMainList(page, size, storeName, status, createdTime, phone, expiredState));
+    }
+
+    @ApiOperation("web-新套餐状态详情")
+    @ApiOperationSupport(order = 16)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "id", dataType = "Integer", paramType = "query")
+    })
+    @GetMapping("/getLifeGroupBuyMainByDetail")
+    public R<LifeGroupBuyMainVo> getLifeGroupBuyMainByDetail(Integer id) {
+        log.info("PlatformStoreCouponController.getLifeGroupBuyMainByDetail?id={}", id);
+        return R.data(platformStoreCouponService.getLifeGroupBuyMainByDetail(id));
+    }
+
     /**
      * web-分页查询店铺信息
      *
@@ -47,7 +76,7 @@ public class PlatformStoreCouponController {
      * @param expiredState 过期状态
      * @return IPage<StoreInfoVo>
      */
-    @ApiOperation("web-分页查询套餐状态")
+    @ApiOperation("web-分页查询代金券状态")
     @ApiOperationSupport(order = 7)
     @ApiImplicitParams({
             @ApiImplicitParam(name = "pageNum", value = "页数", dataType = "int", paramType = "query", required = true),
@@ -75,6 +104,15 @@ public class PlatformStoreCouponController {
         return R.data(platformStoreCouponService.couponStatusExport(status, expiredState));
     }
 
+    @ApiOperation("web-新导出套餐状态Excel")
+    @ApiOperationSupport(order = 15)
+    @GetMapping("/lifeGroupBuyMainStatusExport")
+    public R lifeGroupBuyMainStatusExport(@RequestParam(required = false) String status,
+                                @RequestParam(required = false) String expiredState) throws IOException {
+        log.info("PlatformStoreCouponController.lifeGroupBuyMainStatusExport");
+        return R.data(platformStoreCouponService.lifeGroupBuyMainStatusExport(status, expiredState));
+    }
+
     @ApiOperation("web-套餐状态删除")
     @ApiOperationSupport(order = 11)
     @GetMapping("/deleteCouponStatus")
@@ -83,7 +121,7 @@ public class PlatformStoreCouponController {
         return platformStoreCouponService.deleteCouponStatus(id);
     }
 
-    @ApiOperation("套餐/代金券详情")
+    @ApiOperation("代金券详情")
     @ApiOperationSupport(order = 2)
     @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "主键id", dataType = "Integer", paramType = "query", required = true)})
     @GetMapping("/getCouponById")
@@ -92,15 +130,16 @@ public class PlatformStoreCouponController {
         return R.data(platformStoreCouponService.getCouponById(id));
     }
 
-    @ApiOperation("套餐/代金券审核")
+    @ApiOperation("web-套餐/代金券审核")
     @ApiOperationSupport(order = 2)
     @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "主键id", dataType = "Integer", paramType = "query", required = true),
             @ApiImplicitParam(name = "status", value = "状态", dataType = "String", paramType = "query"),
-            @ApiImplicitParam(name = "comment", value = "审批意见", dataType = "String", paramType = "query")})
+            @ApiImplicitParam(name = "comment", value = "审批意见", dataType = "String", paramType = "query"),
+            @ApiImplicitParam(name = "type", value = "代金券/套餐类型 0:代金券 1:套餐", dataType = "String", paramType = "query")})
     @GetMapping("/approvalCoupon")
-    public R<Integer> approvalCoupon(Integer id, Integer status, String comment) {
-        log.info("PlatformStoreCouponController.approvalCoupon?id={},status={},comment={}", id, status, comment);
-        return R.data(platformStoreCouponService.approvalCoupon(id, status, comment));
+    public R<Integer> approvalCoupon(Integer id, Integer status, String comment, String type) {
+        log.info("PlatformStoreCouponController.approvalCoupon?id={},status={},comment={}type={}", id, status, comment, type);
+        return R.data(platformStoreCouponService.approvalCoupon(id, status, comment, type));
     }
 
 }

+ 28 - 6
alien-store/src/main/java/shop/alien/store/controller/StoreIncomeDetailsRecordController.java

@@ -44,6 +44,32 @@ public class StoreIncomeDetailsRecordController {
         return storeIncomeDetailsRecordService.cashOut(storeId, payPassword, withdrawalMoney);
     }
 
+    @ApiOperation("提现申请-提现全部")
+    @ApiOperationSupport(order = 2)
+    @ApiImplicitParams({@ApiImplicitParam(name = "storeId", value = "门店id", dataType = "Integer", paramType = "query", required = true), @ApiImplicitParam(name = "payPassword", value = "支付密码", dataType = "String", paramType = "query", required = true)})
+    @GetMapping("/applyCashOut")
+    public R<Boolean> applyCashOut(Integer storeId, String payPassword) {
+        String s = storeIncomeDetailsRecordService.applyCashOut(storeId, payPassword);
+        if ("success".equals(s)) {
+            return R.success("提现成功");
+        }
+        return R.fail(s);
+    }
+
+    @ApiOperation("提现审批-提现全部")
+    @ApiOperationSupport(order = 2)
+    @ApiImplicitParams({@ApiImplicitParam(name = "cashOutId", value = "提现申请记录ID", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "approveStatus", value = "审批状态", dataType = "String", paramType = "query", required = true),
+            @ApiImplicitParam(name = "failReason", value = "失败原因", dataType = "String", paramType = "query", required = false)})
+    @GetMapping("/approveCashOut")
+    public R<Boolean> approveCashOut(Integer cashOutId, String approveStatus, String failReason) {
+        String s = storeIncomeDetailsRecordService.approveCashOut(cashOutId, approveStatus, failReason);
+        if ("success".equals(s)) {
+            return R.success("提现成功");
+        }
+        return R.fail(s);
+    }
+
     @ApiOperation("新增收入-手续费一单一算")
     @ApiOperationSupport(order = 2)
     @PostMapping("/addIncome")
@@ -56,9 +82,7 @@ public class StoreIncomeDetailsRecordController {
 
     @ApiOperation("今日收益")
     @ApiOperationSupport(order = 3)
-    @ApiImplicitParams({
-            @ApiImplicitParam(name = "storeId", value = "门店id", dataType = "Integer", paramType = "query", required = true)
-    })
+    @ApiImplicitParams({@ApiImplicitParam(name = "storeId", value = "门店id", dataType = "Integer", paramType = "query", required = true)})
     @GetMapping("/todayIncome")
     public R<String> todayIncome(Integer storeId) {
         return R.data(storeIncomeDetailsRecordService.todayIncome(storeId));
@@ -84,9 +108,7 @@ public class StoreIncomeDetailsRecordController {
 
     @ApiOperation("账户余额-总金额, 可提现金额")
     @ApiOperationSupport(order = 5)
-    @ApiImplicitParams({
-            @ApiImplicitParam(name = "storeId", value = "门店id", dataType = "Integer", paramType = "query", required = true)
-    })
+    @ApiImplicitParams({@ApiImplicitParam(name = "storeId", value = "门店id", dataType = "Integer", paramType = "query", required = true)})
     @GetMapping("/accountBalance")
     public R<Map<String, Object>> accountBalance(Integer storeId) {
         return R.data(storeIncomeDetailsRecordService.accountBalance(storeId));

+ 4 - 3
alien-store/src/main/java/shop/alien/store/controller/StoreInfoController.java

@@ -487,7 +487,7 @@ public class StoreInfoController {
      */
     @ApiOperation("新八大类用户端筛选")
     @PostMapping(value = "getScreeningNew")
-    public R<IPage<StoreInfo>> getScreeningNew(@RequestBody ScreeningOfEightMajorCategoriesVO screeningOfEightMajorCategoriesVO) {
+    public R<IPage<StoreInfoVo>> getScreeningNew(@RequestBody ScreeningOfEightMajorCategoriesVO screeningOfEightMajorCategoriesVO) {
         // 参数校验
         if (screeningOfEightMajorCategoriesVO == null) {
             return R.fail("筛选参数不能为空");
@@ -505,7 +505,7 @@ public class StoreInfoController {
 
         try {
             // 调用服务层获取筛选结果
-            IPage<StoreInfo> result = storeInfoService.getScreeningNew(screeningOfEightMajorCategoriesVO);
+            IPage<StoreInfoVo> result = storeInfoService.getScreeningNew(screeningOfEightMajorCategoriesVO);
 
             // 记录响应日志
             log.info("新八大类用户端筛选响应 - 总记录数: {}, 当前页: {}, 页大小: {}",
@@ -517,7 +517,8 @@ public class StoreInfoController {
             return R.fail(e.getMessage());
         } catch (Exception e) {
             log.error("新八大类用户端筛选异常", e);
-            return R.fail("筛选失败,请稍后重试");
+            return R.data(null);
+            //return R.fail("筛选失败,请稍后重试");
         }
     }
 

+ 1 - 0
alien-store/src/main/java/shop/alien/store/controller/WebSocketController.java

@@ -64,6 +64,7 @@ public class WebSocketController {
     @GetMapping(value = "/sendMsgToClientByPhoneId")
     public R<Boolean> sendMsgToClientByPhoneId(String messageReceiverId, String webSocketVoStr) {
         try {
+            log.info("WebSocketController.sendMsgToClientByPhoneId?messageReceiverId={}, webSocketVoStr={}", messageReceiverId, webSocketVoStr);
             webSocketProcess.sendMessage(messageReceiverId, webSocketVoStr);
             return R.success("发送成功");
         } catch (Exception e) {

+ 11 - 21
alien-store/src/main/java/shop/alien/store/service/LifeAppealManageService.java

@@ -4,25 +4,28 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import lombok.RequiredArgsConstructor;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
-import org.springframework.util.StringUtils;
 import shop.alien.entity.store.LifeAppealManage;
 import shop.alien.entity.store.LifeNotice;
 import shop.alien.entity.store.StoreComment;
 import shop.alien.entity.store.StoreCommentAppeal;
 import shop.alien.entity.store.dto.LifeAppealManageDto;
 import shop.alien.entity.store.excelVo.LifeAppealManageExcelVo;
+import shop.alien.entity.store.excelVo.StoreInfoExcelVo;
 import shop.alien.entity.store.excelVo.util.ExcelGenerator;
 import shop.alien.entity.store.vo.LifeAppealManageVo;
 import shop.alien.mapper.LifeAppealManageMapper;
 import shop.alien.mapper.LifeNoticeMapper;
 import shop.alien.mapper.StoreCommentAppealMapper;
 import shop.alien.mapper.StoreCommentMapper;
+import shop.alien.util.ali.AliOSSUtil;
 
+import java.io.File;
 import java.io.IOException;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
@@ -45,6 +48,7 @@ public class LifeAppealManageService {
 
     private final StoreCommentMapper storeCommentMapper;
 
+    private final AliOSSUtil aliOSSUtil;
 
     @Value("${spring.web.resources.excel-path}")
     private String excelPath;
@@ -52,9 +56,6 @@ public class LifeAppealManageService {
     @Value("${spring.web.resources.excel-generate-path}")
     private String excelGeneratePath;
 
-    @Value("${spring.web.resources.url}")
-    private String fileUrl;
-
     public IPage<LifeAppealManageVo> getStores(int page, int size, String storeName, String storeContact, String storePhone, String appealType) {
         IPage<LifeAppealManageVo> storePage = new Page<>(page, size);
         return lifeAppealManageMapper.getAppealManagement(storePage, storeName, storeContact, storePhone, appealType);
@@ -80,7 +81,6 @@ public class LifeAppealManageService {
             queryWrapper.eq(StoreComment::getId, storeCommentAppeal.getCommentId());
             storeCommentMapper.delete(queryWrapper);
         }
-
         LifeNotice notice = new LifeNotice();
         if (lifeAppealManageDto.getAppealType().equals("1")) {
             notice.setContext("系统同意了您的申请");
@@ -91,7 +91,6 @@ public class LifeAppealManageService {
         notice.setNoticeType(1);
         lifeNoticeMapper.insert(notice);
         return storeCommentAppealMapper.updateById(storeCommentAppeal);
-
     }
 
     public int setIsRead(String id) {
@@ -102,10 +101,6 @@ public class LifeAppealManageService {
         return lifeAppealManageMapper.update(null, updateWrapper);
     }
 
-    public List<LifeAppealManage> getAllList() {
-        return lifeAppealManageMapper.selectList(new LambdaQueryWrapper<>());
-    }
-
     public List<LifeAppealManage> getAppealByStoreId(String storeId) {
         LambdaUpdateWrapper<LifeAppealManage> wrapper = new LambdaUpdateWrapper<>();
         wrapper.eq(LifeAppealManage::getStoreId, storeId)
@@ -135,14 +130,12 @@ public class LifeAppealManageService {
 
     public String appealsExport(String appealType, String storeName, String storePhone) throws IOException {
         QueryWrapper<LifeAppealManage> wrapper = new QueryWrapper<>();
-
-        wrapper.eq(com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotEmpty(appealType), "appeal_status", appealType);
-        wrapper.like(com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotEmpty(storeName), "store_name", storeName);
-        wrapper.like(com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotEmpty(storePhone), "store_phone", storePhone);
+        wrapper.eq(StringUtils.isNotEmpty(appealType), "appeal_status", appealType);
+        wrapper.like(StringUtils.isNotEmpty(storeName), "store_name", storeName);
+        wrapper.like(StringUtils.isNotEmpty(storePhone), "store_phone", storePhone);
         wrapper.eq("delete_flag", 0);
         wrapper.orderByDesc("created_time");
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy/M/d HH:mm:ss");
-
         List<LifeAppealManageVo> storeStaffConfig = lifeAppealManageMapper.getAppealManagement(storeName, storePhone, appealType, null);
         storeStaffConfig.forEach(item -> {
             if ("0".equals(item.getAppealType())) {
@@ -152,13 +145,10 @@ public class LifeAppealManageService {
             } else {
                 item.setAppealType("已驳回");
             }
-
         });
-
         List<LifeAppealManageExcelVo> storeStaffConfigs = new ArrayList<>();
         int index = 1;
         for (LifeAppealManage record : storeStaffConfig) {
-
             LifeAppealManageExcelVo storeCouponStatusVo = new LifeAppealManageExcelVo();
             BeanUtils.copyProperties(record, storeCouponStatusVo);
             storeCouponStatusVo.setId(index++); // 设置序号
@@ -166,8 +156,8 @@ public class LifeAppealManageService {
             storeStaffConfigs.add(storeCouponStatusVo);
         }
         String fileName = UUID.randomUUID().toString().replace("-", "");
-
-        ExcelGenerator.generateExcel(excelPath + excelGeneratePath + fileName + ".xlsx", storeStaffConfigs, LifeAppealManageExcelVo.class);
-        return fileUrl + "excel" + excelGeneratePath + fileName + ".xlsx";
+        String filePath = ExcelGenerator.generateExcel(excelPath + excelGeneratePath + fileName + ".xlsx", storeStaffConfigs, LifeAppealManageExcelVo.class);
+        String url = aliOSSUtil.uploadFile(new File(filePath), "excel/" + fileName + ".xlsx");
+        return url;
     }
 }

+ 2 - 2
alien-store/src/main/java/shop/alien/store/service/LifeDiscountCouponService.java

@@ -65,12 +65,12 @@ public interface LifeDiscountCouponService extends IService<LifeDiscountCoupon>
     /**
      * 获取所有优惠券列表(分页)
      */
-    public IPage<LifeDiscountCouponVo> getStoreAllCouponList(String storeId, UserLoginInfo userLoginInfo, int page, int size, String couponName, String tab, int couponsFromType);
+    public IPage<LifeDiscountCouponVo> getStoreAllCouponList(String storeId, UserLoginInfo userLoginInfo, int page, int size, String couponName, String tab, int couponsFromType, int couponStatus);
 
     /**
      * 获取所有优惠券列表(不分页)
      */
-    public List<LifeDiscountCouponVo> getStoreAllCouponListPaginateNot(String status, String storeId, UserLoginInfo userLoginInfo);
+    public List<LifeDiscountCouponVo> getStoreAllCouponListPaginateNot(String status, String storeId, UserLoginInfo userLoginInfo, int couponStatus);
 
     /**
      * 获取优惠券规则

+ 2 - 0
alien-store/src/main/java/shop/alien/store/service/LifeMessageService.java

@@ -4,6 +4,7 @@ import com.alibaba.fastjson2.JSONObject;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
 import shop.alien.entity.store.LifeMessage;
+import shop.alien.entity.store.vo.LifeFansVo;
 import shop.alien.entity.store.vo.LifeMessageVo;
 
 import java.util.List;
@@ -28,4 +29,5 @@ public interface LifeMessageService extends IService<LifeMessage> {
 
     int getAllNoReadCount(String receiverId) throws Exception;
 
+    List<LifeFansVo> getTalkedUserList() throws Exception;
 }

+ 10 - 42
alien-store/src/main/java/shop/alien/store/service/LifeUserOrderService.java

@@ -10,13 +10,15 @@ import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import shop.alien.entity.store.*;
 import shop.alien.entity.store.excelVo.LifeUserOrderExcelVo;
+import shop.alien.entity.store.excelVo.StoreInfoExcelVo;
 import shop.alien.entity.store.excelVo.util.ExcelGenerator;
 import shop.alien.entity.store.vo.StoreInfoVo;
-import shop.alien.store.config.GaoDeMapUtil;
 import shop.alien.mapper.*;
-import shop.alien.store.service.impl.StoreUserServiceImpl;
+import shop.alien.store.config.GaoDeMapUtil;
+import shop.alien.util.ali.AliOSSUtil;
 import shop.alien.util.common.AlipayTradeRefund;
 
+import java.io.File;
 import java.io.IOException;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
@@ -57,8 +59,10 @@ public class LifeUserOrderService {
     private final LifeNoticeMapper lifeNoticeMapper;
 
     private final StoreImgMapper storeImgMapper;
+
     private final StoreUserMapper storeUserMapper;
-    private final StoreUserServiceImpl storeUserService;
+
+    private final AliOSSUtil aliOSSUtil;
 
     @Value("${spring.web.resources.excel-path}")
     private String excelPath;
@@ -388,18 +392,6 @@ public class LifeUserOrderService {
             returnMap.put("success", "退款失败");
             return returnMap;
         }
-
-        // 添加审核锚点
-//        WebAudit webAudit = new WebAudit();
-//        webAudit.setId(refundOrder.getOrderId());
-//        webAudit.setType("2");
-//        webAudit.setContent(order.getOrderNo());
-//        Integer i = webAuditService.platformAuditRefundTrack(webAudit);
-//        if (!(i > 0)) {
-//            returnMap.put("success", "退款失败");
-//            return returnMap;
-//        }
-
         Date now = new Date();
         order.setStatus(4);
         order.setUpdatedTime(now);
@@ -407,7 +399,6 @@ public class LifeUserOrderService {
         lifeUserOrderMapper.updateById(order);
         refundOrder.setApplicationTime(now);
         refundOrder.setRefundTime(now);
-
         // 将退款记录插入到数据库中
         if (lifeRefundOrderMapper.insert(refundOrder) > 0) {
             returnMap.put("success", "退款成功");
@@ -422,7 +413,6 @@ public class LifeUserOrderService {
             lifeMessage.setNoticeType(2);
             lifeNoticeMapper.insert(lifeMessage);
         }
-
         // 券核销完成后,退款的情况下,需要向 store_income_details_record 表插入一条记录
         if (null != refundOrder.getStoreId()) {
             BigDecimal amounts = new BigDecimal(refundOrder.getAmount()).multiply(new BigDecimal(100));
@@ -474,15 +464,11 @@ public class LifeUserOrderService {
         // 定义格式化模式
         DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
         List<LifeUserOrderExcelVo> lifeUserOrderExcelVos = new ArrayList<>();
-
-        String fileName = UUID.randomUUID().toString().replace("-", "");
-
         LambdaUpdateWrapper<LifeUserOrder> wrapper = new LambdaUpdateWrapper<>();
         wrapper.eq(StringUtils.isNotEmpty(status), LifeUserOrder::getStatus, status);
         wrapper.like(StringUtils.isNotEmpty(orderNo), LifeUserOrder::getOrderNo, orderNo);
         wrapper.like(StringUtils.isNotEmpty(storeId), LifeUserOrder::getStoreId, storeId);
 
-        List<LifeUserOrder> lifeUserOrders = new ArrayList<>();
         boolean flag = true;
         if (StringUtils.isNotEmpty(quanName)) {
             LambdaUpdateWrapper<LifeCoupon> wrapper1 = new LambdaUpdateWrapper<>();
@@ -497,26 +483,15 @@ public class LifeUserOrderService {
         }
         if (flag) {
             wrapper.orderByAsc(LifeUserOrder::getStatus).orderByDesc(LifeUserOrder::getUpdatedTime);
-            lifeUserOrders = lifeUserOrderMapper.selectList(wrapper);
         }
-
         List<Map<String, Object>> orderNoPage = lifeUserOrderMapper.selectMaps(wrapper);
         List<Object> orderNos = orderNoPage.stream()
                 .map(record -> record.get("order_no"))
                 .collect(Collectors.toList());
-
-
-        // 如果没有订单号,直接返回
-//        if (CollectionUtils.isEmpty(orderNos)) {
-//            iPage.setRecords(returnList);
-//            return iPage;
-//        }
-
         // 根据订单号列表查询所有相关订单明细
         LambdaQueryWrapper<LifeUserOrder> detailWrapper = new LambdaQueryWrapper<>();
         detailWrapper.in(LifeUserOrder::getOrderNo, orderNos);
         List<LifeUserOrder> allOrderDetails = lifeUserOrderMapper.selectList(detailWrapper);
-
         // 按订单号分组处理
         Map<String, List<LifeUserOrder>> orderDetailsGrouped = allOrderDetails.stream()
                 .collect(Collectors.groupingBy(LifeUserOrder::getOrderNo));
@@ -528,7 +503,6 @@ public class LifeUserOrderService {
             LifeCoupon quan = lifeCouponMapper.selectById(lifeUserOrder.getQuanId());
             QueryWrapper<StoreInfoVo> queryWrapper = new QueryWrapper<>();
             queryWrapper.eq("a.id", lifeUserOrder.getStoreId());
-
             StoreInfoVo storeInfoVoOne = storeInfoMapper.getStoreInfoVoOne(queryWrapper);
             LifeUserOrderExcelVo lifeUserOrderExcelVo = new LifeUserOrderExcelVo();
             lifeUserOrderExcelVo.setSerialNumber(++serialNumber);
@@ -539,17 +513,12 @@ public class LifeUserOrderService {
             lifeUserOrderExcelVo.setPrice("¥" + quan.getPrice());
             lifeUserOrderExcelVo.setStoreContact(storeInfoVoOne.getStoreContact());
             lifeUserOrderExcelVo.setPhone(storeInfoVoOne.getStorePhone());
-
-
             Instant instant = lifeUserOrder.getPayTime().toInstant();
             // 格式化时间
             String formattedTime = instant.atZone(ZoneId.systemDefault()).toLocalDateTime().format(formatter);
             lifeUserOrderExcelVo.setPayTime(formattedTime);
-
             lifeUserOrderExcelVo.setFinishTime(formattedTime);
-
             lifeUserOrderExcelVo.setOrderStatus(String.valueOf(lifeUserOrder.getStatus()));
-
             // 订单状态转换
             switch (lifeUserOrder.getStatus()) {
                 case 0:
@@ -576,11 +545,10 @@ public class LifeUserOrderService {
                 default:
                     lifeUserOrderExcelVo.setOrderStatus("未知状态");
             }
-
             lifeUserOrderExcelVos.add(lifeUserOrderExcelVo);
         }
-
-        ExcelGenerator.generateExcel(excelPath + excelGeneratePath + fileName + ".xlsx", lifeUserOrderExcelVos, LifeUserOrderExcelVo.class);
-        return fileUrl + "excel" + excelGeneratePath + fileName + ".xlsx";
+        String fileName = UUID.randomUUID().toString().replace("-", "");
+        String filePath = ExcelGenerator.generateExcel(excelPath + excelGeneratePath + fileName + ".xlsx", lifeUserOrderExcelVos, LifeUserOrderExcelVo.class);
+        return aliOSSUtil.uploadFile(new File(filePath), "excel/" + fileName + ".xlsx");
     }
 }

+ 1 - 1
alien-store/src/main/java/shop/alien/store/service/LifeUserStoreService.java

@@ -74,7 +74,7 @@ public class LifeUserStoreService {
             // 过滤已删除的门店
             wrapper.eq("a.delete_flag", 0);
             // 过滤非营业中的门店
-            wrapper.in(null != storeType && !"".equals(storeType), "a.business_section", Arrays.asList(storeType.split(",")));
+            wrapper.in(null != storeType && !"".equals(storeType), "a.store_type", Arrays.asList(storeType.split(",")));
             // 过滤掉永久关门的店铺
             wrapper.ne("a.business_status", 99);
             // 根据构建的条件查询门店信息

+ 9 - 2
alien-store/src/main/java/shop/alien/store/service/PlatformStoreCouponService.java

@@ -3,6 +3,7 @@ package shop.alien.store.service;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import shop.alien.entity.store.LifeCoupon;
 import shop.alien.entity.store.vo.LifeCouponVo;
+import shop.alien.entity.store.vo.LifeGroupBuyMainVo;
 
 import java.io.IOException;
 
@@ -10,13 +11,19 @@ public interface PlatformStoreCouponService {
 
     IPage<LifeCouponVo> getCouponList(Integer page, Integer size, String storeName, String status, String createdTime, String phone, String type);
 
+    IPage<LifeGroupBuyMainVo> getLifeGroupBuyMainList(Integer page, Integer size, String storeName, String status, String createdTime, String phone, String expiredState);
+
     IPage<LifeCouponVo> getCouponStatusList(Integer page, Integer size, String status, String expiredState);
 
     LifeCouponVo getCouponById(Integer id);
 
-    int approvalCoupon(Integer id, Integer status, String comment);
+    int approvalCoupon(Integer id, Integer status, String comment, String type);
+
+    String couponStatusExport(String status, String expiredState) throws IOException;
 
-    String couponStatusExport(String status, String expiredState) throws IOException;;
+    String lifeGroupBuyMainStatusExport(String status, String expiredState) throws IOException;
 
     int deleteCouponStatus(Integer id);
+
+    LifeGroupBuyMainVo getLifeGroupBuyMainByDetail(Integer id);
 }

+ 16 - 0
alien-store/src/main/java/shop/alien/store/service/StoreIncomeDetailsRecordService.java

@@ -27,6 +27,22 @@ public interface StoreIncomeDetailsRecordService extends IService<StoreIncomeDet
     R cashOut(Integer storeId, String payPassword, Integer money);
 
     /**
+     * 提现
+     *
+     * @param storeId     门店id
+     * @return 是否成功
+     */
+    String applyCashOut(Integer storeId, String payPassword);
+
+    /**
+     * 提现审批
+     *
+     * @param cashOutId     提现申请记录ID
+     * @param approveStatus 审批状态
+     */
+    String approveCashOut(Integer cashOutId, String approveStatus, String failReason);
+
+    /**
      * 今日收益
      *
      * @param storeId 门店id

+ 1 - 1
alien-store/src/main/java/shop/alien/store/service/StoreInfoService.java

@@ -189,7 +189,7 @@ public interface StoreInfoService extends IService<StoreInfo> {
      * 八大类用户端筛选
      */
     IPage<StoreInfo> getScreening(ScreeningOfEightMajorCategoriesVO screeningOfEightMajorCategoriesVO);
-    IPage<StoreInfo> getScreeningNew(ScreeningOfEightMajorCategoriesVO screeningOfEightMajorCategoriesVO);
+    IPage<StoreInfoVo> getScreeningNew(ScreeningOfEightMajorCategoriesVO screeningOfEightMajorCategoriesVO);
 
     List<StoreInfo> getBusinessTypesName(String businessTypesNames);
 

+ 198 - 82
alien-store/src/main/java/shop/alien/store/service/impl/LifeDiscountCouponServiceImpl.java

@@ -69,21 +69,39 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
 
     @Override
     public boolean addDiscountCoupon(LifeDiscountCouponDto lifeDiscountCouponDto) {
-
         try {
             //发布优惠券表信息
             LifeDiscountCoupon lifeDiscountCoupon = new LifeDiscountCoupon();
             BeanUtils.copyProperties(lifeDiscountCouponDto, lifeDiscountCoupon);
             // 根据开始领取时间判断可领取状态
             // 判断是否在领取时间内
+
             Date now = new Date();
             Instant instant = now.toInstant();
             ZoneId zoneId = ZoneId.systemDefault();
             LocalDate localNow = instant.atZone(zoneId).toLocalDate();
-            int startResult = localNow.compareTo(lifeDiscountCoupon.getBeginGetDate());
-            int endResult = localNow.compareTo(lifeDiscountCoupon.getEndGetDate());
-            if (startResult < 0 || endResult > 0) {
-                lifeDiscountCoupon.setGetStatus(0);
+            if (lifeDiscountCouponDto.getCouponStatus() == 1 && !StringUtils.isEmpty(lifeDiscountCoupon.getBeginGetDate()) || !StringUtils.isEmpty(lifeDiscountCoupon.getEndGetDate())) {
+                int startResult = localNow.compareTo(lifeDiscountCoupon.getBeginGetDate());
+                int endResult = localNow.compareTo(lifeDiscountCoupon.getEndGetDate());
+                if ((lifeDiscountCouponDto.getCouponStatus() != null && lifeDiscountCouponDto.getCouponStatus() == 0) || (startResult < 0 || endResult > 0)) {
+                    lifeDiscountCoupon.setGetStatus(0);
+                } else {
+                    lifeDiscountCoupon.setGetStatus(1);
+                }
+            }
+
+            // 设置有效期
+            String specifiedDay = lifeDiscountCoupon.getSpecifiedDay();
+            if(!StringUtils.isEmpty(specifiedDay)){
+                int sDay = Integer.parseInt(specifiedDay);
+                if(sDay > 0 && lifeDiscountCouponDto.getBeginGetDate() != null){
+                    Date beginGetDate = Date.from(lifeDiscountCouponDto.getBeginGetDate().atStartOfDay(ZoneId.systemDefault()).toInstant());
+                    Date validDate = addDaysToDateJava8(beginGetDate, sDay);
+                    LocalDate validDateLocalDate = validDate.toInstant()
+                            .atZone(ZoneId.systemDefault())
+                            .toLocalDate();
+                    lifeDiscountCoupon.setValidDate(validDateLocalDate);
+                }
             }
             lifeDiscountCouponMapper.insert(lifeDiscountCoupon);
             //发布优惠券规则信息
@@ -91,16 +109,22 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
             LifeDiscountCouponUnavailableRules lifeDiscountCouponUnavailableRules = new LifeDiscountCouponUnavailableRules();
             lifeDiscountCouponUnavailableRules.setDiscountCouponId(lifeDiscountCoupon.getId());
             lifeDiscountCouponUnavailableRules.setUnavailableRuleType(DiscountCouponEnum.WEEKDAY_UNAVAILABLE.getValue());
-            lifeDiscountCouponDto.getWeeklyDisabledList().forEach(weeklyDisabled -> {
-                lifeDiscountCouponUnavailableRules.setUnavailableRuleValue(weeklyDisabled);
-                lifeDiscountCouponUnavailableRulesMapper.insert(lifeDiscountCouponUnavailableRules);
-            });
+            if(CollectionUtils.isNotEmpty(lifeDiscountCouponDto.getWeeklyDisabledList())) {
+                lifeDiscountCouponDto.getWeeklyDisabledList().forEach(weeklyDisabled -> {
+                    lifeDiscountCouponUnavailableRules.setUnavailableRuleValue(weeklyDisabled);
+                    lifeDiscountCouponUnavailableRulesMapper.insert(lifeDiscountCouponUnavailableRules);
+                });
+            }
+
             //节假日规则保存
             lifeDiscountCouponUnavailableRules.setUnavailableRuleType(DiscountCouponEnum.HOLIDAY_UNAVAILABLE.getValue());
-            lifeDiscountCouponDto.getHolidayDisabledList().forEach(holidayDisabled -> {
-                lifeDiscountCouponUnavailableRules.setUnavailableRuleValue(holidayDisabled);
-                lifeDiscountCouponUnavailableRulesMapper.insert(lifeDiscountCouponUnavailableRules);
-            });
+            if(CollectionUtils.isNotEmpty(lifeDiscountCouponDto.getHolidayDisabledList())){
+                lifeDiscountCouponDto.getHolidayDisabledList().forEach(holidayDisabled -> {
+                    lifeDiscountCouponUnavailableRules.setUnavailableRuleValue(holidayDisabled);
+                    lifeDiscountCouponUnavailableRulesMapper.insert(lifeDiscountCouponUnavailableRules);
+                });
+            }
+
             //领取规则
             lifeDiscountCouponUnavailableRules.setUnavailableRuleType(DiscountCouponEnum.CLAIM_RULE.getValue());
             String claimRule = lifeDiscountCouponDto.getClaimRule();
@@ -110,6 +134,7 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
             }
             lifeDiscountCouponUnavailableRules.setUnavailableRuleValue(lifeDiscountCouponDto.getClaimRule());
             lifeDiscountCouponUnavailableRulesMapper.insert(lifeDiscountCouponUnavailableRules);
+
             //指定时间段可用规则
             List<LifeDiscountCouponQuantumRules> availableTimeQuantumList =  lifeDiscountCouponDto.getAvailableTimeQuantum();
             if(CollectionUtils.isNotEmpty(availableTimeQuantumList)){
@@ -118,6 +143,7 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
                 });
                 lifeDiscountCouponQuantumRulesService.saveBatch(availableTimeQuantumList);
             }
+
             //自定义时间段不可用规则
             List<LifeDiscountCouponQuantumRules> customizeUnavailableTimeQuantumList =  lifeDiscountCouponDto.getCustomizeUnavailableTimeQuantum();
             if(CollectionUtils.isNotEmpty(customizeUnavailableTimeQuantumList)) {
@@ -127,7 +153,7 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
                 lifeDiscountCouponQuantumRulesService.saveBatch(customizeUnavailableTimeQuantumList);
             }
         } catch (BeansException e) {
-            e.printStackTrace();
+            log.error("LifeDiscountCouponServiceImpl.receiveCoupon ERROR Msg=" + e.getMessage());
             return false;
         }
         return true;
@@ -140,6 +166,39 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
             LifeDiscountCoupon lifeDiscountCoupon = new LifeDiscountCoupon();
             lifeDiscountCoupon.setId(Integer.parseInt(lifeDiscountCouponDto.getCouponId()));
             BeanUtils.copyProperties(lifeDiscountCouponDto, lifeDiscountCoupon);
+
+            // 根据开始领取时间判断可领取状态
+            // 判断是否在领取时间内
+            Date now = new Date();
+            Instant instant = now.toInstant();
+            ZoneId zoneId = ZoneId.systemDefault();
+            LocalDate localNow = instant.atZone(zoneId).toLocalDate();
+            if (lifeDiscountCouponDto.getCouponStatus() == 1 && !StringUtils.isEmpty(lifeDiscountCoupon.getBeginGetDate()) || !StringUtils.isEmpty(lifeDiscountCoupon.getEndGetDate())) {
+                int startResult = localNow.compareTo(lifeDiscountCoupon.getBeginGetDate());
+                int endResult = localNow.compareTo(lifeDiscountCoupon.getEndGetDate());
+                if ((lifeDiscountCouponDto.getCouponStatus() != null && lifeDiscountCouponDto.getCouponStatus() == 0) || (startResult < 0 || endResult > 0)) {
+                    lifeDiscountCoupon.setGetStatus(0);
+                } else {
+                    lifeDiscountCoupon.setGetStatus(1);
+                }
+            } else if (lifeDiscountCouponDto.getCouponStatus() == 0) {
+                lifeDiscountCoupon.setGetStatus(0);
+            }
+
+            // 设置有效期
+            String specifiedDay = lifeDiscountCouponDto.getSpecifiedDay();
+            if(!StringUtils.isEmpty(specifiedDay)){
+                int sDay = Integer.parseInt(specifiedDay);
+                if(sDay > 0 && lifeDiscountCouponDto.getBeginGetDate() != null) {
+                    Date beginGetDate = Date.from(lifeDiscountCouponDto.getBeginGetDate().atStartOfDay(ZoneId.systemDefault()).toInstant());
+                    Date validDate = addDaysToDateJava8(beginGetDate, sDay);
+                    LocalDate validDateLocalDate = validDate.toInstant()
+                            .atZone(ZoneId.systemDefault())
+                            .toLocalDate();
+                    lifeDiscountCoupon.setValidDate(validDateLocalDate);
+                }
+            }
+
             lifeDiscountCouponMapper.updateById(lifeDiscountCoupon);
             //发布优惠券规则信息
             //先删除之前所有规则
@@ -151,27 +210,33 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
             LifeDiscountCouponUnavailableRules lifeDiscountCouponUnavailableRules = new LifeDiscountCouponUnavailableRules();
             lifeDiscountCouponUnavailableRules.setDiscountCouponId(lifeDiscountCoupon.getId());
             lifeDiscountCouponUnavailableRules.setUnavailableRuleType(DiscountCouponEnum.WEEKDAY_UNAVAILABLE.getValue());
-            lifeDiscountCouponDto.getWeeklyDisabledList().forEach(weeklyDisabled -> {
-                lifeDiscountCouponUnavailableRules.setUnavailableRuleValue(weeklyDisabled);
-                lifeDiscountCouponUnavailableRulesMapper.insert(lifeDiscountCouponUnavailableRules);
-            });
+            if(CollectionUtils.isNotEmpty(lifeDiscountCouponDto.getWeeklyDisabledList())) {
+                lifeDiscountCouponDto.getWeeklyDisabledList().forEach(weeklyDisabled -> {
+                    lifeDiscountCouponUnavailableRules.setUnavailableRuleValue(weeklyDisabled);
+                    lifeDiscountCouponUnavailableRulesMapper.insert(lifeDiscountCouponUnavailableRules);
+                });
+            }
+
             //节假日规则保存
             lifeDiscountCouponUnavailableRules.setUnavailableRuleType(DiscountCouponEnum.HOLIDAY_UNAVAILABLE.getValue());
-            lifeDiscountCouponDto.getHolidayDisabledList().forEach(holidayDisabled -> {
-                lifeDiscountCouponUnavailableRules.setUnavailableRuleValue(holidayDisabled);
-                lifeDiscountCouponUnavailableRulesMapper.insert(lifeDiscountCouponUnavailableRules);
-            });
+            if(CollectionUtils.isNotEmpty(lifeDiscountCouponDto.getHolidayDisabledList())){
+                lifeDiscountCouponDto.getHolidayDisabledList().forEach(holidayDisabled -> {
+                    lifeDiscountCouponUnavailableRules.setUnavailableRuleValue(holidayDisabled);
+                    lifeDiscountCouponUnavailableRulesMapper.insert(lifeDiscountCouponUnavailableRules);
+                });
+            }
+
             //领取规则
             lifeDiscountCouponUnavailableRules.setUnavailableRuleType(DiscountCouponEnum.CLAIM_RULE.getValue());
             lifeDiscountCouponUnavailableRules.setUnavailableRuleValue(lifeDiscountCouponDto.getClaimRule());
             lifeDiscountCouponUnavailableRulesMapper.insert(lifeDiscountCouponUnavailableRules);
 
-            // 删除时间段规则信息
+            // 删除优惠券时间段规则信息
             LambdaQueryWrapper<LifeDiscountCouponQuantumRules> lifeDiscountCouponQuantumRulesLambdaQueryWrapper = new LambdaQueryWrapper<>();
             lifeDiscountCouponQuantumRulesLambdaQueryWrapper.eq(LifeDiscountCouponQuantumRules::getDiscountCouponId, lifeDiscountCoupon.getId());
             lifeDiscountCouponQuantumRulesMapper.delete(lifeDiscountCouponQuantumRulesLambdaQueryWrapper);
 
-            //指定时间段可用规则
+            // 保存指定时间段可用规则
             List<LifeDiscountCouponQuantumRules> availableTimeQuantumList =  lifeDiscountCouponDto.getAvailableTimeQuantum();
             if(CollectionUtils.isNotEmpty(availableTimeQuantumList)){
                 availableTimeQuantumList.forEach(availableTimeQuantum->{
@@ -179,7 +244,7 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
                 });
                 lifeDiscountCouponQuantumRulesService.saveBatch(availableTimeQuantumList);
             }
-            //自定义时间段不可用规则
+            // 保存自定义时间段不可用规则
             List<LifeDiscountCouponQuantumRules> customizeUnavailableTimeQuantumList =  lifeDiscountCouponDto.getCustomizeUnavailableTimeQuantum();
             if(CollectionUtils.isNotEmpty(customizeUnavailableTimeQuantumList)) {
                 customizeUnavailableTimeQuantumList.forEach(customizeUnavailableTimeQuantum->{
@@ -189,7 +254,7 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
             }
 
         } catch (BeansException e) {
-            e.printStackTrace();
+            log.error("LifeDiscountCouponServiceImpl.editDiscountCoupon ERROR Msg=" + e.getMessage());
             return false;
         }
         return true;
@@ -210,14 +275,14 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
         LifeDiscountCoupon lifeDiscountCoupon = lifeDiscountCouponMapper.selectById(counponId);
         lifeDiscountCoupon.setGetStatus(lifeDiscountCoupon.getGetStatus() == Integer.parseInt(DiscountCouponEnum.NO_GET.getValue())
                 ? Integer.parseInt(DiscountCouponEnum.CAN_GET.getValue()) : Integer.parseInt(DiscountCouponEnum.NO_GET.getValue()));
-        Date now = new Date();
-        Instant instant = now.toInstant();
-        ZoneId zoneId = ZoneId.systemDefault();
-        LocalDate localNow = instant.atZone(zoneId).toLocalDate();
-        if (localNow.compareTo(lifeDiscountCoupon.getStartDate()) < 0) {
-            lifeDiscountCoupon.setStartDate(localNow);
-            lifeDiscountCoupon.setGetStatus(Integer.parseInt(DiscountCouponEnum.CAN_GET.getValue()));
-        }
+//        Date now = new Date();
+//        Instant instant = now.toInstant();
+//        ZoneId zoneId = ZoneId.systemDefault();
+//        LocalDate localNow = instant.atZone(zoneId).toLocalDate();
+//        if (localNow.compareTo(lifeDiscountCoupon.getStartDate()) < 0) {
+//            lifeDiscountCoupon.setStartDate(localNow);
+//            lifeDiscountCoupon.setGetStatus(Integer.parseInt(DiscountCouponEnum.CAN_GET.getValue()));
+//        }
         lifeDiscountCouponMapper.updateById(lifeDiscountCoupon);
         return true;
     }
@@ -270,6 +335,18 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
         return lifeDiscountCouponVo;
     }
 
+    public static Date addDaysToDateJava8(Date date, int days) {
+        // 将Date转换为Instant
+        Instant instant = date.toInstant();
+
+        // 转换为LocalDate并加天数
+        LocalDate localDate = instant.atZone(ZoneId.systemDefault()).toLocalDate();
+        LocalDate newLocalDate = localDate.plusDays(days);
+
+        // 转换回Date
+        return Date.from(newLocalDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
+    }
+
     @Override
     public List<LifeDiscountCouponVo> getStoreUserCouponList(String storeId, UserLoginInfo userLoginInfo) {
         List<LifeDiscountCouponVo> lifeDiscountCouponVos = new ArrayList<>();
@@ -279,7 +356,7 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
                         .eq(LifeDiscountCoupon::getStoreId, storeId)
                         .eq(LifeDiscountCoupon::getGetStatus, "1")
                         .gt(LifeDiscountCoupon::getSingleQty, 0) //还有库存
-                        .ge(LifeDiscountCoupon::getEndDate, new Date())
+                        .ge(LifeDiscountCoupon::getEndGetDate, new Date())
                         .orderByDesc(LifeDiscountCoupon::getCreatedTime));
         //根据优惠券列表查询该优惠券是否领取过
         for (LifeDiscountCoupon lifeDiscountCoupon : lifeDiscountCoupons) {
@@ -292,8 +369,13 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
             queryWrapper.eq(LifeDiscountCouponUser::getUserId, userLoginInfo.getUserId());
             queryWrapper.orderByDesc(LifeDiscountCouponUser::getReceiveTime);
             List<LifeDiscountCouponUser> lifeDiscountCouponUsers = lifeDiscountCouponUserMapper.selectList(queryWrapper);
+            String specifiedDay = lifeDiscountCoupon.getSpecifiedDay();
+            Date receiveDay = null;
+
             //判断是否已经全部领取
             if (lifeDiscountCoupon.getRestrictedQuantity() != 0 && lifeDiscountCouponUsers.size() >= lifeDiscountCoupon.getRestrictedQuantity()) {
+                receiveDay = lifeDiscountCouponUsers.get(0).getReceiveTime();
+                lifeDiscountCouponVo.setExpirationTime(lifeDiscountCouponUsers.get(0).getExpirationTime());
                 lifeDiscountCouponVo.setCanReceived(false);
             } else {
                 //判断一下领取规则
@@ -307,6 +389,7 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
                 } else {
                     LifeDiscountCouponUser lifeDiscountCouponUser = lifeDiscountCouponUsers.get(0);
                     Date receiveTime = lifeDiscountCouponUser.getReceiveTime();
+                    receiveDay = lifeDiscountCouponUser.getReceiveTime();
 
                     // 将 Date 转换为 Instant
                     Instant instant = receiveTime.toInstant();
@@ -328,11 +411,20 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
                         confineTo = ChronoUnit.YEARS.between(localDateTime, now);
                     }
                     //如果在规则范围内,则不允许领取,范围外,则可以领取
-                    if (confineTo < 1) {
-                        lifeDiscountCouponVo.setCanReceived(false);
-                    } else {
-                        lifeDiscountCouponVo.setCanReceived(true);
-                    }
+                    lifeDiscountCouponVo.setCanReceived(confineTo >= 1);
+                    lifeDiscountCouponVo.setExpirationTime(lifeDiscountCouponUser.getExpirationTime());
+                }
+            }
+            if(!StringUtils.isEmpty(specifiedDay)){
+                int sDay = Integer.parseInt(specifiedDay);
+                if(sDay > 0 && receiveDay != null){
+                    Date validDate = addDaysToDateJava8(receiveDay, sDay);
+                    LocalDate validDateLocalDate = validDate.toInstant()
+                            .atZone(ZoneId.systemDefault())
+                            .toLocalDate();
+                    lifeDiscountCouponVo.setValidDate(validDateLocalDate);
+                } else {
+                    lifeDiscountCouponVo.setValidDate(null);
                 }
             }
             lifeDiscountCouponVo.setQuantityClaimed(lifeDiscountCouponUsers.size());
@@ -596,16 +688,32 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
             return lifeDiscountCouponVos;
         }
         for (LifeDiscountCouponUser lifeDiscountCouponUser : lifeDiscountCouponUserIPage.getRecords()) {
-            LifeDiscountCoupon lifeDiscountCouponOne = lifeDiscountCoupons.stream().filter(lifeDiscountCoupon -> lifeDiscountCoupon.getId().equals(lifeDiscountCouponUser.getCouponId())).collect(Collectors.toList()).get(0);
+            LifeDiscountCoupon lifeDiscountCouponOne = lifeDiscountCoupons.stream().filter(lifeDiscountCoupon ->
+                    lifeDiscountCoupon.getId().equals(lifeDiscountCouponUser.getCouponId())).collect(Collectors.toList()).get(0);
             StoreInfo storeInfoOne = storeInfoList.stream().filter(storeInfo -> storeInfo.getId().toString().equals(lifeDiscountCouponOne.getStoreId())).collect(Collectors.toList()).get(0);
             LifeDiscountCouponVo lifeDiscountCouponVo = new LifeDiscountCouponVo();
             lifeDiscountCouponVo.setBusinessSection(storeInfoOne.getBusinessSection());
             lifeDiscountCouponVo.setCouponId(lifeDiscountCouponOne.getId());
             BeanUtils.copyProperties(lifeDiscountCouponOne, lifeDiscountCouponVo);
             lifeDiscountCouponVo.setQuantityClaimed(lifeDiscountCouponUserIPage.getRecords().size());
+            lifeDiscountCouponVo.setExpirationTime(lifeDiscountCouponUser.getExpirationTime());
+            // 设置有效期
+            String specifiedDay = lifeDiscountCouponOne.getSpecifiedDay();
+            if(!StringUtils.isEmpty(specifiedDay)){
+                int sDay = Integer.parseInt(specifiedDay);
+                if(sDay > 0){
+                    Date receiveDay = lifeDiscountCouponUser.getReceiveTime();
+                    Date validDate = addDaysToDateJava8(receiveDay, sDay);
+                    LocalDate validDateLocalDate = validDate.toInstant()
+                            .atZone(ZoneId.systemDefault())
+                            .toLocalDate();
+                    lifeDiscountCouponVo.setValidDate(validDateLocalDate);
+                }
+            }
+
             // 判断是否到了优惠券的开始时间
             lifeDiscountCouponVo.setReachUseTimeFlag(1);
-            if (localNow1.isBefore(lifeDiscountCouponOne.getStartDate())) {
+            if (localNow1.isBefore(lifeDiscountCouponOne.getBeginGetDate())) {
                 lifeDiscountCouponVo.setReachUseTimeFlag(0);
             }
             lifeDiscountCouponVos.add(lifeDiscountCouponVo);
@@ -622,12 +730,13 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
     }
 
     @Override
-    public IPage<LifeDiscountCouponVo> getStoreAllCouponList(String storeId, UserLoginInfo userLoginInfo, int page, int size, String couponName, String tab, int couponsFromType) {
+    public IPage<LifeDiscountCouponVo> getStoreAllCouponList(String storeId, UserLoginInfo userLoginInfo, int page, int size, String couponName, String tab, int couponsFromType, int couponStatus) {
 
         if (couponsFromType == 1) {
             IPage<LifeDiscountCoupon> iPage = new Page<>(page, size);
             List<LifeDiscountCouponVo> lifeDiscountCouponVos = new ArrayList<>();
             LambdaQueryWrapper<LifeDiscountCoupon> lifeDiscountCouponLambdaQueryWrapper = new LambdaQueryWrapper<LifeDiscountCoupon>();
+            lifeDiscountCouponLambdaQueryWrapper.eq(LifeDiscountCoupon::getCouponStatus, couponStatus);
             //如果couponName不为空,则模糊查询
             if (!StringUtils.isEmpty(couponName)) {
                 lifeDiscountCouponLambdaQueryWrapper.like(LifeDiscountCoupon::getName, couponName);
@@ -645,7 +754,7 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
                 lifeDiscountCouponLambdaQueryWrapper.eq(LifeDiscountCoupon::getGetStatus, 1);
             } else if (!StringUtils.isEmpty(tab) && tab.equals("2")) {//已结束
                 //结束时间小于当前时间
-                lifeDiscountCouponLambdaQueryWrapper.lt(LifeDiscountCoupon::getEndDate, getPureDate(now));
+                lifeDiscountCouponLambdaQueryWrapper.lt(LifeDiscountCoupon::getEndGetDate, getPureDate(now));
 
                 //不要已暂停关闭领取的
                 lifeDiscountCouponLambdaQueryWrapper.eq(LifeDiscountCoupon::getGetStatus, 1);
@@ -662,19 +771,21 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
                 Instant instant = now.toInstant();
                 ZoneId zoneId = ZoneId.systemDefault();
                 LocalDate localNow = instant.atZone(zoneId).toLocalDate();
-                int startResult = localNow.compareTo(lifeDiscountCoupon.getBeginGetDate());
-                int endResult = localNow.compareTo(lifeDiscountCoupon.getEndGetDate());
-                //如果当前时间小于开始时间
-                if (lifeDiscountCoupon.getSingleQty() == 0) {//无库存则已售罄
-                    lifeDiscountCouponVo.setStatus(Integer.parseInt(DiscountCouponEnum.HAVE_SOLD_OUT.getValue()));
-                } else if (lifeDiscountCoupon.getGetStatus().toString().equals(DiscountCouponEnum.NO_GET.getValue())) {
-                    lifeDiscountCouponVo.setStatus(Integer.parseInt(DiscountCouponEnum.SUSPEND_GET.getValue()));
-                } else if (startResult < 0) {
-                    lifeDiscountCouponVo.setStatus(Integer.parseInt(DiscountCouponEnum.HAVE_NOT_STARTED.getValue()));
-                } else if (endResult > 0) {
-                    lifeDiscountCouponVo.setStatus(Integer.parseInt(DiscountCouponEnum.FINISHED.getValue()));
-                } else if (startResult >= 0 && endResult <= 0) {
-                    lifeDiscountCouponVo.setStatus(Integer.parseInt(DiscountCouponEnum.UNDER_WAY.getValue()));
+                if(!StringUtils.isEmpty(lifeDiscountCoupon.getBeginGetDate()) && !StringUtils.isEmpty(lifeDiscountCoupon.getEndGetDate())) {
+                    int startResult = localNow.compareTo(lifeDiscountCoupon.getBeginGetDate());
+                    int endResult = localNow.compareTo(lifeDiscountCoupon.getEndGetDate());
+                    //如果当前时间小于开始时间
+                    if (lifeDiscountCoupon.getSingleQty() == 0) {//无库存则已售罄
+                        lifeDiscountCouponVo.setStatus(Integer.parseInt(DiscountCouponEnum.HAVE_SOLD_OUT.getValue()));
+                    } else if (lifeDiscountCoupon.getGetStatus().toString().equals(DiscountCouponEnum.NO_GET.getValue())) {
+                        lifeDiscountCouponVo.setStatus(Integer.parseInt(DiscountCouponEnum.SUSPEND_GET.getValue()));
+                    } else if (startResult < 0) {
+                        lifeDiscountCouponVo.setStatus(Integer.parseInt(DiscountCouponEnum.HAVE_NOT_STARTED.getValue()));
+                    } else if (endResult > 0) {
+                        lifeDiscountCouponVo.setStatus(Integer.parseInt(DiscountCouponEnum.FINISHED.getValue()));
+                    } else if (startResult >= 0 && endResult <= 0) {
+                        lifeDiscountCouponVo.setStatus(Integer.parseInt(DiscountCouponEnum.UNDER_WAY.getValue()));
+                    }
                 }
                 // 查询三个规则
                 List<LifeDiscountCouponUnavailableRules> discountCouponId = lifeDiscountCouponUnavailableRulesMapper.selectList(new QueryWrapper<LifeDiscountCouponUnavailableRules>().eq("discount_coupon_id", lifeDiscountCoupon.getId()));
@@ -732,19 +843,21 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
                 Instant instant = now.toInstant();
                 ZoneId zoneId = ZoneId.systemDefault();
                 LocalDate localNow = instant.atZone(zoneId).toLocalDate();
-                int startResult = localNow.compareTo(record.getStartDate());
-                int endResult = localNow.compareTo(record.getEndDate());
-                //如果当前时间小于开始时间
-                if (record.getSingleQty() == 0) {//无库存则已售罄
-                    record.setStatus(Integer.parseInt(DiscountCouponEnum.HAVE_SOLD_OUT.getValue()));
-                } else if (record.getGetStatus().toString().equals(DiscountCouponEnum.NO_GET.getValue())) {
-                    record.setStatus(Integer.parseInt(DiscountCouponEnum.SUSPEND_GET.getValue()));
-                } else if (startResult < 0) {
-                    record.setStatus(Integer.parseInt(DiscountCouponEnum.HAVE_NOT_STARTED.getValue()));
-                } else if (endResult > 0) {
-                    record.setStatus(Integer.parseInt(DiscountCouponEnum.FINISHED.getValue()));
-                } else if (startResult >= 0 && endResult <= 0) {
-                    record.setStatus(Integer.parseInt(DiscountCouponEnum.UNDER_WAY.getValue()));
+                if(!StringUtils.isEmpty(record.getBeginGetDate()) && !StringUtils.isEmpty(record.getEndGetDate())) {
+                    int startResult = localNow.compareTo(record.getBeginGetDate());
+                    int endResult = localNow.compareTo(record.getEndGetDate());
+                    //如果当前时间小于开始时间
+                    if (record.getSingleQty() == 0) {//无库存则已售罄
+                        record.setStatus(Integer.parseInt(DiscountCouponEnum.HAVE_SOLD_OUT.getValue()));
+                    } else if (record.getGetStatus().toString().equals(DiscountCouponEnum.NO_GET.getValue())) {
+                        record.setStatus(Integer.parseInt(DiscountCouponEnum.SUSPEND_GET.getValue()));
+                    } else if (startResult < 0) {
+                        record.setStatus(Integer.parseInt(DiscountCouponEnum.HAVE_NOT_STARTED.getValue()));
+                    } else if (endResult > 0) {
+                        record.setStatus(Integer.parseInt(DiscountCouponEnum.FINISHED.getValue()));
+                    } else if (startResult >= 0 && endResult <= 0) {
+                        record.setStatus(Integer.parseInt(DiscountCouponEnum.UNDER_WAY.getValue()));
+                    }
                 }
                 List<LifeDiscountCouponUnavailableRules> discountCouponId = lifeDiscountCouponUnavailableRulesMapper.selectList(new QueryWrapper<LifeDiscountCouponUnavailableRules>().eq("discount_coupon_id", record.getCouponId()));
                 Map<String, List<LifeDiscountCouponUnavailableRules>> collect = discountCouponId.stream().collect(Collectors.groupingBy(x -> x.getUnavailableRuleType()));
@@ -768,12 +881,13 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
     }
 
     @Override
-    public List<LifeDiscountCouponVo> getStoreAllCouponListPaginateNot(String status, String storeId, UserLoginInfo userLoginInfo) {
+    public List<LifeDiscountCouponVo> getStoreAllCouponListPaginateNot(String status, String storeId, UserLoginInfo userLoginInfo, int couponStatus) {
         List<LifeDiscountCouponVo> lifeDiscountCouponVos = new ArrayList<>();
         //根据店铺id查询该店铺的优惠券,状态是开启领取的券
         List<LifeDiscountCoupon> lifeDiscountCoupons = lifeDiscountCouponMapper.selectList(
                 new LambdaQueryWrapper<LifeDiscountCoupon>()
                         .eq(LifeDiscountCoupon::getStoreId, storeId)
+                        .eq(LifeDiscountCoupon::getCouponStatus, couponStatus)
                         .ne(LifeDiscountCoupon::getSingleQty, 0)
                         .orderByDesc(LifeDiscountCoupon::getCreatedTime)
         );
@@ -787,17 +901,19 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
             Instant instant = now.toInstant();
             ZoneId zoneId = ZoneId.systemDefault();
             LocalDate localNow = instant.atZone(zoneId).toLocalDate();
-            int startResult = localNow.compareTo(lifeDiscountCoupon.getBeginGetDate());
-            int endResult = localNow.compareTo(lifeDiscountCoupon.getEndGetDate());
-            //如果当前时间小于开始时间
-            if (lifeDiscountCoupon.getGetStatus().toString().equals(DiscountCouponEnum.NO_GET.getValue())) {
-                lifeDiscountCouponVo.setStatus(Integer.parseInt(DiscountCouponEnum.SUSPEND_GET.getValue()));
-            } else if (startResult < 0) {
-                lifeDiscountCouponVo.setStatus(Integer.parseInt(DiscountCouponEnum.HAVE_NOT_STARTED.getValue()));
-            } else if (endResult > 0) {
-                lifeDiscountCouponVo.setStatus(Integer.parseInt(DiscountCouponEnum.FINISHED.getValue()));
-            } else if (startResult >= 0 && endResult <= 0) {
-                lifeDiscountCouponVo.setStatus(Integer.parseInt(DiscountCouponEnum.UNDER_WAY.getValue()));
+            if(!StringUtils.isEmpty(lifeDiscountCoupon.getBeginGetDate()) && !StringUtils.isEmpty(lifeDiscountCoupon.getEndGetDate())) {
+                int startResult = localNow.compareTo(lifeDiscountCoupon.getBeginGetDate());
+                int endResult = localNow.compareTo(lifeDiscountCoupon.getEndGetDate());
+                //如果当前时间小于开始时间
+                if (lifeDiscountCoupon.getGetStatus().toString().equals(DiscountCouponEnum.NO_GET.getValue())) {
+                    lifeDiscountCouponVo.setStatus(Integer.parseInt(DiscountCouponEnum.SUSPEND_GET.getValue()));
+                } else if (startResult < 0) {
+                    lifeDiscountCouponVo.setStatus(Integer.parseInt(DiscountCouponEnum.HAVE_NOT_STARTED.getValue()));
+                } else if (endResult > 0) {
+                    lifeDiscountCouponVo.setStatus(Integer.parseInt(DiscountCouponEnum.FINISHED.getValue()));
+                } else if (startResult >= 0 && endResult <= 0) {
+                    lifeDiscountCouponVo.setStatus(Integer.parseInt(DiscountCouponEnum.UNDER_WAY.getValue()));
+                }
             }
             BeanUtils.copyProperties(lifeDiscountCoupon, lifeDiscountCouponVo);
             //如果按照状态查询了

+ 33 - 4
alien-store/src/main/java/shop/alien/store/service/impl/LifeDiscountCouponUserServiceImpl.java

@@ -1,5 +1,6 @@
 package shop.alien.store.service.impl;
 
+import com.aliyun.tea.utils.StringUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import lombok.RequiredArgsConstructor;
 import org.springframework.beans.BeanUtils;
@@ -45,17 +46,34 @@ public class LifeDiscountCouponUserServiceImpl extends ServiceImpl<LifeDiscountC
             Instant instant = now.toInstant();
             ZoneId zoneId = ZoneId.systemDefault();
             LocalDate localNow = instant.atZone(zoneId).toLocalDate();
-            int startResult = localNow.compareTo(lifeDiscountCoupon.getStartDate());
+            int startResult = localNow.compareTo(lifeDiscountCoupon.getBeginGetDate());
             if (startResult < 0) {
                 return R.fail("该优惠劵活动时间未开始");
             }
+            int getStatus = lifeDiscountCoupon.getGetStatus();
+            if (getStatus == 0) {
+                return R.fail("该优惠劵已经关闭领取");
+            }
+            String specifiedDay = lifeDiscountCoupon.getSpecifiedDay();
+
             //判断领取数量
             for (int i = 0; i < receiveQuantity; i++) {
                 LifeDiscountCouponUser lifeDiscountCouponUser = new LifeDiscountCouponUser();
                 BeanUtils.copyProperties(lifeDiscountCouponUserDto, lifeDiscountCouponUser);
                 lifeDiscountCouponUser.setReceiveTime(new Date());
-                //存入过期时间
-                lifeDiscountCouponUser.setExpirationTime(lifeDiscountCoupon.getEndDate());
+
+                // 存入过期时间, 领取时间加上specifiedDay
+                if(!StringUtils.isEmpty(specifiedDay)){
+                    int sDay = Integer.parseInt(specifiedDay);
+                    if(sDay > 0 && lifeDiscountCoupon.getBeginGetDate() != null) {
+                        Date validDate = addDaysToDateJava8(new Date(), sDay);
+                        LocalDate validDateLocalDate = validDate.toInstant()
+                                .atZone(ZoneId.systemDefault())
+                                .toLocalDate();
+                        lifeDiscountCouponUser.setExpirationTime(validDateLocalDate);
+                    }
+                }
+
                 //存入状态  待使用:0
                 lifeDiscountCouponUser.setStatus(Integer.parseInt(DiscountCouponEnum.WAITING_USED.getValue()));
                 lifeDiscountCouponUserMapper.insert(lifeDiscountCouponUser);
@@ -64,10 +82,21 @@ public class LifeDiscountCouponUserServiceImpl extends ServiceImpl<LifeDiscountC
             lifeDiscountCoupon.setSingleQty(lifeDiscountCoupon.getSingleQty() - receiveQuantity);
             lifeDiscountCouponMapper.updateById(lifeDiscountCoupon);
         } catch (BeansException e) {
-            e.printStackTrace();
             log.error("LifeDiscountCouponController.receiveCoupon ERROR Msg=" + e.getMessage());
             return R.fail("领取失败");
         }
         return R.success("领取成功");
     }
+
+    public static Date addDaysToDateJava8(Date date, int days) {
+        // 将Date转换为Instant
+        Instant instant = date.toInstant();
+
+        // 转换为LocalDate并加天数
+        LocalDate localDate = instant.atZone(ZoneId.systemDefault()).toLocalDate();
+        LocalDate newLocalDate = localDate.plusDays(days);
+
+        // 转换回Date
+        return Date.from(newLocalDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
+    }
 }

+ 16 - 50
alien-store/src/main/java/shop/alien/store/service/impl/LifeMessageServiceImpl.java

@@ -44,36 +44,6 @@ public class LifeMessageServiceImpl extends ServiceImpl<LifeMessageMapper, LifeM
     @Override
     public List<LifeMessageVo> getMessageList(String receiverId, int friendType, String search) throws Exception {
         try {
-            // 查询所有好友
-//        QueryWrapper<LifeFansVo> wrapper = new QueryWrapper<>();
-//        wrapper.groupBy("foll.phoneId");
-
-//        if ("user".equals(receiverId.split("_")[0])) {
-//            String myselfUserPhone = receiverId.split("_")[1];
-//            blockerType = "2";
-//            LifeUser myLifeUser = lifeUserService.getUserByPhone(myselfUserPhone);
-//            blockerId = String.valueOf(myLifeUser.getId());
-//        } else {
-//            String myselfStorePhone = receiverId.split("_")[1];
-//            blockerType = "1";
-//            StoreUser myStoreUser = storeUserService.getUserByPhone(myselfStorePhone);
-//            blockerId = String.valueOf(myStoreUser.getId());
-//        }
-
-//        List<LifeFansVo> lifeFansList = lifeFansMapper.getMutualAttention(new Page<>(1, Integer.MAX_VALUE), receiverId, blockerType, blockerId, wrapper).getRecords();
-//        List<String> friendsIds = lifeFansList.stream().map(LifeFansVo::getPhoneId).filter(item -> !item.equals(receiverId)).collect(Collectors.toList());
-//        String friendsIdsStr = "'" + String.join("','", friendsIds) + "'";
-
-//        wrapper = new QueryWrapper<>();
-//        wrapper.eq("num", 1);
-//        if (1 == friendType) {
-//            // 当前用户的所有好友消息
-//            wrapper.apply("(sender_id in (" + friendsIdsStr + ") or receiver_id in (" + friendsIdsStr + "))");
-//        } else {
-//            // 当前用户的所有未关注人消息
-//            wrapper.apply("(sender_id not in (" + friendsIdsStr + ") and receiver_id not in (" + friendsIdsStr + "))");
-//        }
-
             String blockerType = "user".equals(Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getString("userType")) ? "2" : "1";
             String blockerId = JwtUtil.getCurrentUserInfo().getString("userId");
             QueryWrapper<LifeFansVo> wrapper = new QueryWrapper<>();
@@ -96,7 +66,7 @@ public class LifeMessageServiceImpl extends ServiceImpl<LifeMessageMapper, LifeM
                 wrapper.apply("message.phoneId in ( " +
                         "    select receiver_id " +
                         "    from life_message " +
-                        "    where sender_id = '" + receiverId + "'" +
+                        "    where sender_id = '" + receiverId + "'  and delete_flag = 0 " +
                         "    group by receiver_id " +
                         ")");
                 // 没聊过
@@ -104,17 +74,13 @@ public class LifeMessageServiceImpl extends ServiceImpl<LifeMessageMapper, LifeM
                 wrapper.apply("message.phoneId not in ( " +
                         "    select receiver_id " +
                         "    from life_message " +
-                        "    where sender_id = '" + receiverId + "'" +
+                        "    where sender_id = '" + receiverId + "'  and delete_flag = 0 " +
                         "    group by receiver_id " +
                         ")");
             }
             wrapper.orderByDesc("message.created_time");
-//        IPage<LifeMessageVo> ipage = new Page<>(page, size);
             List<LifeMessageVo> lifeMessagePageList = lifeMessageMapper.getLifeMessagePageByPhoneId(receiverId, wrapper);
             if (!CollectionUtils.isEmpty(lifeMessagePageList)) {
-                // 取出所有发送消息的用户
-//            List<String> phoneIdList = lifeMessagePageList.stream().map(LifeMessageVo::getPhoneId).filter(item -> item.contains("_")).collect(Collectors.toList());
-
                 // 当前用户的所有关注
                 LambdaQueryWrapper<LifeFans> followWrapper = new LambdaQueryWrapper<>();
                 followWrapper.eq(LifeFans::getFansId, receiverId);
@@ -134,6 +100,7 @@ public class LifeMessageServiceImpl extends ServiceImpl<LifeMessageMapper, LifeM
                 messageWrapper.eq(LifeMessage::getReceiverId, receiverId);
                 messageWrapper.eq(LifeMessage::getIsRead, 0);
                 messageWrapper.eq(LifeMessage::getDeleteFlag, 0);
+                messageWrapper.apply("(instr(delete_phone_id, '" + receiverId + "') is null or instr(delete_phone_id, '" + receiverId + "') = 0)");
                 List<LifeMessage> noReadList = lifeMessageMapper.selectList(messageWrapper);
 
                 // 查询免打扰用户
@@ -141,19 +108,7 @@ public class LifeMessageServiceImpl extends ServiceImpl<LifeMessageMapper, LifeM
                 notDisturbWrapper.eq("phone_id", receiverId);
                 List<String> notDisturbList = lifeMessageNotDisturbMapper.selectList(notDisturbWrapper).stream().map(LifeMessageNotDisturb::getNotDisturbId).collect(Collectors.toList());
 
-//            // 根据手机号查询发送人信息
-//            List<String> storePhoneList = phoneIdList.stream().filter(item -> "store".equals(item.split("_")[0])).map(item -> item.split("_")[1]).collect(Collectors.toList());
-//            List<String> userPhoneList = phoneIdList.stream().filter(item -> "user".equals(item.split("_")[0])).map(item -> item.split("_")[1]).collect(Collectors.toList());
-//            String storePhones = "'" + String.join("','", storePhoneList) + "'";
-//            String userPhones = "'" + String.join("','", userPhoneList) + "'";
-//            List<LifeMessageVo> userList = lifeMessageMapper.getLifeUserAndStoreUserByPhone(storePhones, userPhones);
-
                 for (LifeMessageVo messageVo : lifeMessagePageList) {
-//                // 发送人信息
-//                LifeMessageVo user = userList.stream().filter(item -> item.getPhoneId().equals(messageVo.getPhoneId())).findFirst().orElse(null);
-//                messageVo.setUserName(null == user ? "" : user.getUserName());
-//                messageVo.setUserImage(null == user ? "" : user.getUserImage());
-
                     // 免打扰
                     if (notDisturbList.contains(messageVo.getPhoneId())) {
                         messageVo.setIsNotDisturb("1");
@@ -219,7 +174,7 @@ public class LifeMessageServiceImpl extends ServiceImpl<LifeMessageMapper, LifeM
             wrapper.apply("message.phoneId not in ( " +
                     "    select receiver_id " +
                     "    from life_message " +
-                    "    where sender_id = '" + receiverId + "'" +
+                    "    where sender_id = '" + receiverId + "' and delete_flag = 0 " +
                     "    group by receiver_id " +
                     ")");
             wrapper.orderByDesc("message.created_time");
@@ -325,7 +280,7 @@ public class LifeMessageServiceImpl extends ServiceImpl<LifeMessageMapper, LifeM
                 }
             }
 
-            List<LifeMessageVo> lifeMessageVos = lifeMessageMapper.selectUserImageLists(receiverId, senderId);
+            List<LifeMessageVo> lifeMessageVos = lifeMessageMapper.getMessageListByReceiverId(receiverId, senderId);
             for (LifeMessageVo lifeMessageVo : lifeMessageVos) {
                 if (lifeMessageVo.getReceiverId().equals(receiverId)) {
                     if (null != lifeUser1) {
@@ -494,4 +449,15 @@ public class LifeMessageServiceImpl extends ServiceImpl<LifeMessageMapper, LifeM
         }
     }
 
+    @Override
+    public List<LifeFansVo> getTalkedUserList() throws Exception {
+        try {
+            String phoneId = Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getString("userType") + "_" + JwtUtil.getCurrentUserInfo().getString("phone");
+            return lifeMessageMapper.getTalkedUserList(phoneId);
+        } catch (Exception e) {
+            log.error("LifeMessageServiceImpl.getTalkedUserList Error Mgs={}", e.getMessage());
+            throw new Exception(e);
+        }
+    }
+
 }

+ 1 - 1
alien-store/src/main/java/shop/alien/store/service/impl/LifeStoreOrderServiceImpl.java

@@ -74,7 +74,7 @@ public class LifeStoreOrderServiceImpl extends ServiceImpl<LifeUserOrderMapper,
             map.put("youxiaoqi", youxiaoqiTime);
             map.put("status", order.getStatus());
             LambdaUpdateWrapper<LifeUser> lifeUserWrapper = new LambdaUpdateWrapper<>();
-            lifeUserWrapper.eq(LifeUser::getId, order.getUserId());
+            lifeUserWrapper.eq(LifeUser::getId, order.getUserId()).in(LifeUser::getDeleteFlag, Arrays.asList(0, 1));
             LifeUser lifeUser = lifeUserService.getOne(lifeUserWrapper);
             map.put("phoneNum", lifeUser.getUserPhone());
             map.put("price", order.getFinalPrice());

+ 10 - 9
alien-store/src/main/java/shop/alien/store/service/impl/LifeUserViolationServiceImpl.java

@@ -16,6 +16,7 @@ import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import shop.alien.entity.store.*;
 import shop.alien.entity.store.dto.LifeUserViolationDto;
+import shop.alien.entity.store.excelVo.LifeUserOrderExcelVo;
 import shop.alien.entity.store.excelVo.LifeUserViolationExcelVO;
 import shop.alien.entity.store.excelVo.util.ExcelGenerator;
 import shop.alien.entity.store.vo.LifeUserViolationVo;
@@ -24,8 +25,10 @@ import shop.alien.mapper.*;
 import shop.alien.store.config.WebSocketProcess;
 import shop.alien.store.service.*;
 import shop.alien.store.util.FunctionMagic;
+import shop.alien.util.ali.AliOSSUtil;
 import shop.alien.util.common.JwtUtil;
 
+import java.io.File;
 import java.io.IOException;
 import java.time.Instant;
 import java.time.ZoneId;
@@ -60,7 +63,6 @@ public class LifeUserViolationServiceImpl extends ServiceImpl<LifeUserViolationM
 
     private final StoreUserService storeUserService;
 
-
     private final LifeUserDynamicsService lifeUserDynamicsService;
 
     private final StoreCommentService storeCommentService;
@@ -71,17 +73,16 @@ public class LifeUserViolationServiceImpl extends ServiceImpl<LifeUserViolationM
 
     private final WebSocketProcess webSocketProcess;
 
+    private final AliOSSUtil aliOSSUtil;
+
     @Value("${spring.web.resources.excel-path}")
     private String excelPath;
 
     @Value("${spring.web.resources.excel-generate-path}")
     private String excelGeneratePath;
 
-    @Value("${spring.web.resources.url}")
-    private String fileUrl;
-
     @Override
-    public int reporting(LifeUserViolation lifeuserViolation) throws Exception  {
+    public int reporting(LifeUserViolation lifeuserViolation) throws Exception {
         try {
             int result = lifeUserViolationMapper.insert(lifeuserViolation);
             if (result > 0) {
@@ -109,7 +110,7 @@ public class LifeUserViolationServiceImpl extends ServiceImpl<LifeUserViolationM
         return 0;
     }
 
-    private static LifeNotice getLifeNotice(LifeUserViolation lifeuserViolation)  {
+    private static LifeNotice getLifeNotice(LifeUserViolation lifeuserViolation) {
         JSONObject data = JwtUtil.getCurrentUserInfo();
         String phoneId = null;
         if (data != null) {
@@ -335,7 +336,6 @@ public class LifeUserViolationServiceImpl extends ServiceImpl<LifeUserViolationM
         queryWrapper.eq(StringUtils.isNotEmpty(processingStatus), PROCESSING_STATUS, processingStatus).and(flag, wrapper -> wrapper.nested(wq -> wq.eq(REPORTING_USER_TYPE, "1").in(!MIDs.isEmpty(), REPORTING_USER_ID, MIDs)).or(wq -> wq.eq(REPORTING_USER_TYPE, "2").in(!UIDs.isEmpty(), REPORTING_USER_ID, UIDs))).orderByDesc("updated_time");
         List<LifeUserViolation> resultPage = lifeUserViolationMapper.selectList(queryWrapper);
         List<LifeUserViolationExcelVO> res = Lists.newArrayList();
-        String fileName = UUID.randomUUID().toString().replace("-", "");
         AtomicInteger serialNumber = new AtomicInteger(1);
         resultPage.forEach(e -> {
             LifeUserViolationExcelVO dto = new LifeUserViolationExcelVO();
@@ -384,8 +384,9 @@ public class LifeUserViolationServiceImpl extends ServiceImpl<LifeUserViolationM
             }
             res.add(dto);
         });
-        ExcelGenerator.generateExcel(excelPath + excelGeneratePath + fileName + ".xlsx", res, LifeUserViolationExcelVO.class);
-        return fileUrl + "excel" + excelGeneratePath + fileName + ".xlsx";
+        String fileName = UUID.randomUUID().toString().replace("-", "");
+        String filePath = ExcelGenerator.generateExcel(excelPath + excelGeneratePath + fileName + ".xlsx", res, LifeUserViolationExcelVO.class);
+        return aliOSSUtil.uploadFile(new File(filePath), "excel/" + fileName + ".xlsx");
     }
 
     @Override

+ 271 - 32
alien-store/src/main/java/shop/alien/store/service/impl/PlatformStoreCouponServiceImpl.java

@@ -1,7 +1,9 @@
 package shop.alien.store.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import lombok.RequiredArgsConstructor;
@@ -9,12 +11,20 @@ import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import shop.alien.entity.store.LifeCoupon;
+import shop.alien.entity.store.LifeGroupBuyMain;
+import shop.alien.entity.store.StoreImg;
+import shop.alien.entity.store.StoreInfo;
+import shop.alien.entity.store.excelVo.LifeUserViolationExcelVO;
+import shop.alien.entity.store.*;
 import shop.alien.entity.store.excelVo.StoreCouponStatusVo;
 import shop.alien.entity.store.excelVo.util.ExcelGenerator;
 import shop.alien.entity.store.vo.LifeCouponVo;
-import shop.alien.mapper.PlatformStoreCouponMapper;
+import shop.alien.entity.store.vo.LifeGroupBuyMainVo;
+import shop.alien.mapper.*;
 import shop.alien.store.service.PlatformStoreCouponService;
+import shop.alien.util.ali.AliOSSUtil;
 
+import java.io.File;
 import java.io.IOException;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
@@ -29,17 +39,25 @@ public class PlatformStoreCouponServiceImpl implements PlatformStoreCouponServic
 
     private final PlatformStoreCouponMapper platformStoreCouponMapper;
 
-    List<LifeCouponVo> toExcel = new ArrayList<>();
+    private final PlatformStoreLifeGroupBuyMainMapper platformStoreLifeGroupBuyMainMapper;
+
+    private final StoreInfoMapper storeInfoMapper;
+
+    private final StoreImgMapper storeImgMapper;
+
+    private final EssentialHolidayComparisonMapper essentialHolidayComparisonMapper;
+
+    private final LifeGroupBuyThaliMapper lifeGroupBuyThaliMapper;
 
+    private final AliOSSUtil aliOSSUtil;
+
+    List<LifeCouponVo> toExcel = new ArrayList<>();
 
     @Value("${spring.web.resources.excel-path}")
     private String excelPath;
-    @Value("${spring.web.resources.excel-clearing-receipt}")
-    private String excelClearingReceipt;
+
     @Value("${spring.web.resources.excel-generate-path}")
     private String excelGeneratePath;
-    @Value("${spring.web.resources.url}")
-    private String fileUrl;
 
     @Override
     public IPage<LifeCouponVo> getCouponList(Integer page, Integer size, String storeName, String status, String createdTime, String phone, String type) {
@@ -80,14 +98,57 @@ public class PlatformStoreCouponServiceImpl implements PlatformStoreCouponServic
     }
 
     @Override
-    public IPage<LifeCouponVo> getCouponStatusList(Integer page, Integer size, String status, String expiredState) {
-        IPage<LifeCouponVo> iPage = new Page<>(page, size);
-        QueryWrapper<LifeCouponVo> wrapper = new QueryWrapper<>();
+    public IPage<LifeGroupBuyMainVo> getLifeGroupBuyMainList(Integer page, Integer size, String storeName, String status, String createdTime, String phone, String expiredState) {
+        QueryWrapper<LifeGroupBuyMainVo> wrapper = new QueryWrapper<>();
+        wrapper.like(StringUtils.isNotEmpty(storeName), "store.store_name", storeName);
+        if (status == null || status.equals("")) {
+            wrapper.in("life.status", 1, 2, 3, 4, 5, 6, 7);
+        }
+        if (status.equals("9")) {
+            wrapper.in("life.status", 4, 5, 6, 7);
+        } else {
+            wrapper.eq(StringUtils.isNotEmpty(status), "life.status", status);
+        }
+        //0:套餐未过期 1:套餐已过期
+        LocalDateTime nowDate = LocalDateTime.now(); // 获取当前时间
+        if (expiredState != null) {
+            if (expiredState.equals("0")) {
+                wrapper.gt("life.end_time", nowDate);
+            }
+            if (expiredState.equals("1")) {
+                wrapper.lt("life.end_time", nowDate);
+            }
+        }
 
-//        wrapper.like(StringUtils.isNotEmpty(storeName), "store.store_name", storeName);
-//        wrapper.eq(StringUtils.isNotEmpty(status), "coupon.status", status);
+        wrapper.eq("life.delete_flag", 0);
+        wrapper.eq("store.delete_flag", 0);
+        wrapper.eq("user.delete_flag", 0);
+        wrapper.like(StringUtils.isNotEmpty(createdTime), "life.created_time", createdTime);
+        wrapper.like(StringUtils.isNotEmpty(phone), "user.phone", phone);
+        wrapper.orderByDesc("life.created_time");
 
+        IPage<LifeGroupBuyMainVo> lifeGroupBuyMainList = platformStoreLifeGroupBuyMainMapper.getLifeGroupBuyMainList(new Page<>(page, size), wrapper);
+        lifeGroupBuyMainList.getRecords().forEach(item -> {
+// expiredState 赋值逻辑(修正版)
+            LocalDateTime now = LocalDateTime.now(); // 获取当前时间
+            Date endDate = item.getEndTime();
+            if (endDate != null) {
+                LocalDateTime endDateTime = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
+                // 核心逻辑:未过期时赋 0,已过期赋 1(与前端枚举定义一致)
+                if (now.isBefore(endDateTime)) {
+                    item.setExpiredState("0"); // 当前时间未超过 endDate → 未到期
+                } else {
+                    item.setExpiredState("1"); // 当前时间超过 endDate → 已到期
+                }
+            }
+        });
+        return lifeGroupBuyMainList;
+    }
 
+    @Override
+    public IPage<LifeCouponVo> getCouponStatusList(Integer page, Integer size, String status, String expiredState) {
+        IPage<LifeCouponVo> iPage = new Page<>(page, size);
+        QueryWrapper<LifeCouponVo> wrapper = new QueryWrapper<>();
         // 定义允许的状态值
         List<String> allowedStatus = Arrays.asList("1", "2", "3");
         if ("-3".equals(status)) { // 已售罄(逻辑状态,状态为进行中但是余量为0的)
@@ -104,16 +165,12 @@ public class PlatformStoreCouponServiceImpl implements PlatformStoreCouponServic
                 wrapper.eq("coupon.status", status);
             }
         }
-
         wrapper.eq("coupon.delete_flag", 0);
         wrapper.eq("store.delete_flag", 0);
         wrapper.eq("user.delete_flag", 0);
         wrapper.eq("coupon.status_delete_flag", 0);
-//        wrapper.like(StringUtils.isNotEmpty(createdTime),"coupon.created_time", createdTime);
-//        wrapper.like(StringUtils.isNotEmpty(phone),"user.phone", phone);
         wrapper.isNotNull("coupon.status");
         wrapper.orderByDesc("coupon.created_time");
-
         Date currentDate = new Date();
         if ("0".equals(expiredState)) {
             wrapper.ge("coupon.end_date", currentDate);
@@ -173,23 +230,35 @@ public class PlatformStoreCouponServiceImpl implements PlatformStoreCouponServic
     }
 
     @Override
-    public int approvalCoupon(Integer id, Integer status, String comment) {
-        LifeCoupon coupon = platformStoreCouponMapper.selectById(id);
-        if (null == coupon) return 0;
-
-        // 如果通过,且券有效时间在当前时间之前,则修改状态为进行中
-        Date now = new Date();
-        if (status == 0 && coupon.getStartDate().before(now) && coupon.getEndDate().after(now)) {
-            status = 1;
-        }
+    public int approvalCoupon(Integer id, Integer status, String comment, String type) {
+        if (type.equals("0")) {
+            LifeCoupon coupon = platformStoreCouponMapper.selectById(id);
+            if (null == coupon) return 0;
+
+            // 如果通过,且券有效时间在当前时间之前,则修改状态为进行中
+            Date now = new Date();
+            if (status == 0 && coupon.getStartDate().before(now) && coupon.getEndDate().after(now)) {
+                status = 1;
+            }
 
-        coupon.setStatus(status);
-        coupon.setApprovalComments(comment);
-        // 审核后开始
-        if ("0".equals(coupon.getSaleTimeStrType())) {
-            coupon.setStartDate(new Date());
+            coupon.setStatus(status);
+            coupon.setApprovalComments(comment);
+            // 审核后开始
+            if ("0".equals(coupon.getSaleTimeStrType())) {
+                coupon.setStartDate(new Date());
+            }
+            return platformStoreCouponMapper.updateById(coupon);
+        } else {
+            LifeGroupBuyMain lifeGroupBuyMain = platformStoreLifeGroupBuyMainMapper.selectById(id);
+            if (null == lifeGroupBuyMain) return 0;
+            lifeGroupBuyMain.setStatus(status);
+            lifeGroupBuyMain.setApprovalComments(comment);
+            // 审核通过后开始
+            if (lifeGroupBuyMain.getStartTimeType() == 0 && lifeGroupBuyMain.getStatus() == 5) {
+                lifeGroupBuyMain.setStartTimeValue(new Date());
+            }
+            return platformStoreLifeGroupBuyMainMapper.updateById(lifeGroupBuyMain);
         }
-        return platformStoreCouponMapper.updateById(coupon);
     }
 
     @Override
@@ -295,9 +364,117 @@ public class PlatformStoreCouponServiceImpl implements PlatformStoreCouponServic
             storeCouponStatusVos.add(storeCouponStatusVo);
         }
         String fileName = UUID.randomUUID().toString().replace("-", "");
+        String filePath = ExcelGenerator.generateExcel(excelPath + excelGeneratePath + fileName + ".xlsx", storeCouponStatusVos, StoreCouponStatusVo.class);
+        String url = aliOSSUtil.uploadFile(new File(filePath), "excel/" + fileName + ".xlsx");
+        return url;
+    }
 
-        ExcelGenerator.generateExcel(excelPath + excelGeneratePath + fileName + ".xlsx", storeCouponStatusVos, StoreCouponStatusVo.class);
-        return fileUrl + "excel" + excelGeneratePath + fileName + ".xlsx";
+    @Override
+    public String lifeGroupBuyMainStatusExport(String status, String expiredState) throws IOException {
+        QueryWrapper<LifeGroupBuyMainVo> wrapper = new QueryWrapper<>();
+        // 定义允许的状态值
+        if (StringUtils.isEmpty(status)) {
+            wrapper.in("life.status", 1, 2, 3, 4, 5, 6, 7);
+        }
+        if (status.equals("9")) {
+            wrapper.in("life.status", 4, 5, 6, 7);
+        } else {
+            wrapper.eq(StringUtils.isNotEmpty(status), "life.status", status);
+        }
+        //0:套餐未过期 1:套餐已过期
+        LocalDateTime nowDate = LocalDateTime.now(); // 获取当前时间
+        if (expiredState != null) {
+            if (expiredState.equals("0")) {
+                wrapper.gt("life.end_time", nowDate);
+            }
+            if (expiredState.equals("1")) {
+                wrapper.lt("life.end_time", nowDate);
+            }
+        }
+
+        wrapper.eq("life.delete_flag", 0);
+        wrapper.eq("store.delete_flag", 0);
+        wrapper.eq("user.delete_flag", 0);
+
+        wrapper.orderByDesc("life.created_time");
+
+        List<LifeGroupBuyMainVo> lifeGroupBuyMainList = platformStoreLifeGroupBuyMainMapper.getLifeGroupBuyMainList(wrapper);
+        lifeGroupBuyMainList.forEach(item -> {
+            if (item.getStatus() == 1) {
+                item.setCouponState("待审核");
+            } else if (item.getStatus() == 2) {
+                item.setCouponState("未开始");
+            } else if (item.getStatus() == 3) {
+                item.setCouponState("审核拒绝");
+            } else if (item.getStatus() == 4 && item.getInventoryNum() == 0) {
+                item.setCouponState("已售罄");
+            } else if (item.getStatus() == 5 && item.getInventoryNum() > 0) {
+                item.setCouponState("进行中");
+            } else if (item.getStatus() == 6) {
+                item.setCouponState("已下架");
+            } else if (item.getStatus() == 7) {
+                item.setCouponState("已结束");
+            }
+            item.setCouponName(item.getGroupName());
+            Date startDate = item.getStartTimeValue();
+            Date endDate = item.getEndTime();
+            // expiredState 赋值逻辑(修正版)
+            LocalDateTime now = LocalDateTime.now(); // 获取当前时间
+
+            // 格式化日期
+            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+            String formattedEndDate = "";
+            if (endDate != null) {
+                LocalDateTime endDateTime = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
+                // 调整结束时间为前一天的23:59:59
+                endDateTime = endDateTime.minusDays(1).withHour(23).withMinute(59).withSecond(59);
+                formattedEndDate = endDateTime.format(formatter);
+
+                // 核心逻辑:未过期时赋 0,已过期赋 1(与前端枚举定义一致)
+                if (now.isBefore(endDateTime)) {
+                    // 计算剩余天数
+                    long remainingDays = ChronoUnit.DAYS.between(now, endDateTime);
+                    item.setDaysToExpire(remainingDays + "天");
+                    item.setExpiredState("未到期"); // 当前时间未超过 endDate → 未到期
+                } else {
+                    item.setDaysToExpire("0天");
+                    item.setExpiredState("已到期"); // 当前时间超过 endDate → 已到期
+                }
+                // 将结束时间调整为前一秒
+                endDateTime = endDateTime.minusSeconds(1);
+            }
+
+            if (startDate != null) {
+                LocalDateTime startDateTime = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
+                String formattedStartDate = startDateTime.format(formatter);
+                item.setCouponTime(formattedStartDate + "-" + formattedEndDate);
+            }
+        });
+
+        // 根据 expiredState 进行筛选
+        if (StringUtils.isNotEmpty(expiredState)) {
+            // 将前端传递的 "0"/"1" 转换为业务状态
+            String targetState = "0".equals(expiredState) ? "未到期" : "已到期";
+
+            // 筛选时增加空值判断,避免 NPE
+            lifeGroupBuyMainList = lifeGroupBuyMainList.stream()
+                    .filter(item -> {
+                        String itemState = item.getExpiredState(); // 获取当前项的状态
+                        return targetState.equals(itemState); // 严格匹配字符串
+                    })
+                    .collect(Collectors.toList());
+        }
+        List<StoreCouponStatusVo> storeCouponStatusVos = new ArrayList<>();
+        int index = 1;
+        for (LifeGroupBuyMainVo record : lifeGroupBuyMainList) {
+            StoreCouponStatusVo storeCouponStatusVo = new StoreCouponStatusVo();
+            BeanUtils.copyProperties(record, storeCouponStatusVo);
+            storeCouponStatusVo.setId(String.valueOf(index++)); // 设置序号
+            storeCouponStatusVos.add(storeCouponStatusVo);
+        }
+        String fileName = UUID.randomUUID().toString().replace("-", "");
+        String filePath = ExcelGenerator.generateExcel(excelPath + excelGeneratePath + fileName + ".xlsx", storeCouponStatusVos, StoreCouponStatusVo.class);
+        return aliOSSUtil.uploadFile(new File(filePath), "excel/" + fileName + ".xlsx");
     }
 
     @Override
@@ -307,4 +484,66 @@ public class PlatformStoreCouponServiceImpl implements PlatformStoreCouponServic
         lifeCoupon.setStatusDeleteFlag(1);
         return platformStoreCouponMapper.deleteById(id);
     }
+
+    @Override
+    public LifeGroupBuyMainVo getLifeGroupBuyMainByDetail(Integer id) {
+        LifeGroupBuyMainVo lifeGroupBuyMainVo = new LifeGroupBuyMainVo();
+        LifeGroupBuyMain lifeGroupBuyMain = platformStoreLifeGroupBuyMainMapper.selectById(id);
+        List<LifeGroupBuyThali> lifeGroupBuyThali = lifeGroupBuyThaliMapper.getLifeGroupBuyThaliList(new LambdaQueryWrapper<LifeGroupBuyThali>()
+                .eq(LifeGroupBuyThali::getParentId, lifeGroupBuyMain.getId()).groupBy(LifeGroupBuyThali::getDetailId));
+        lifeGroupBuyMainVo.setLifeGroupBuyThaliList(lifeGroupBuyThali);
+
+        // 添加商户信息
+        StoreInfo storeUser = storeInfoMapper.selectById(lifeGroupBuyMain.getStoreId());
+        // 图片
+        List<String> collect = Arrays.stream(lifeGroupBuyMain.getImageId().split(","))
+                .map(String::trim)
+                .collect(Collectors.toList());
+        List<StoreImg> storeImgs = storeImgMapper.selectList(new LambdaQueryWrapper<StoreImg>().in(StoreImg::getId, collect));
+        BeanUtils.copyProperties(lifeGroupBuyMain, lifeGroupBuyMainVo);
+        lifeGroupBuyMainVo.setStoreName(storeUser.getStoreName());
+        lifeGroupBuyMainVo.setStoreImgList(storeImgs);
+        //0:套餐未过期 1:套餐已过期
+        LocalDateTime nowDate = LocalDateTime.now(); // 获取当前时间
+
+        // 格式化日期
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        String formattedEndDate = "";
+        LocalDateTime endDateTime = lifeGroupBuyMainVo.getEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
+        // 调整结束时间为前一天的23:59:59
+        endDateTime = endDateTime.minusDays(1).withHour(23).withMinute(59).withSecond(59);
+//            formattedEndDate = endDateTime.format(formatter);
+
+        // 核心逻辑:未过期时赋 0,已过期赋 1(与前端枚举定义一致)
+        if (nowDate.isBefore(endDateTime)) {
+            // 计算剩余天数
+            long remainingDays = ChronoUnit.DAYS.between(nowDate, endDateTime);
+            lifeGroupBuyMainVo.setDaysToExpire(remainingDays + "天");
+            lifeGroupBuyMainVo.setExpiredState("0"); // 当前时间未超过 endDate → 未到期
+        } else {
+            lifeGroupBuyMainVo.setDaysToExpire("0天");
+            lifeGroupBuyMainVo.setExpiredState("1"); // 当前时间超过 endDate → 已到期
+        }
+
+        // 核心逻辑:未过期时赋 0,已过期赋 1(与前端枚举定义一致)
+        if (nowDate.isBefore(endDateTime)) {
+            // 计算剩余天数
+            long remainingDays = ChronoUnit.DAYS.between(nowDate, endDateTime);
+            lifeGroupBuyMainVo.setDaysToExpire(remainingDays + "天");
+            lifeGroupBuyMainVo.setExpiredState("0"); // 当前时间未超过 endDate → 未到期
+        } else {
+            lifeGroupBuyMainVo.setDaysToExpire("0天");
+            lifeGroupBuyMainVo.setExpiredState("1"); // 当前时间超过 endDate → 已到期
+        }
+        // 不可用日期
+        String afterSemicolon = lifeGroupBuyMain.getDisableDateValue().split(";")[1];
+        if (StringUtils.isNotEmpty(afterSemicolon)) {
+            List<String> collectUnavailableDate = Arrays.stream(afterSemicolon.split(",")).map(String::trim).collect(Collectors.toList());
+            if (CollectionUtils.isNotEmpty(collectUnavailableDate)) {
+                List<EssentialHolidayComparison> essentialHolidayComparisons = essentialHolidayComparisonMapper.selectList(new LambdaQueryWrapper<EssentialHolidayComparison>().in(EssentialHolidayComparison::getId, collectUnavailableDate));
+                lifeGroupBuyMainVo.setEssentialHolidayComparisonList(essentialHolidayComparisons);
+            }
+        }
+        return lifeGroupBuyMainVo;
+    }
 }

+ 8 - 7
alien-store/src/main/java/shop/alien/store/service/impl/StoreActivityServiceImpl.java

@@ -20,8 +20,10 @@ import shop.alien.entity.store.vo.StoreActivityVo;
 import shop.alien.entity.store.vo.StoreInfoVo;
 import shop.alien.mapper.*;
 import shop.alien.store.service.StoreActivityService;
+import shop.alien.util.ali.AliOSSUtil;
 import shop.alien.util.common.StringToJsonConverterUtils;
 
+import java.io.File;
 import java.io.IOException;
 import java.text.SimpleDateFormat;
 import java.time.Instant;
@@ -49,9 +51,6 @@ public class StoreActivityServiceImpl extends ServiceImpl<StoreActivityMapper, S
     @Value("${spring.web.resources.excel-generate-path}")
     private String excelGeneratePath;
 
-    @Value("${spring.web.resources.url}")
-    private String fileUrl;
-
     private final StoreActivityRuleDetailMapper storeActivityRuleDetailMapper;
 
     private final StoreInfoMapper storeInfoMapper;
@@ -62,6 +61,8 @@ public class StoreActivityServiceImpl extends ServiceImpl<StoreActivityMapper, S
 
     private final StoreActivityRuleMapper storeActivityRuleMapper;
 
+    private final AliOSSUtil aliOSSUtil;
+
     @Override
     public IPage<StoreActivityVo> getActiveList(int page, int size, String status, String createdTime) {
         // 创建格式化对象
@@ -430,7 +431,7 @@ public class StoreActivityServiceImpl extends ServiceImpl<StoreActivityMapper, S
                 }
             }
             // 转换为Integer集合
-            if (integerList.size() > 0) {
+            if (!integerList.isEmpty()) {
                 List<LifeUserVo> lifeUserVos = new ArrayList<>();
                 for (Integer userId : integerList) {
                     LifeUser lifeUser = lifeUserMapper.selectById(userId);
@@ -483,7 +484,6 @@ public class StoreActivityServiceImpl extends ServiceImpl<StoreActivityMapper, S
                 new LambdaQueryWrapper<StoreActivity>()
                         .like(com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotEmpty(status), StoreActivity::getStatus, status)
                         .like(com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotEmpty(createdTime), StoreActivity::getCreatedTime, createdTime));
-        String fileName = UUID.randomUUID().toString().replace("-", "");
         List<StoreActivityExcelVo> storeInfoExcelVos = new ArrayList<>();
         int serialNumber = 0;
         for (StoreActivity storeActivity : storeActivities) {
@@ -519,8 +519,9 @@ public class StoreActivityServiceImpl extends ServiceImpl<StoreActivityMapper, S
             storeActivityExcelVo.setApprovalOpinion(storeActivity.getApprovalOpinion());
             storeInfoExcelVos.add(storeActivityExcelVo);
         }
-        ExcelGenerator.generateExcel(excelPath + excelGeneratePath + fileName + ".xlsx", storeInfoExcelVos, StoreActivityExcelVo.class);
-        return fileUrl + "excel" + excelGeneratePath + fileName + ".xlsx";
+        String fileName = UUID.randomUUID().toString().replace("-", "");
+        String filePath = ExcelGenerator.generateExcel(excelPath + excelGeneratePath + fileName + ".xlsx", storeInfoExcelVos, StoreActivityExcelVo.class);
+        return aliOSSUtil.uploadFile(new File(filePath), "excel/" + fileName + ".xlsx");
     }
 
     /**

+ 109 - 2
alien-store/src/main/java/shop/alien/store/service/impl/StoreIncomeDetailsRecordServiceImpl.java

@@ -8,13 +8,16 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import lombok.RequiredArgsConstructor;
 import org.springframework.beans.BeanUtils;
+import org.apache.commons.lang.StringUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import shop.alien.entity.result.R;
 import shop.alien.entity.store.*;
+import shop.alien.entity.store.*;
 import shop.alien.entity.store.vo.StoreIncomeDetailsRecordVo;
 import shop.alien.mapper.StoreCashOutRecordMapper;
 import shop.alien.mapper.StoreIncomeDetailsRecordMapper;
@@ -56,6 +59,7 @@ public class StoreIncomeDetailsRecordServiceImpl extends ServiceImpl<StoreIncome
 
     private final StoreIncomeDetailsRecordMapper storeIncomeDetailsRecordMapper;
 
+
     /**
      * 提现-提现全部-手续费一单一算
      *
@@ -151,9 +155,112 @@ public class StoreIncomeDetailsRecordServiceImpl extends ServiceImpl<StoreIncome
             }
             return R.fail("余额不足");
         }
-        return R.fail("支付密码错误");
+        return "支付密码错误";
+    }
+
+    /**
+     * 提现申请-提现全部-手续费一单一算
+     *
+     * @param storeId     门店id
+     * @return 是否成功
+     */
+    @Transactional
+    @Override
+    public String applyCashOut(Integer storeId, String payPassword) {
+        StoreUser storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getStoreId, storeId).eq(StoreUser::getPayPassword, payPassword));
+        if (storeUser != null) {
+            //查询可用账单(大于创建时间3天)
+            LambdaQueryWrapper<StoreIncomeDetailsRecord> wrapper = new LambdaQueryWrapper<>();
+            //当前时间-3天大于创建时间
+            wrapper.lt(StoreIncomeDetailsRecord::getCreatedTime, DateUtils.calcDays(new Date(), -3))
+                    //未绑定提现记录的
+                    .isNull(StoreIncomeDetailsRecord::getCashOutId).eq(StoreIncomeDetailsRecord::getStoreId, storeId);
+            List<StoreIncomeDetailsRecord> list = this.list(wrapper);
+            if (!list.isEmpty()) {
+                //总金额
+                Integer availableAmount = 0;
+                //手续费
+                Integer commission = 0;
+                for (StoreIncomeDetailsRecord record : list) {
+                    availableAmount += record.getMoney();
+                    commission += record.getCommission();
+                }
+                int money = availableAmount - commission;
+                list = list.stream().sorted(Comparator.comparing(StoreIncomeDetailsRecord::getCreatedTime)).collect(Collectors.toList());
+                Date startDate = list.get(0).getCreatedTime();
+                Date endDate = list.get(list.size() - 1).getCreatedTime();
+                //增加提现申请记录
+                StoreCashOutRecord storeCashOutRecord = new StoreCashOutRecord();
+                storeCashOutRecord.setStoreId(storeId);
+                storeCashOutRecord.setMoney(money);
+                storeCashOutRecord.setCommission(commission);
+                storeCashOutRecord.setCashOutType(0);
+                storeCashOutRecord.setPaymentStatus(3);
+                storeCashOutRecord.setDeleteFlag(0);
+                storeCashOutRecord.setIncomeStartTime(startDate);
+                storeCashOutRecord.setIncomeEndTime(endDate);
+                storeCashOutRecord.setStoreUserId(storeUser.getId());
+                storeCashOutRecordMapper.insert(storeCashOutRecord);
+                //关联提现记录
+                list.forEach(record -> record.setCashOutId(storeCashOutRecord.getId()));
+                this.saveOrUpdateBatch(list);
+                return "申请成功";
+            }
+            return "账单未到可提现时间";
+        }
+        return "支付密码错误";
     }
 
+    @Transactional
+    @Override
+    public String approveCashOut(Integer cashOutId, String approveStatus, String failReason) {
+        if (cashOutId != null && cashOutId > 0 && StringUtils.isNotBlank(approveStatus)) {
+            StoreCashOutRecord storeCashOutRecord = storeCashOutRecordMapper.selectById(cashOutId);
+            if (approveStatus.equals("0")) {
+                //同意,开始提现
+                Integer storeUserId = storeCashOutRecord.getStoreUserId();
+                StoreUser storeUser = storeUserMapper.selectById(storeUserId);
+                int money = storeCashOutRecord.getMoney();
+                BigDecimal decimal = new BigDecimal(money);
+                BigDecimal divide = decimal.divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
+                if (Double.parseDouble(divide.toString()) < 0.10) {
+                    return "金额不能小于0.1元";
+                }
+                // StoreAliPayLog pay = aliApi.pay(storeUser.getName(), storeUser.getIdCard(), storeUser.getPhone(), divide.toString());
+                StoreAliPayLog pay =  new StoreAliPayLog();
+                if (pay != null) {
+                    // 提现成功,更新提现申请相关状态
+                    storeCashOutRecord.setOrderNo(pay.getOutBizNo());
+                    storeCashOutRecord.setAliOrderNo(pay.getOrderId());
+                    storeCashOutRecord.setPaymentStatus(1);//提现成功
+                    storeCashOutRecord.setApproveTime(new Date());// 审批时间
+                    storeCashOutRecord.setPayDate(new Date());//支付时间
+
+                    //减少账户余额
+                    storeUserMapper.updateById(new StoreUser(storeCashOutRecord.getStoreId(), storeUser.getMoney() - storeCashOutRecord.getMoney() - storeCashOutRecord.getCommission()));
+                } else {
+                    // 提现失败
+                    storeCashOutRecord.setPaymentStatus(2);
+                    storeCashOutRecord.setApproveTime(new Date());// 审批时间
+                    storeCashOutRecord.setFailReason("支付失败");
+                }
+                storeCashOutRecordMapper.updateById(storeCashOutRecord);
+            } else {
+                storeCashOutRecord.setPaymentStatus(4);
+                storeCashOutRecord.setFailReason(failReason);
+                storeCashOutRecordMapper.updateById(storeCashOutRecord);
+                // 拒绝将账单中的提现记录置空
+                LambdaUpdateWrapper<StoreIncomeDetailsRecord> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
+                lambdaUpdateWrapper.eq(StoreIncomeDetailsRecord::getStoreId, storeCashOutRecord.getStoreId())
+                        .eq(StoreIncomeDetailsRecord::getCashOutId, storeCashOutRecord.getId())
+                        .set(StoreIncomeDetailsRecord::getCashOutId, "");
+                 int result = storeIncomeDetailsRecordMapper.updateByCashOutId(storeCashOutRecord.getStoreId(), storeCashOutRecord.getId());
+            }
+        }
+        return "审批成功";
+    }
+
+
     /**
      * 今日收益
      *
@@ -182,7 +289,7 @@ public class StoreIncomeDetailsRecordServiceImpl extends ServiceImpl<StoreIncome
      * @return 未到账期
      */
     @Override
-    public JSONObject noYetPayment(Integer storeId, Integer incomeType, Integer paymentType, String startTime, String endTime, int page, int size) {
+    public JSONObject noYetPayment(Integer storeId, Integer incomeType, Integer paymentType) {
         LambdaQueryWrapper<StoreIncomeDetailsRecord> wrapper = new LambdaQueryWrapper<>();
         JSONObject jsonObject = new JSONObject();
         Date now = new Date();

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 251 - 305
alien-store/src/main/java/shop/alien/store/service/impl/StoreInfoServiceImpl.java


+ 10 - 10
alien-store/src/main/java/shop/alien/store/service/impl/StoreStaffConfigServiceImpl.java

@@ -2,18 +2,21 @@ package shop.alien.store.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import lombok.RequiredArgsConstructor;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
-import org.springframework.util.StringUtils;
 import shop.alien.entity.store.StoreStaffConfig;
+import shop.alien.entity.store.excelVo.StoreInfoExpiredRecordsExcelVo;
 import shop.alien.entity.store.excelVo.StoreStaffConfigExcelVo;
 import shop.alien.entity.store.excelVo.util.ExcelGenerator;
 import shop.alien.mapper.StoreStaffConfigMapper;
 import shop.alien.store.service.StoreStaffConfigService;
+import shop.alien.util.ali.AliOSSUtil;
 
+import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Date;
@@ -32,6 +35,8 @@ public class StoreStaffConfigServiceImpl implements StoreStaffConfigService {
 
     private final StoreStaffConfigMapper storeStaffConfigMapper;
 
+    private final AliOSSUtil aliOSSUtil;
+
     @Value("${spring.web.resources.excel-path}")
     private String excelPath;
     @Value("${spring.web.resources.excel-clearing-receipt}")
@@ -52,7 +57,7 @@ public class StoreStaffConfigServiceImpl implements StoreStaffConfigService {
 
     @Override
     public int addOrUpdateStaffConfig(StoreStaffConfig storeStaffConfig) {
-        if (StringUtils.isEmpty(storeStaffConfig.getId())) {
+        if (StringUtils.isEmpty(storeStaffConfig.getId().toString())) {
             Date nowDate = new Date(System.currentTimeMillis());
             storeStaffConfig.setCreatedTime(nowDate);
             return storeStaffConfigMapper.insert(storeStaffConfig);
@@ -78,11 +83,9 @@ public class StoreStaffConfigServiceImpl implements StoreStaffConfigService {
     @Override
     public String staffConfigExport(String status) throws IOException {
         QueryWrapper<StoreStaffConfig> wrapper = new QueryWrapper<>();
-
-        wrapper.eq(com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotEmpty(status), "status", status);
+        wrapper.eq(StringUtils.isNotEmpty(status), "status", status);
         wrapper.eq("delete_flag", 0);
         wrapper.orderByDesc("created_time");
-
         List<StoreStaffConfig> storeStaffConfig = storeStaffConfigMapper.selectList(wrapper);
         storeStaffConfig.forEach(item -> {
             if ("0".equals(item.getStatus())) {
@@ -94,7 +97,6 @@ public class StoreStaffConfigServiceImpl implements StoreStaffConfigService {
             }
 
         });
-
         List<StoreStaffConfigExcelVo> storeStaffConfigs = new ArrayList<>();
         int index = 1;
         for (StoreStaffConfig record : storeStaffConfig) {
@@ -104,10 +106,8 @@ public class StoreStaffConfigServiceImpl implements StoreStaffConfigService {
             storeStaffConfigs.add(storeCouponStatusVo);
         }
         String fileName = UUID.randomUUID().toString().replace("-", "");
-
-        ExcelGenerator.generateExcel(excelPath + excelGeneratePath + fileName + ".xlsx", storeStaffConfigs, StoreStaffConfigExcelVo.class);
-        return fileUrl + "excel" + excelGeneratePath + fileName + ".xlsx";
+        String filePath = ExcelGenerator.generateExcel(excelPath + excelGeneratePath + fileName + ".xlsx", storeStaffConfigs, StoreStaffConfigExcelVo.class);
+        return aliOSSUtil.uploadFile(new File(filePath), "excel/" + fileName + ".xlsx");
     }
 
-
 }

+ 67 - 64
alien-store/src/main/java/shop/alien/store/service/impl/StoreUserServiceImpl.java

@@ -1,5 +1,6 @@
 package shop.alien.store.service.impl;
 
+import cn.hutool.core.date.DateTime;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@@ -27,13 +28,17 @@ import shop.alien.store.config.BaseRedisService;
 import shop.alien.store.service.NearMeService;
 import shop.alien.store.service.StoreUserService;
 import shop.alien.store.util.FunctionMagic;
+import shop.alien.util.ali.AliOSSUtil;
 import shop.alien.util.common.DateUtils;
 import shop.alien.util.common.JwtUtil;
 
+import java.io.File;
 import java.io.IOException;
 import java.text.SimpleDateFormat;
-import java.time.*;
-
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
 
@@ -49,23 +54,6 @@ import java.util.*;
 @RequiredArgsConstructor
 public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser> implements StoreUserService {
 
-    @Value("${spring.web.resources.excel-path}")
-    private String excelPath;
-
-    @Value("${spring.web.resources.excel-generate-path}")
-    private String excelGeneratePath;
-
-    @Value("${spring.web.resources.url}")
-    private String fileUrl;
-
-    @Value("${jwt.expiration-time}")
-    private String effectiveTime;
-
-    /**
-     * 设定初始化默认密码
-     */
-    private static final String DEFAULT_PASSWORD = "123456";
-
     private final StoreUserMapper storeUserMapper;
 
     private final StoreInfoMapper storeInfoMapper;
@@ -82,6 +70,22 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
 
     private final NearMeService nearMeService;
 
+    private final AliOSSUtil aliOSSUtil;
+
+    @Value("${spring.web.resources.excel-path}")
+    private String excelPath;
+
+    @Value("${spring.web.resources.excel-generate-path}")
+    private String excelGeneratePath;
+
+    @Value("${jwt.expiration-time}")
+    private String effectiveTime;
+
+    /**
+     * 设定初始化默认密码
+     */
+    private static final String DEFAULT_PASSWORD = "123456";
+
     /**
      * 手机号获取
      *
@@ -195,10 +199,10 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
     @Override
     public R<String> forgetOrModifyPassword(String phone, String newPhone, String oldPassword, String newPassword, String confirmNewPassword, String verificationCode, Integer type) {
         boolean flag = false;
-        try{
+        try {
             //类型为0 忘记密码
             if (type == 0) {
-               return forgetPassword(phone, newPassword, verificationCode);
+                return forgetPassword(phone, newPassword, verificationCode);
             }
             //修改密码
             else if (type == 1) {
@@ -224,7 +228,7 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
             }
             //更换绑定手机号
             else if (type == 2) {
-               return ChangeBoundPhone(phone, newPhone, verificationCode);
+                return ChangeBoundPhone(phone, newPhone, verificationCode);
             }
             return R.success("密码修改成功");
         } catch (Exception e) {
@@ -319,10 +323,10 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
             newUpdateWrapper.eq(StoreUser::getPhone, newPhone);
             StoreUser newStoreUser = this.getOne(newUpdateWrapper);
             if (newStoreUser != null) {
-                if(newStoreUser.getPhone().equals(newPhone)){
+                if (newStoreUser.getPhone().equals(newPhone)) {
                     throw new RuntimeException("该手机号已注册过商户");
                 }
-            }else{
+            } else {
                 LambdaUpdateWrapper<StoreUser> updateWrapper = new LambdaUpdateWrapper<>();
                 updateWrapper.eq(StoreUser::getPhone, phone);
                 StoreUser storeUser = this.getOne(updateWrapper);
@@ -501,7 +505,6 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
                         .like(StringUtils.isNotEmpty(phone), StoreUser::getPhone, phone)
                         .eq(StringUtils.isNotEmpty(status), StoreUser::getStatus, status)
         );
-        String fileName = UUID.randomUUID().toString().replace("-", "");
         List<StoreUserExcelVo> storeUserExcelVoList = new ArrayList<>();
         int serialNumber = 0;
         for (StoreUser storeUser : storeUsers) {
@@ -516,12 +519,11 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
             storeUserExcelVo.setStatus(storeUser.getStatus() == 0 ? "启用" : "禁用");
             storeUserExcelVoList.add(storeUserExcelVo);
         }
-        ExcelGenerator.generateExcel(excelPath + excelGeneratePath + fileName + ".xlsx", storeUserExcelVoList, StoreUserExcelVo.class);
-        return fileUrl + "excel" + excelGeneratePath + fileName + ".xlsx";
-
+        String fileName = UUID.randomUUID().toString().replace("-", "");
+        String filePath = ExcelGenerator.generateExcel(excelPath + excelGeneratePath + fileName + ".xlsx", storeUserExcelVoList, StoreUserExcelVo.class);
+        return aliOSSUtil.uploadFile(new File(filePath), "excel/" + fileName + ".xlsx");
     }
 
-
     /**
      * 注册校验
      *
@@ -534,8 +536,6 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
         queryWrapper.in(StoreUser::getStatus, 0, 1);
         List<StoreUser> storeUsers = storeUserMapper.selectList(queryWrapper);
         return CollectionUtils.isEmpty(storeUsers) ? Boolean.TRUE : Boolean.FALSE;
-
-
     }
 
     /**
@@ -591,7 +591,7 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
             //钱包功能暂未完成此效验默认状态都是1通过
             if (storeUser.getMoney() != null && storeUser.getMoney() > 0) {
                 //vaule为0代表有未体现的现金
-                storeMap.put("accountMoney", "1");
+                storeMap.put("accountMoney", "0");
             } else {
                 //vaule为1代表没有未体现的现金
                 storeMap.put("accountMoney", "1");
@@ -653,33 +653,37 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
         StoreUser storeUser = storeUserMapper.selectOne(storeUserLambdaQueryWrapper);
         String key = "verification_" + storeUser.getPhone();
         String redisVerificationCode = baseRedisService.getString(key);
-        if (redisVerificationCode.equals(storeUserVo.getVerificationCode())) {
-            if (storeUser != null) {
-                // 添加注销原因
-                storeUser.setLogoutReason(storeUserVo.getLogoutReason());
-                // 添加注销code
-                storeUser.setLogoutCode(storeUserVo.getLogoutCode());
-                // 注销中状态
-                storeUser.setStatus(-1);
-                // 添加注销申请时间
-                storeUser.setLogoutTime(new Date());
-                // 更新logout_flag状态为1
-                storeUser.setLogoutFlag(1);
-                int num = storeUserMapper.updateById(storeUser);
-                if (num > 0) {
-                    // 发送通知
-                    LifeNotice lifeMessage = new LifeNotice();
-                    lifeMessage.setReceiverId("store_" + storeUser.getPhone());
-                    String text = "您提交的账号注销申请已成功提交, 系统将按流程进行处理. 注销申请提交后, 将进入7天的冷静期. 期间您可以随时在" +
-                            "[账号信息]撤回申请. 冷静期结束后, 系统将正式开始注销操作. 账号内所有数据(包括但不限于个人信息、 资产等) 将被永久清除, 且无法恢复." +
-                            "如有疑问, 可联系【客服】咨询. 感谢您使用我们的服务.";
-                    lifeMessage.setContext(text);
-                    lifeMessage.setTitle("注销通知");
-                    lifeMessage.setSenderId("system");
-                    lifeMessage.setIsRead(0);
-                    lifeMessage.setNoticeType(1);
-                    lifeNoticeMapper.insert(lifeMessage);
+        if (redisVerificationCode != null) {
+            if (redisVerificationCode.equals(storeUserVo.getVerificationCode())) {
+                if (storeUser != null) {
+                    // 添加注销原因
+                    storeUser.setLogoutReason(storeUserVo.getLogoutReason());
+                    // 添加注销code
+                    storeUser.setLogoutCode(storeUserVo.getLogoutCode());
+                    // 注销中状态
+                    storeUser.setStatus(-1);
+                    // 添加注销申请时间
+                    storeUser.setLogoutTime(new Date());
+                    // 更新logout_flag状态为1
+                    storeUser.setLogoutFlag(1);
+                    int num = storeUserMapper.updateById(storeUser);
+                    if (num > 0) {
+                        // 发送通知
+                        LifeNotice lifeMessage = new LifeNotice();
+                        lifeMessage.setReceiverId("store_" + new DateTime());
+                        String text = "您提交的账号注销申请已成功提交, 系统将按流程进行处理. 注销申请提交后, 将进入7天的冷静期. 期间您可以随时在" +
+                                "[账号信息]撤回申请. 冷静期结束后, 系统将正式开始注销操作. 账号内所有数据(包括但不限于个人信息、 资产等) 将被永久清除, 且无法恢复." +
+                                "如有疑问, 可联系【客服】咨询. 感谢您使用我们的服务.";
+                        lifeMessage.setContext(text);
+                        lifeMessage.setTitle("注销商家账号通知");
+                        lifeMessage.setSenderId("system");
+                        lifeMessage.setIsRead(0);
+                        lifeMessage.setNoticeType(1);
+                        lifeNoticeMapper.insert(lifeMessage);
+                    }
                 }
+            } else {
+                throw new RuntimeException("验证码错误");
             }
         } else {
             throw new RuntimeException("验证码错误");
@@ -697,9 +701,9 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
         // 注销状态变为可用
         storeUser.setStatus(0);
         // 清空注销原因
-        storeUser.setLogoutReason(null);
+        storeUser.setLogoutReason("");
         // 清空注销code
-        storeUser.setLogoutCode(null);
+        storeUser.setLogoutCode("");
         // 清空注销申请时间
         storeUser.setLogoutTime(null);
         // 更新logout_flag状态为0
@@ -716,7 +720,7 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
                     "当前账号状态已恢复正常. 您可以继续使用该账号登录并享受各项服务, 所有个人数据及账户信息" +
                     "均已妥善保留. 若您后续仍有注销需求, 可随时通过账号信息页面重新提交申请. 感谢您的理解与支持!";
             lifeMessage.setContext(text);
-            lifeMessage.setTitle("撤销注销通知");
+            lifeMessage.setTitle("撤销商家账号注销通知");
             lifeMessage.setSenderId("system");
             lifeMessage.setIsRead(0);
             lifeMessage.setNoticeType(1);
@@ -751,15 +755,14 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
 
     @Override
     public List<String> getIds(String name, String phone) {
-        if (Objects.isNull(name) && Objects.isNull(phone)) return Arrays.asList("");
+        if (Objects.isNull(name) && Objects.isNull(phone)) return Collections.singletonList("");
         LambdaQueryWrapper<StoreUser> wrapper = new LambdaQueryWrapper<>();
-
         List<Triple<Boolean, SFunction<StoreUser, ?>, Object>> conditions = new ArrayList<>();
         conditions.add(Triple.of(StringUtils.isNotEmpty(name), StoreUser::getName, name));
         conditions.add(Triple.of(StringUtils.isNotEmpty(phone), StoreUser::getPhone, phone));
         FunctionMagic.buildLikeConditions(wrapper, conditions);
         List<String> res = FunctionMagic.convertToIds(storeUserMapper.selectList(wrapper), StoreUser::getId);
-        return CollectionUtils.isEmpty(res) ? Arrays.asList("") : res;
+        return CollectionUtils.isEmpty(res) ? Collections.singletonList("") : res;
     }
 
     @Override

+ 0 - 530
alien-store/src/main/java/shop/alien/store/task/ScheduledTask.java

@@ -1,530 +0,0 @@
-package shop.alien.store.task;
-
-import cn.hutool.core.collection.CollectionUtil;
-import com.alibaba.fastjson2.JSONObject;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Component;
-import shop.alien.entity.second.SecondGoods;
-import shop.alien.entity.second.SecondTradeRecord;
-import shop.alien.entity.store.*;
-import shop.alien.entity.store.vo.WebSocketVo;
-import shop.alien.mapper.*;
-import shop.alien.mapper.second.SecondGoodsMapper;
-import shop.alien.mapper.second.SecondTradeRecordMapper;
-import shop.alien.store.config.BaseRedisService;
-import shop.alien.store.config.WebSocketProcess;
-import shop.alien.store.service.*;
-import shop.alien.store.util.ali.AliApi;
-import shop.alien.util.common.AlipayTradeRefund;
-import shop.alien.util.common.DateUtils;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.time.LocalDateTime;
-import java.time.ZoneId;
-import java.util.*;
-import java.util.stream.Collectors;
-
-@Slf4j
-@Component
-@RequiredArgsConstructor
-public class ScheduledTask {
-
-    private final LifeCouponMapper lifeCouponMapper;
-
-    private final LifeUserOrderMapper lifeUserOrderMapper;
-
-    private final AlipayTradeRefund alipayTradeRefund;
-
-    private final StoreIncomeDetailsRecordService storeIncomeDetailsRecordService;
-
-    private final StoreCashOutRecordService storeCashOutRecordService;
-
-    private final StoreUserService storeUserService;
-
-    private final AliApi aliApi;
-
-    private final LifeReverseGroupBuyingService lifeReverseGroupBuyingService;
-
-    private final LifeMessageMapper lifeMessageMapper;
-
-    private final LifeUserService lifeUserService;
-
-    private final SecondTradeRecordMapper secondTradeRecordMapper;
-
-    private final LifeNoticeMapper lifeNoticeMapper;
-
-    private final LifeUserMapper lifeUserMapper;
-
-    private final SecondGoodsMapper secondGoodsMapper;
-
-    private final WebSocketProcess webSocketProcess;
-
-    private final BaseRedisService baseRedisService;
-
-//    @Scheduled(cron = "0 */10 * * * ?")
-    public void sendDiscountCouponRemind() {
-        //查询
-
-    }
-
-//    @Scheduled(cron = "0 */10 * * * ?")
-    // 该方法用于定时更新生活优惠券(LifeCoupon)的状态
-    public void quanStatusUpdateTask() {
-        //执行修改代金券状态
-        System.out.println("执行修改代金券状态 ===>");
-        // 获取当前时间
-        Date now = new Date();
-        // 创建一个 Calendar 实例,用于对日期进行操作
-        Calendar calendar = Calendar.getInstance();
-        // 将 Calendar 的时间设置为当前时间
-        calendar.setTime(now);
-        // 将 Calendar 的小时设置为 0
-        calendar.set(Calendar.HOUR_OF_DAY, 0);
-        // 将 Calendar 的分钟设置为 0
-        calendar.set(Calendar.MINUTE, 0);
-        // 将 Calendar 的秒设置为 0
-        calendar.set(Calendar.SECOND, 0);
-        // 将 Calendar 的毫秒设置为 0
-        calendar.set(Calendar.MILLISECOND, 0);
-        // 获取处理后的时间,即当前日期的零点
-        now = calendar.getTime();
-
-        // 创建一个 LambdaUpdateWrapper 用于查询生活优惠券,这里实际上主要用于查询操作
-        LambdaUpdateWrapper<LifeCoupon> selectWrapper = new LambdaUpdateWrapper<>();
-        // 创建一个集合,用于存储要查询的优惠券状态值
-        List<Integer> ids = new ArrayList<>();
-        // 待审核
-        ids.add(0);
-        // 进行中
-        ids.add(1);
-        // 已暂停
-        ids.add(2);
-        // 设置查询条件,查询状态为 0、1 或 2 的生活优惠券
-        selectWrapper.in(LifeCoupon::getStatus, ids);
-        // 调用 lifeCouponMapper 的 selectList 方法,根据上述条件查询生活优惠券列表
-        List<LifeCoupon> jinxingzhongList = lifeCouponMapper.selectList(selectWrapper);
-        // 判断查询结果列表是否不为空
-        if (!jinxingzhongList.isEmpty()) {
-            // 遍历查询到的生活优惠券列表
-            for (LifeCoupon quan : jinxingzhongList) {
-                // 获取当前优惠券的结束日期
-                Date endTime = quan.getEndDate();
-                // 比较当前日期(零点)和优惠券的结束日期,如果当前日期大于结束日期  将状态变成已结束
-                if (now.compareTo(endTime) > 0) {
-                    // 创建一个 LambdaUpdateWrapper 用于更新生活优惠券的状态
-                    LambdaUpdateWrapper<LifeCoupon> updateWrapper = new LambdaUpdateWrapper<>();
-                    // 设置更新条件,根据优惠券的 ID 进行更新
-                    updateWrapper.eq(LifeCoupon::getId, quan.getId())
-                            // 设置要更新的字段,将优惠券的状态更新为 3
-                            .set(LifeCoupon::getStatus, 3);
-                    // 调用 lifeCouponMapper 的 update 方法,根据上述条件更新优惠券的状态
-                    lifeCouponMapper.update(null, updateWrapper);
-                }
-            }
-        }
-
-        // 创建另一个 LambdaUpdateWrapper 用于查询状态为 0 的生活优惠券
-        LambdaUpdateWrapper<LifeCoupon> selectWrapper2 = new LambdaUpdateWrapper<>();
-        // 设置查询条件,查询状态为 0 的生活优惠券
-        selectWrapper2.eq(LifeCoupon::getStatus, 0);
-        // 调用 lifeCouponMapper 的 selectList 方法,根据上述条件查询生活优惠券列表
-        List<LifeCoupon> weikaishiList = lifeCouponMapper.selectList(selectWrapper2);
-        // 判断查询结果列表是否不为空
-        if (!weikaishiList.isEmpty()) {
-            // 遍历查询到的生活优惠券列表
-            for (LifeCoupon quan : weikaishiList) {
-                // 获取当前优惠券的开始日期
-                Date startTime = quan.getStartDate();
-                // 获取当前优惠券的结束日期
-                Date endTime = quan.getEndDate();
-                // 判断当前日期(零点)是否在优惠券的开始日期和结束日期之间  将待使用变成进行中
-                if (now.compareTo(startTime) >= 0 && now.compareTo(endTime) <= 0) {
-                    // 创建一个 LambdaUpdateWrapper 用于更新生活优惠券的状态
-                    LambdaUpdateWrapper<LifeCoupon> updateWrapper = new LambdaUpdateWrapper<>();
-                    // 设置更新条件,根据优惠券的 ID 进行更新
-                    updateWrapper.eq(LifeCoupon::getId, quan.getId())
-                            // 设置要更新的字段,将优惠券的状态更新为 1
-                            .set(LifeCoupon::getStatus, 1);
-                    // 调用 lifeCouponMapper 的 update 方法,根据上述条件更新优惠券的状态
-                    lifeCouponMapper.update(null, updateWrapper);
-                }
-            }
-        }
-    }
-
-//    @Scheduled(cron = "0 */10 * * * ?")
-    public void orderStatusUpdateTask() {
-        Date now = new Date();
-        Calendar calendar = Calendar.getInstance();
-        calendar.setTime(now);
-        calendar.set(Calendar.HOUR_OF_DAY, 0);
-        calendar.set(Calendar.MINUTE, 0);
-        calendar.set(Calendar.SECOND, 0);
-        calendar.set(Calendar.MILLISECOND, 0);
-        now = calendar.getTime();
-        LambdaUpdateWrapper<LifeUserOrder> selectWrapper = new LambdaUpdateWrapper<>();
-        List<Integer> ids = new ArrayList<>();
-        ids.add(0);
-        ids.add(3);
-        selectWrapper.in(LifeUserOrder::getStatus, ids);
-        List<LifeUserOrder> orderList = lifeUserOrderMapper.selectList(selectWrapper);
-        if (!orderList.isEmpty()) {
-            for (LifeUserOrder order : orderList) {
-                Date payTime = order.getPayTime();
-                LifeCoupon quan = lifeCouponMapper.selectById(order.getQuanId());
-                calendar.setTime(payTime);
-                calendar.add(Calendar.DAY_OF_MONTH, quan.getExpirationDate());
-                Date guoqiDate = calendar.getTime();
-                Date endDate = quan.getEndDate();
-                if (now.compareTo(guoqiDate) > 0 || now.compareTo(endDate) > 0) {
-                    String result = alipayTradeRefund.processRefund(order.getOrderNo(), order.getFinalPrice(), "过期自动退");
-                    if (result.equals("调用成功")) {
-                        LambdaUpdateWrapper<LifeUserOrder> updateWrapper = new LambdaUpdateWrapper<>();
-                        updateWrapper.eq(LifeUserOrder::getId, order.getId()).set(LifeUserOrder::getStatus, 4).set(LifeUserOrder::getRefundTime, new Date());
-                        lifeUserOrderMapper.update(null, updateWrapper);
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * 自动转账
-     * 一分钟执行一次
-     */
-//    @Scheduled(cron = "0 */1 * * * ?")
-    public void autoTransferAccounts() {
-        //获取已到账期
-        LambdaQueryWrapper<StoreIncomeDetailsRecord> wrapper = new LambdaQueryWrapper<>();
-        wrapper.lt(StoreIncomeDetailsRecord::getCreatedTime, DateUtils.calcDays(new Date(), -28)).isNull(StoreIncomeDetailsRecord::getCashOutId);
-        List<StoreIncomeDetailsRecord> list = storeIncomeDetailsRecordService.list(wrapper);
-        // 根据 storeId 分组
-        Map<Integer, List<StoreIncomeDetailsRecord>> groupedByStoreId = list.stream()
-                .collect(Collectors.groupingBy(StoreIncomeDetailsRecord::getStoreId));
-        //获取账户余额
-        List<Integer> storeIds = new ArrayList<>();
-        Map<Integer, Integer> storeMoney = new HashMap<>();
-        Map<Integer, Integer> storeCommission = new HashMap<>();
-        groupedByStoreId.forEach((storeId, records) -> {
-            storeIds.add(storeId);
-            // 对每个 storeId 对应的 records 进行处理
-            int money = 0;
-            int commission = 0;
-            for (StoreIncomeDetailsRecord record : records) {
-                money += record.getMoney() - record.getCommission();
-                commission += record.getCommission();
-            }
-            storeMoney.put(storeId, money);
-            storeCommission.put(storeId, commission);
-        });
-        List<StoreUser> storeUserList = storeUserService.list(new LambdaUpdateWrapper<StoreUser>().in(StoreUser::getStoreId, storeIds));
-        //转账
-        storeMoney.forEach((storeId, money) -> {
-            if (money < 10) {
-                log.info("账户已到账期金额小于最小转账金额, 用户id: {},金额: {}", storeId, money);
-            } else {
-                List<StoreUser> userList = storeUserList.stream()
-                        .filter(storeUser -> storeUser.getStoreId().equals(storeId))
-                        .collect(Collectors.toList());
-                if (!userList.isEmpty()) {
-                    StoreUser filteredUsers = userList.get(0);
-                    StoreAliPayLog pay = aliApi.pay(filteredUsers.getName(), filteredUsers.getIdCard(), filteredUsers.getPhone(), new BigDecimal(money).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString());
-                    if (null == pay) {
-                        log.error("支付宝转账失败, 用户: {},金额: {}", filteredUsers.getPhone(), money);
-                    } else {
-                        StoreCashOutRecord storeCashOutRecord = new StoreCashOutRecord();
-                        //转账记录表
-                        storeCashOutRecord.setStoreId(storeId)
-                                .setMoney(money)
-                                .setCommission(storeCommission.get(storeId))
-                                .setCashOutType(1)
-                                .setOrderNo(pay.getOutBizNo())
-                                .setAliOrderNo(pay.getOrderId())
-                                .setIncomeStartTime(groupedByStoreId.get(storeId).get(0).getCreatedTime())
-                                .setIncomeEndTime(groupedByStoreId.get(storeId).get(groupedByStoreId.get(storeId).size() - 1).getCreatedTime())
-                                .setPaymentDate(new Date());
-                        storeCashOutRecordService.save(storeCashOutRecord);
-                        list.forEach(record -> {
-                            if (record.getStoreId().equals(storeId)) {
-                                record.setCashOutId(storeCashOutRecord.getId());
-                            }
-                        });
-                        //减少金额
-                        filteredUsers.setMoney(filteredUsers.getMoney() - money);
-                        storeUserService.updateById(filteredUsers);
-                    }
-                }
-            }
-        });
-        //增加记录
-        storeIncomeDetailsRecordService.saveOrUpdateBatch(list);
-    }
-
-    /**
-     * 反向团购订单自动退款
-     */
-//    @Scheduled(cron = "0 * * * * ?")
-    public void reverseGroupOrder() {
-        LambdaQueryWrapper<LifeReverseGroupBuying> wrapper = new LambdaQueryWrapper<>();
-        //状态, 0:待审核, 1:未通过, 2:已通过, 3:待接单, 4:未接单(已截止), 5:待使用, 6:已完成, 7:已退款
-        wrapper.eq(LifeReverseGroupBuying::getStatus, 4);
-        List<LifeReverseGroupBuying> list = lifeReverseGroupBuyingService.list();
-        for (LifeReverseGroupBuying lifeReverseGroupBuying : list) {
-            //竞价结束
-            if (DateUtils.dateCompare(new Date(), lifeReverseGroupBuying.getBiddingEndTime())) {
-                LifeUserOrder lifeUserOrder = lifeUserOrderMapper.selectById(lifeReverseGroupBuying.getOrderId());
-                String s = alipayTradeRefund.processRefund(lifeUserOrder.getOrderNo(), new BigDecimal(lifeReverseGroupBuying.getGroupMoney()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString(), "用户反向团购, 未有商家接单");
-                if (s.contains("成功")) {
-                    //修改状态
-                    lifeReverseGroupBuying.setStatus(7);
-                    lifeReverseGroupBuyingService.updateById(lifeReverseGroupBuying);
-                } else {
-                    LifeUser lifeUser = lifeUserService.getById(lifeUserOrder.getUserId());
-                    LifeMessage lifeMessage = new LifeMessage();
-                    lifeMessage.setSenderName("system");
-                    if (lifeUser != null) {
-                        lifeMessage.setReceiverId("user_" + lifeUser.getUserPhone());
-                        lifeMessage.setContent("你有一笔反向团购退款失败, 请联系管理员");
-                        lifeMessage.setType("2");
-                        lifeMessageMapper.insert(lifeMessage);
-                    }
-
-                }
-            }
-        }
-    }
-
-    /**
-     * 二手交易平台 - 交易时间前的十分钟和十五分钟之间  给买家和卖家发送通知提醒
-     */
-//    @Scheduled(cron = "0 * * * * ?")
-    public void secondTradeRemind() throws Exception {
-        LocalDateTime now = LocalDateTime.now().withSecond(0).withNano(0);
-
-        // 查询所有待交易
-        LambdaQueryWrapper<SecondTradeRecord> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(SecondTradeRecord::getTradeStatus, 3);
-        List<SecondTradeRecord> tradeRecordList = secondTradeRecordMapper.selectList(wrapper);
-
-        for (SecondTradeRecord tradeRecord : tradeRecordList) {
-            // 十分钟前
-            LocalDateTime tenMinutesAgo = tradeRecord.getTransactionTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().minusMinutes(10).withSecond(0).withNano(0);
-            // 交易时间的十分钟前
-            if (now.isEqual(tenMinutesAgo)) {
-                LifeUser buyer = lifeUserMapper.selectById(tradeRecord.getBuyerId());
-                LifeUser seller = lifeUserMapper.selectById(tradeRecord.getSellerId());
-
-                String buyerPhoneId = null == buyer ? "" : "user_" + buyer.getUserPhone();
-                String sellerPhoneId = null == seller ? "" : "user_" + seller.getUserPhone();
-
-                // 封装交易信息
-                JSONObject message = new JSONObject();
-                message.put("tradeId", tradeRecord.getId());
-                message.put("transactionAmount", tradeRecord.getTransactionAmount());
-                message.put("transactionLatitudeLongitude", tradeRecord.getTransactionLatitudeLongitude());
-                message.put("transactionLatitudeLongitudeAddress", tradeRecord.getTransactionLatitudeLongitudeAddress());
-                message.put("transactionLocation", tradeRecord.getTransactionLocation());
-                message.put("transactionTime", tradeRecord.getTransactionTime());
-                message.put("tradeStatus", tradeRecord.getTradeStatus());
-
-                // 给买家发送消息
-                LifeMessage lifeMessage = new LifeMessage();
-                lifeMessage.setSenderId(sellerPhoneId);
-                lifeMessage.setReceiverId(buyerPhoneId);
-                lifeMessage.setContent(message.toJSONString());
-                lifeMessage.setType("5");
-                lifeMessageMapper.insert(lifeMessage);
-
-                // 给买家推送消息
-                WebSocketVo websocketVo = new WebSocketVo();
-                websocketVo.setSenderId(sellerPhoneId);
-                websocketVo.setReceiverId(buyerPhoneId);
-                websocketVo.setCategory("message");
-                websocketVo.setType("5");
-                websocketVo.setText(message.toJSONString());
-                websocketVo.setMessageId(lifeMessage.getId());
-                webSocketProcess.sendMessage(buyerPhoneId, JSONObject.from(websocketVo).toJSONString());
-
-                // 给买家发送通知
-                LifeNotice lifeNotice = new LifeNotice();
-                lifeNotice.setSenderId("system");
-                lifeNotice.setReceiverId(buyerPhoneId);
-                lifeNotice.setBusinessId(tradeRecord.getId());
-                lifeNotice.setTitle("商品交易签到");
-                lifeNotice.setNoticeType(1);
-                // 封装通知信息
-                JSONObject noticeMessage = new JSONObject();
-                noticeMessage.put("tradeId", tradeRecord.getId());
-                noticeMessage.put("otherSideUserId", tradeRecord.getSellerId());
-                noticeMessage.put("otherSidePhoneId", sellerPhoneId);
-                noticeMessage.put("otherSideName", null == seller ? "" : seller.getUserName());
-                noticeMessage.put("otherSideImage", null == seller ? "" : seller.getUserImage());
-                noticeMessage.put("message", "您有一笔交易即将开始, 请及时前往查看");
-                lifeNotice.setContext(noticeMessage.toJSONString());
-                lifeNoticeMapper.insert(lifeNotice);
-
-                // 给买家推送通知
-                websocketVo = new WebSocketVo();
-                websocketVo.setSenderId("system");
-                websocketVo.setReceiverId(buyerPhoneId);
-                websocketVo.setCategory("notice");
-                websocketVo.setNoticeType("1");
-                websocketVo.setType("5");
-                websocketVo.setText(JSONObject.from(lifeNotice).toJSONString());
-                websocketVo.setMessageId(lifeMessage.getId());
-                webSocketProcess.sendMessage(buyerPhoneId, JSONObject.from(websocketVo).toJSONString());
-
-                // 给卖家发送消息
-                lifeMessage = new LifeMessage();
-                lifeMessage.setSenderId(buyerPhoneId);
-                lifeMessage.setReceiverId(sellerPhoneId);
-                lifeMessage.setContent(message.toJSONString());
-                lifeMessage.setType("5");
-                lifeMessageMapper.insert(lifeMessage);
-
-                // 给卖家推送消息
-                websocketVo = new WebSocketVo();
-                websocketVo.setSenderId(buyerPhoneId);
-                websocketVo.setReceiverId(sellerPhoneId);
-                websocketVo.setCategory("message");
-                websocketVo.setType("5");
-                websocketVo.setText(message.toJSONString());
-                websocketVo.setMessageId(lifeMessage.getId());
-                webSocketProcess.sendMessage(sellerPhoneId, JSONObject.from(websocketVo).toJSONString());
-
-                // 给卖家发送通知
-                lifeNotice = new LifeNotice();
-                lifeNotice.setSenderId("system");
-                lifeNotice.setReceiverId(sellerPhoneId);
-                lifeNotice.setBusinessId(tradeRecord.getId());
-                lifeNotice.setTitle("商品交易签到");
-                lifeNotice.setNoticeType(1);
-                // 封装通知信息
-                noticeMessage = new JSONObject();
-                noticeMessage.put("tradeId", tradeRecord.getId());
-                noticeMessage.put("otherSideUserId", tradeRecord.getBuyerId());
-                noticeMessage.put("otherSidePhoneId", buyerPhoneId);
-                noticeMessage.put("otherSideName", null == buyer ? "" : buyer.getUserName());
-                noticeMessage.put("otherSideImage", null == buyer ? "" : buyer.getUserImage());
-                noticeMessage.put("message", "您有一笔交易即将开始, 请及时前往查看");
-                lifeNotice.setContext(noticeMessage.toJSONString());
-                lifeNoticeMapper.insert(lifeNotice);
-
-                // 给卖家推送通知
-                websocketVo = new WebSocketVo();
-                websocketVo.setSenderId("system");
-                websocketVo.setReceiverId(sellerPhoneId);
-                websocketVo.setCategory("notice");
-                websocketVo.setNoticeType("1");
-                websocketVo.setType("5");
-                websocketVo.setText(JSONObject.from(lifeNotice).toJSONString());
-                websocketVo.setMessageId(lifeMessage.getId());
-                webSocketProcess.sendMessage(sellerPhoneId, JSONObject.from(websocketVo).toJSONString());
-            }
-        }
-    }
-
-    /**
-     * 二手交易平台 - 到达交易时间时,给买家和卖家发送交易确认提醒
-     */
-//    @Scheduled(cron = "0 * * * * ?")
-    public void secondTradeConfirm() throws Exception {
-        LocalDateTime now = LocalDateTime.now().withSecond(0).withNano(0);
-
-        // 查询所有待交易
-        LambdaQueryWrapper<SecondTradeRecord> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(SecondTradeRecord::getTradeStatus, 3);
-        List<SecondTradeRecord> tradeRecordList = secondTradeRecordMapper.selectList(wrapper);
-
-        for (SecondTradeRecord tradeRecord : tradeRecordList) {
-            LocalDateTime tenMinutesAgo = tradeRecord.getTransactionTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().withSecond(0).withNano(0);
-            // 交易时间的十分钟前
-            if (now.isEqual(tenMinutesAgo)) {
-                LifeUser buyer = lifeUserMapper.selectById(tradeRecord.getBuyerId());
-                LifeUser seller = lifeUserMapper.selectById(tradeRecord.getSellerId());
-                SecondGoods goods = secondGoodsMapper.selectById(tradeRecord.getGoodsId());
-
-                String buyerPhoneId = null == buyer ? "" : "user_" + buyer.getUserPhone();
-                String sellerPhoneId = null == seller ? "" : "user_" + seller.getUserPhone();
-
-                // 给买家发送通知
-                LifeNotice lifeNotice = new LifeNotice();
-                lifeNotice.setSenderId("system");
-                lifeNotice.setReceiverId(buyerPhoneId);
-                lifeNotice.setBusinessId(tradeRecord.getId());
-                lifeNotice.setTitle("商品是否交易成功");
-                lifeNotice.setNoticeType(1);
-                // 封装通知信息
-                JSONObject noticeMessage = new JSONObject();
-                noticeMessage.put("goodsId", goods.getId());
-                noticeMessage.put("goodsHomeImage", goods.getHomeImage());
-                noticeMessage.put("goodsTitle", goods.getTitle());
-                noticeMessage.put("tradeId", tradeRecord.getId());
-                noticeMessage.put("transactionAmount", tradeRecord.getTransactionAmount());
-                noticeMessage.put("transactionLatitudeLongitude", tradeRecord.getTransactionLatitudeLongitude());
-                noticeMessage.put("transactionLatitudeLongitudeAddress", tradeRecord.getTransactionLatitudeLongitudeAddress());
-                noticeMessage.put("transactionLocation", tradeRecord.getTransactionLocation());
-                noticeMessage.put("transactionTime", tradeRecord.getTransactionTime());
-                noticeMessage.put("tradeStatus", tradeRecord.getTradeStatus());
-                noticeMessage.put("message", "您有一笔交易已完成, 请前往确认");
-                lifeNotice.setContext(noticeMessage.toJSONString());
-                lifeNoticeMapper.insert(lifeNotice);
-
-                // 给买家推送通知
-                WebSocketVo websocketVo = new WebSocketVo();
-                websocketVo.setSenderId("system");
-                websocketVo.setReceiverId(buyerPhoneId);
-                websocketVo.setCategory("notice");
-                websocketVo.setNoticeType("1");
-                websocketVo.setType("5");
-                websocketVo.setText(JSONObject.from(lifeNotice).toJSONString());
-                webSocketProcess.sendMessage(buyerPhoneId, JSONObject.from(websocketVo).toJSONString());
-
-                // 给卖家发送通知
-                lifeNotice = new LifeNotice();
-                lifeNotice.setSenderId("system");
-                lifeNotice.setReceiverId(sellerPhoneId);
-                lifeNotice.setBusinessId(tradeRecord.getId());
-                lifeNotice.setTitle("商品是否交易成功");
-                lifeNotice.setNoticeType(1);
-                lifeNotice.setContext(noticeMessage.toJSONString());
-                lifeNoticeMapper.insert(lifeNotice);
-
-                // 给卖家推送通知
-                websocketVo = new WebSocketVo();
-                websocketVo.setSenderId("system");
-                websocketVo.setReceiverId(sellerPhoneId);
-                websocketVo.setCategory("notice");
-                websocketVo.setNoticeType("1");
-                websocketVo.setType("5");
-                websocketVo.setText(JSONObject.from(lifeNotice).toJSONString());
-                webSocketProcess.sendMessage(buyerPhoneId, JSONObject.from(websocketVo).toJSONString());
-            }
-        }
-    }
-
-    /**
-     * 二手交易平台 - 每分钟从redis中读取已读的消息id 并将数据库设为已读
-     */
-//    @Scheduled(cron = "0 * * * * ?")
-    public void readMessage() {
-        try {
-            if (CollectionUtil.isEmpty(baseRedisService.getList("readMessageIdKey"))) return;
-
-            List<String> dataList = baseRedisService.popBatchFromList("readMessageIdKey");
-            if (CollectionUtil.isNotEmpty(dataList)) {
-                LambdaUpdateWrapper<LifeMessage> wrapper = new LambdaUpdateWrapper<>();
-                wrapper.in(LifeMessage::getId, dataList)
-                        .set(LifeMessage::getIsRead, 1);
-                lifeMessageMapper.update(null, wrapper);
-            }
-        } catch (Exception e) {
-            log.error("ScheduledTask.readMessage Error Mgs={}", e.getMessage());
-        }
-    }
-}

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio