瀏覽代碼

Merge branch 'master' into bjcz_his_scrm

# Conflicts:
#	fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreHealthOrderScrmController.java
#	fs-admin/src/main/resources/application.yml
#	fs-company-app/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java
#	fs-company-app/src/main/resources/application.yml
#	fs-company/src/main/java/com/fs/company/controller/company/CompanyUserController.java
#	fs-company/src/main/java/com/fs/company/controller/qw/QwSopTempController.java
#	fs-company/src/main/resources/application.yml
#	fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java
#	fs-service/src/main/java/com/fs/course/config/CourseConfig.java
#	fs-service/src/main/java/com/fs/course/domain/FsUserCourse.java
#	fs-service/src/main/java/com/fs/course/domain/FsUserCoursePeriod.java
#	fs-service/src/main/java/com/fs/course/dto/FsOrderDeliveryNoteDTO.java
#	fs-service/src/main/java/com/fs/course/mapper/FsUserCompanyUserMapper.java
#	fs-service/src/main/java/com/fs/course/mapper/FsUserCoursePeriodDaysMapper.java
#	fs-service/src/main/java/com/fs/course/param/FsCourseWatchLogListParam.java
#	fs-service/src/main/java/com/fs/course/service/IFsUserCompanyUserService.java
#	fs-service/src/main/java/com/fs/course/service/IFsUserCoursePeriodService.java
#	fs-service/src/main/java/com/fs/course/service/IFsUserCourseService.java
#	fs-service/src/main/java/com/fs/course/service/IFsUserCourseVideoService.java
#	fs-service/src/main/java/com/fs/course/service/impl/FsCourseQuestionBankServiceImpl.java
#	fs-service/src/main/java/com/fs/course/service/impl/FsUserCompanyUserServiceImpl.java
#	fs-service/src/main/java/com/fs/course/service/impl/FsUserCoursePeriodDaysServiceImpl.java
#	fs-service/src/main/java/com/fs/course/service/impl/FsUserCoursePeriodServiceImpl.java
#	fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseServiceImpl.java
#	fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
#	fs-service/src/main/java/com/fs/course/vo/FsUserCoursePeriodVO.java
#	fs-service/src/main/java/com/fs/his/domain/FsUser.java
#	fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java
#	fs-service/src/main/java/com/fs/his/service/impl/FsStorePaymentServiceImpl.java
#	fs-service/src/main/java/com/fs/his/service/impl/FsUserServiceImpl.java
#	fs-service/src/main/java/com/fs/hisStore/config/StoreConfig.java
#	fs-service/src/main/java/com/fs/hisStore/domain/FsStoreOrderScrm.java
#	fs-service/src/main/java/com/fs/hisStore/mapper/FsStorePaymentScrmMapper.java
#	fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreProductScrmMapper.java
#	fs-service/src/main/java/com/fs/hisStore/param/FsStorePaymentParam.java
#	fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java
#	fs-service/src/main/java/com/fs/hisStore/service/impl/FsStorePaymentScrmServiceImpl.java
#	fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderCodeOpenIdVo.java
#	fs-service/src/main/java/com/fs/hisStore/vo/FsStorePaymentVO.java
#	fs-service/src/main/java/com/fs/huifuPay/sdk/opps/core/utils/HuiFuUtils.java
#	fs-service/src/main/java/com/fs/ipad/IpadSendUtils.java
#	fs-service/src/main/java/com/fs/qw/mapper/QwWatchLogMapper.java
#	fs-service/src/main/java/com/fs/qw/service/impl/CustomerTransferApprovalServiceImpl.java
#	fs-service/src/main/java/com/fs/qw/service/impl/QwExternalContactServiceImpl.java
#	fs-service/src/main/java/com/fs/sop/service/impl/QwSopTempServiceImpl.java
#	fs-service/src/main/java/com/fs/tag/service/impl/FsTagUpdateServiceImpl.java
#	fs-service/src/main/java/com/fs/wxwork/service/WxWorkServiceNew.java
#	fs-service/src/main/resources/application-dev.yml
#	fs-service/src/main/resources/application-druid-bjczwh.yml
#	fs-service/src/main/resources/mapper/company/CrmStatisticManageMapper.xml
#	fs-service/src/main/resources/mapper/course/FsCourseWatchLogMapper.xml
#	fs-service/src/main/resources/mapper/course/FsUserCompanyUserMapper.xml
#	fs-service/src/main/resources/mapper/course/FsUserCourseMapper.xml
#	fs-service/src/main/resources/mapper/course/FsUserCoursePeriodMapper.xml
#	fs-service/src/main/resources/mapper/his/FsUserMapper.xml
#	fs-service/src/main/resources/mapper/hisStore/FsStoreOrderScrmMapper.xml
#	fs-service/src/main/resources/mapper/hisStore/FsStorePaymentScrmMapper.xml
#	fs-service/src/main/resources/mapper/hisStore/FsUserScrmMapper.xml
#	fs-service/src/main/resources/mapper/sop/SopUserLogsMapper.xml
#	fs-user-app/src/main/java/com/fs/app/controller/AppLoginController.java
#	fs-user-app/src/main/java/com/fs/app/controller/WxUserController.java
#	fs-user-app/src/main/java/com/fs/app/controller/store/CompanyUserScrmController.java
#	fs-user-app/src/main/java/com/fs/app/controller/store/H5ScrmController.java
#	fs-user-app/src/main/java/com/fs/app/controller/store/WxUserScrmController.java
#	fs-user-app/src/main/resources/application.yml
吴树波 1 周之前
父節點
當前提交
ec2db95770
共有 100 個文件被更改,包括 9878 次插入791 次删除
  1. 13 6
      README.md
  2. 139 0
      deploy.sh
  3. 3 8
      fs-admin/src/main/java/com/fs/FSApplication.java
  4. 48 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyConfigController.java
  5. 27 4
      fs-admin/src/main/java/com/fs/company/controller/CompanyController.java
  6. 1 9
      fs-admin/src/main/java/com/fs/company/controller/CompanyDeductController.java
  7. 1 10
      fs-admin/src/main/java/com/fs/company/controller/CompanyRechargeController.java
  8. 572 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyUserAllController.java
  9. 1 1
      fs-admin/src/main/java/com/fs/course/controller/FsCoursePlaySourceConfigController.java
  10. 35 8
      fs-admin/src/main/java/com/fs/course/controller/FsCourseQuestionBankController.java
  11. 35 1
      fs-admin/src/main/java/com/fs/course/controller/FsCourseTrafficLogController.java
  12. 43 31
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseCompanyStatisticsController.java
  13. 79 74
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseController.java
  14. 4 0
      fs-admin/src/main/java/com/fs/course/controller/FsUserCoursePeriodController.java
  15. 13 0
      fs-admin/src/main/java/com/fs/course/controller/qw/QwFsCourseWatchLogController.java
  16. 21 0
      fs-admin/src/main/java/com/fs/course/params/FsUserCourseConfigParam.java
  17. 59 0
      fs-admin/src/main/java/com/fs/his/controller/FsCompanyController.java
  18. 18 13
      fs-admin/src/main/java/com/fs/his/controller/FsCompanyDeductController.java
  19. 24 0
      fs-admin/src/main/java/com/fs/his/controller/FsCompanyDivItemController.java
  20. 20 13
      fs-admin/src/main/java/com/fs/his/controller/FsCompanyRechargeController.java
  21. 23 0
      fs-admin/src/main/java/com/fs/his/controller/FsDoctorController.java
  22. 29 0
      fs-admin/src/main/java/com/fs/his/controller/FsInquiryOrderController.java
  23. 27 4
      fs-admin/src/main/java/com/fs/his/controller/FsInquiryOrderReportController.java
  24. 246 14
      fs-admin/src/main/java/com/fs/his/controller/FsIntegralOrderController.java
  25. 109 0
      fs-admin/src/main/java/com/fs/his/controller/FsIntegralOrderLogsController.java
  26. 30 4
      fs-admin/src/main/java/com/fs/his/controller/FsPackageOrderController.java
  27. 42 1
      fs-admin/src/main/java/com/fs/his/controller/FsPrescribeController.java
  28. 108 0
      fs-admin/src/main/java/com/fs/his/controller/FsQuestionAndAnswerController.java
  29. 114 0
      fs-admin/src/main/java/com/fs/his/controller/FsStoreActivityController.java
  30. 29 0
      fs-admin/src/main/java/com/fs/his/controller/FsStoreAfterSalesController.java
  31. 60 5
      fs-admin/src/main/java/com/fs/his/controller/FsStoreOrderController.java
  32. 29 0
      fs-admin/src/main/java/com/fs/his/controller/FsStoreSubOrderController.java
  33. 20 2
      fs-admin/src/main/java/com/fs/his/controller/FsUserController.java
  34. 94 0
      fs-admin/src/main/java/com/fs/his/controller/FsUserExtractController.java
  35. 12 0
      fs-admin/src/main/java/com/fs/his/param/BatchCreateErpOrderParam.java
  36. 13 0
      fs-admin/src/main/java/com/fs/his/param/BatchSetErpOrderParam.java
  37. 247 0
      fs-admin/src/main/java/com/fs/his/param/FurtherConsultationParam.java
  38. 329 0
      fs-admin/src/main/java/com/fs/his/param/PrescriptionParam.java
  39. 31 4
      fs-admin/src/main/java/com/fs/his/task/CompanyBalanceTask.java
  40. 480 0
      fs-admin/src/main/java/com/fs/his/task/NetMedicalService.java
  41. 77 0
      fs-admin/src/main/java/com/fs/his/task/Task.java
  42. 114 4
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreHealthOrderScrmController.java
  43. 35 0
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreOrderScrmController.java
  44. 13 2
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStorePaymentScrmController.java
  45. 12 0
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreProductScrmController.java
  46. 57 19
      fs-admin/src/main/java/com/fs/hisStore/task/ErpTask.java
  47. 29 0
      fs-admin/src/main/java/com/fs/hisStore/task/ExpressTask.java
  48. 517 0
      fs-admin/src/main/java/com/fs/hisStore/task/LiveTask.java
  49. 7 1
      fs-admin/src/main/java/com/fs/hisStore/task/MallStoreTask.java
  50. 46 0
      fs-admin/src/main/java/com/fs/live/aspectj/LiveControllerAspect.java
  51. 193 0
      fs-admin/src/main/java/com/fs/live/controller/LiveAfterSalesController.java
  52. 97 0
      fs-admin/src/main/java/com/fs/live/controller/LiveAfterSalesItemController.java
  53. 97 0
      fs-admin/src/main/java/com/fs/live/controller/LiveAfterSalesLogsController.java
  54. 8 14
      fs-admin/src/main/java/com/fs/live/controller/LiveAnchorController.java
  55. 227 0
      fs-admin/src/main/java/com/fs/live/controller/LiveAutoTaskController.java
  56. 98 0
      fs-admin/src/main/java/com/fs/live/controller/LiveCartController.java
  57. 98 29
      fs-admin/src/main/java/com/fs/live/controller/LiveController.java
  58. 227 0
      fs-admin/src/main/java/com/fs/live/controller/LiveCouponController.java
  59. 103 0
      fs-admin/src/main/java/com/fs/live/controller/LiveCouponIssueController.java
  60. 103 0
      fs-admin/src/main/java/com/fs/live/controller/LiveCouponIssueUserController.java
  61. 105 0
      fs-admin/src/main/java/com/fs/live/controller/LiveCouponUserController.java
  62. 113 0
      fs-admin/src/main/java/com/fs/live/controller/LiveDataController.java
  63. 97 0
      fs-admin/src/main/java/com/fs/live/controller/LiveEventConfController.java
  64. 97 0
      fs-admin/src/main/java/com/fs/live/controller/LiveGiftController.java
  65. 107 29
      fs-admin/src/main/java/com/fs/live/controller/LiveGoodsController.java
  66. 0 103
      fs-admin/src/main/java/com/fs/live/controller/LiveGoodsOrderController.java
  67. 0 103
      fs-admin/src/main/java/com/fs/live/controller/LiveGoodsOrderItemsController.java
  68. 419 0
      fs-admin/src/main/java/com/fs/live/controller/LiveHealthOrderController.java
  69. 143 0
      fs-admin/src/main/java/com/fs/live/controller/LiveLotteryConfController.java
  70. 97 0
      fs-admin/src/main/java/com/fs/live/controller/LiveLotteryRecordController.java
  71. 97 0
      fs-admin/src/main/java/com/fs/live/controller/LiveLotteryRegistrationController.java
  72. 22 20
      fs-admin/src/main/java/com/fs/live/controller/LiveMsgController.java
  73. 731 0
      fs-admin/src/main/java/com/fs/live/controller/LiveOrderController.java
  74. 97 0
      fs-admin/src/main/java/com/fs/live/controller/LiveOrderItemController.java
  75. 97 0
      fs-admin/src/main/java/com/fs/live/controller/LiveOrderLogsController.java
  76. 118 0
      fs-admin/src/main/java/com/fs/live/controller/LiveOrderPaymentController.java
  77. 0 103
      fs-admin/src/main/java/com/fs/live/controller/LiveQuestionController.java
  78. 125 0
      fs-admin/src/main/java/com/fs/live/controller/LiveRedConfController.java
  79. 4 0
      fs-admin/src/main/java/com/fs/live/controller/LiveRedController.java
  80. 125 0
      fs-admin/src/main/java/com/fs/live/controller/LiveRewardRecordController.java
  81. 98 0
      fs-admin/src/main/java/com/fs/live/controller/LiveSensitiveWordsController.java
  82. 122 0
      fs-admin/src/main/java/com/fs/live/controller/LiveTrafficLogController.java
  83. 97 0
      fs-admin/src/main/java/com/fs/live/controller/LiveUserFavoriteController.java
  84. 97 0
      fs-admin/src/main/java/com/fs/live/controller/LiveUserFollowController.java
  85. 97 0
      fs-admin/src/main/java/com/fs/live/controller/LiveUserLikeController.java
  86. 108 0
      fs-admin/src/main/java/com/fs/live/controller/LiveUserLotteryRecordController.java
  87. 97 0
      fs-admin/src/main/java/com/fs/live/controller/LiveUserRedRecordController.java
  88. 33 20
      fs-admin/src/main/java/com/fs/live/controller/LiveVideoController.java
  89. 102 0
      fs-admin/src/main/java/com/fs/live/controller/LiveWatchConfigController.java
  90. 63 20
      fs-admin/src/main/java/com/fs/live/controller/LiveWatchUserController.java
  91. 326 0
      fs-admin/src/main/java/com/fs/qw/controller/IpadAllocationRecordsController.java
  92. 138 0
      fs-admin/src/main/java/com/fs/qw/controller/QwDeptController.java
  93. 2 0
      fs-admin/src/main/java/com/fs/qw/controller/QwSopTempController.java
  94. 309 5
      fs-admin/src/main/java/com/fs/qw/controller/QwUserController.java
  95. 93 6
      fs-admin/src/main/java/com/fs/qw/qwTask/qwTask.java
  96. 51 25
      fs-admin/src/main/java/com/fs/task/FsCompanyTask.java
  97. 30 39
      fs-admin/src/main/java/com/fs/web/controller/system/SysConfigController.java
  98. 0 37
      fs-admin/src/test/java/com/fs/api/controller/IndexStatisticsControllerTest.java
  99. 1 0
      fs-common/src/main/java/com/fs/common/constant/FsConstants.java
  100. 34 0
      fs-common/src/main/java/com/fs/common/constant/LiveKeysConstant.java

+ 13 - 6
README.md

@@ -5,14 +5,21 @@
 
 #### 软件模块说明
 
-| 模块名称         | 模块描述         | 对应前端项目                  |
-|--------------|--------------|-------------------------|
-| fs-admin     | 总后台服务        | ylrz_his_scrm_adminUI   |
-| fs-company   | 销售端          | ylrz_his_scrm_companyUI |
-| fs-user-app  | 微信小程序端       | 对应某个微信小程序(前端蒲瑶清楚)       |
-| fs-framework | 主要依赖包,核心包    | /                       |
+| 模块名称         | 模块描述          | 对应前端项目                  |
+|--------------|---------------|-------------------------|
+| fs-admin     | 总后台服务         | ylrz_his_scrm_adminUI   |
+| fs-company   | 销售端           | ylrz_his_scrm_companyUI |
+| fs-store     | 店铺端           | ylrz_his_scrm_storeUI |
+| fs-doctor    | 医生端           | ylrz_his_scrm_doctorUI |
+| fs-user-app  | 微信小程序端        | 对应某个微信小程序(前端蒲瑶清楚)       |
+| fs-framework | 主要依赖包,核心包     | /                       |
 | fs-service   | 所有的链接配置文件都在里面 | /                       |
 
+#### 分支说明
+| 分支名称       | 描述    | 对应前端项目与分支                                                                |
+|------------|-------|--------------------------------------------------------------------------|
+| ScrmStores | 医建宝项目 | ylrz_his_scrm_adminUI(yjb_ScrmStores)、ylrz_his_scrm_companyUI(ScrmStore) |
+
 
 #### 安装教程
 

+ 139 - 0
deploy.sh

@@ -0,0 +1,139 @@
+#!/bin/bash
+
+# 各服务对应的远程服务器配置 北京卓美
+declare -A SERVER_CONFIG=(
+    # 服务名:IP地址
+    ["fs-live-app"]="114.132.218.150"
+)
+
+# 通用配置(所有服务器相同)
+REMOTE_USER="root"
+REMOTE_BASE_DIR="/home/software"
+
+# 本地 JAR 包路径
+LOCAL_FS_LIVE_SOCKET_JAR="./fs-live-app/target/fs-live-app.jar"
+
+# 函数:检查本地文件是否存在
+check_local_file() {
+    if [ ! -f "$1" ]; then
+        echo "错误: 本地文件 $1 不存在。"
+        exit 1
+    fi
+}
+
+# 停止远程服务器上可能正在运行的旧版本
+stop_remote_app() {
+    local remote_user=$1
+    local remote_host=$2
+    local app_name=$3
+
+    echo "正在停止 $remote_host 上的 $app_name 服务..."
+    ssh "$remote_user@$remote_host" "pkill -f $app_name || echo '没有找到运行中的进程'"
+}
+
+# 检查服务器连通性
+check_server_connectivity() {
+    local remote_user=$1
+    local remote_host=$2
+
+    if ! ssh -o ConnectTimeout=5 "$remote_user@$remote_host" "echo '连接成功'" &>/dev/null; then
+        echo "错误: 无法连接到服务器 $remote_host"
+        return 1
+    fi
+    return 0
+}
+
+# 部署单个 JAR 包到指定服务器
+deploy_jar() {
+    local local_jar=$1
+    local service_name=$2  # 服务名,用于确定目标服务器
+    local remote_dir=$3     # 远程目录名
+
+    # 获取服务对应的服务器IP
+    local remote_host="${SERVER_CONFIG[$service_name]}"
+    if [ -z "$remote_host" ]; then
+        echo "错误: 未找到服务 $service_name 的服务器配置"
+        return 1
+    fi
+
+    local app_name=$(basename "$local_jar" .jar)
+
+    echo "========================================"
+    echo "开始部署 $service_name 到服务器 $remote_host"
+    echo "本地文件: $local_jar"
+    echo "远程目录: $REMOTE_BASE_DIR/$remote_dir"
+    echo "========================================"
+
+    # 检查本地文件
+    check_local_file "$local_jar"
+
+    # 检查服务器连通性
+    if ! check_server_connectivity "$REMOTE_USER" "$remote_host"; then
+        return 1
+    fi
+
+    # 创建远程目录(如果不存在)
+    echo "创建远程目录..."
+    ssh "$REMOTE_USER@$remote_host" "mkdir -p $REMOTE_BASE_DIR/$remote_dir"
+
+    # 停止旧版本
+    stop_remote_app "$REMOTE_USER" "$remote_host" "$app_name"
+
+    # 上传 JAR 包
+    echo "上传 JAR 包..."
+    scp "$local_jar" "$REMOTE_USER@$remote_host:$REMOTE_BASE_DIR/$remote_dir/"
+
+    # 在后台启动 JAR 包
+    echo "启动服务..."
+    ssh -f "$REMOTE_USER@$remote_host" \
+    "cd $REMOTE_BASE_DIR/$remote_dir && \
+     nohup java -jar  -Dfile.encoding=UTF-8 $app_name.jar --spring.profiles.active=druid-bjzm --server.port=7114  \
+     >> $app_name.log 2>&1 &"
+
+    # 检查进程是否启动成功
+    if ssh "$REMOTE_USER@$remote_host" "pgrep -f $app_name" &>/dev/null; then
+        echo "✓ $service_name 部署成功到 $remote_host"
+    else
+        echo "✗ $service_name 启动失败,请检查日志: $REMOTE_BASE_DIR/$remote_dir/$app_name.log"
+        return 1
+    fi
+
+    echo ""
+}
+
+# 主要部署流程
+echo "开始多服务器分布式部署..."
+echo "部署配置:"
+for service in "${!SERVER_CONFIG[@]}"; do
+    echo "  $service -> ${SERVER_CONFIG[$service]}"
+done
+echo ""
+
+# 部署 fs-live-app
+deploy_jar "$LOCAL_FS_LIVE_SOCKET_JAR" "fs-live-app" "fs-live-app"
+
+# 部署 fs-sync (注意:这里使用了不同的JAR命名方式)
+#deploy_jar "$LOCAL_FS_SYNC_APP_JAR" "fs-sync" "fs-sync"
+
+echo "========================================"
+echo "分布式部署完成!"
+echo "各服务部署状态:"
+for service in "${!SERVER_CONFIG[@]}"; do
+    remote_host="${SERVER_CONFIG[$service]}"
+    echo "  $service -> $remote_host"
+done
+echo "========================================"
+
+# 可选:显示各服务进程状态
+#echo "服务进程状态检查:"
+#for service in "${!SERVER_CONFIG[@]}"; do
+#    remote_host="${SERVER_CONFIG[$service]}"
+#    app_name="$service"  # 简化处理,实际可能需要根据JAR文件名调整
+#    if ssh "$REMOTE_USER@$remote_host" "pgrep -f $app_name" &>/dev/null; then
+#        echo "  ✓ $service 在 $remote_host 上运行正常"
+#    else
+#        echo "  ✗ $service 在 $remote_host 上未运行"
+#    fi
+#done
+
+# 251105 0953

+ 3 - 8
fs-admin/src/main/java/com/fs/FSApplication.java

@@ -1,11 +1,8 @@
 package com.fs;
 
-import com.qiniu.common.Zone;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
-import org.springframework.core.io.Resource;
-import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
 import org.springframework.scheduling.annotation.EnableAsync;
 import org.springframework.scheduling.annotation.EnableScheduling;
 import org.springframework.transaction.annotation.Transactional;
@@ -13,14 +10,12 @@ import org.springframework.transaction.annotation.Transactional;
 /**
  * 启动程序
  */
-@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
+@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
 @Transactional
 @EnableAsync
 @EnableScheduling
-public class FSApplication
-{
-    public static void main(String[] args)
-    {
+public class FSApplication {
+    public static void main(String[] args) {
         // System.setProperty("spring.devtools.restart.enabled", "false");
         SpringApplication.run(FSApplication.class, args);
         System.out.println("admin启动成功");

+ 48 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyConfigController.java

@@ -0,0 +1,48 @@
+package com.fs.company.controller;
+
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.company.service.ICompanyConfigService;
+import com.fs.system.domain.SysConfig;
+import com.fs.system.service.ISysConfigService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 系统配置
+ *
+
+ */
+@RestController
+@RequestMapping("/company/companyConfig")
+public class CompanyConfigController extends BaseController
+{
+
+    @Autowired
+    private ICompanyConfigService companyConfigService;
+
+
+    @Autowired
+    private ISysConfigService configService;
+
+
+
+    /**
+     * 根据参数键名查询总后台参数值
+     * @param configKey
+     * @return
+     */
+    @GetMapping(value = "/getConfigByKey/{configKey}")
+    public AjaxResult getConfigByKey(@PathVariable String configKey)
+    {
+        SysConfig config=configService.selectConfigByConfigKey(configKey);
+        return AjaxResult.success(config);
+    }
+
+
+
+}

+ 27 - 4
fs-admin/src/main/java/com/fs/company/controller/CompanyController.java

@@ -10,16 +10,14 @@ import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.model.LoginUser;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ParseUtils;
 import com.fs.common.utils.SecurityUtils;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.common.utils.sign.Md5Utils;
 import com.fs.company.domain.*;
-import com.fs.company.param.CompanyDeductParam;
-import com.fs.company.param.CompanyParam;
-import com.fs.company.param.CompanyRechargeParam;
-import com.fs.company.param.CompanyVoiceCallerParam;
+import com.fs.company.param.*;
 import com.fs.company.service.*;
 import com.fs.company.vo.CompanyCrmVO;
 import com.fs.company.vo.CompanyVO;
@@ -34,6 +32,7 @@ import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
 
+import java.text.ParseException;
 import java.util.List;
 
 /**
@@ -60,6 +59,30 @@ public class CompanyController extends BaseController
     private ICompanyVoiceCallerService callerService;
     @Autowired
     private ISysConfigService configService;
+
+    /**
+     * 查询企业列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveMiniLives:list')")
+    @GetMapping("/liveShowList")
+    public TableDataInfo liveShowList(CompanyParam param) throws ParseException {
+        startPage();
+        List<CompanyVO> list = companyService.liveShowList(param);
+        for (CompanyVO vo : list){
+            vo.setCompanyMobile(ParseUtils.parsePhone(vo.getCompanyMobile()));
+        }
+        return getDataTable(list);
+    }
+
+    @PostMapping(value = "/batchUpdateLiveShow")
+    public R batchUpdateLiveShow(@RequestBody CompanyLiveShowParam param) {
+        if (param.getIds().isEmpty()) {
+            return R.error("请选择要操作的记录");
+        }
+        companyService.batchUpdateLiveShow(param);
+        return R.ok();
+    }
+
     /**
      * 查询企业列表
      */

+ 1 - 9
fs-admin/src/main/java/com/fs/company/controller/CompanyDeductController.java

@@ -133,15 +133,7 @@ public class CompanyDeductController extends BaseController
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         if(deduct.getIsAudit()==1){
             Company company=companyService.selectCompanyByIdForUpdate(deduct.getCompanyId());
-
-            // 同步redis缓存
-            R r = companyRechargeService.syncUpdateRedisCompanyRecharge(company, deduct.getMoney(), 2);
-            if(!"200".equals(r.get("code").toString())){
-                return r;
-            }
-            // 充值后,需要同步更新余额到数据库,否则余额与缓存中的不一致
-            String newMoney = r.get("newMoney").toString();
-            company.setMoney(new BigDecimal(newMoney));
+            company.setMoney(company.getMoney().subtract(deduct.getMoney()));
             companyService.updateCompany(company);
             CompanyMoneyLogs log=new CompanyMoneyLogs();
             log.setCompanyId(deduct.getCompanyId());

+ 1 - 10
fs-admin/src/main/java/com/fs/company/controller/CompanyRechargeController.java

@@ -122,16 +122,7 @@ public class CompanyRechargeController extends BaseController
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         if(companyRecharge.getIsAudit()==1){
             Company company=companyService.selectCompanyById(companyRecharge.getCompanyId());
-
-            // 同步redis缓存
-            // 注意:在进行充值审核之前,需要先执行一下定时任务同步缓存数据到数据库,再进行后续操作,否则金额不正确
-            R r = companyRechargeService.syncUpdateRedisCompanyRecharge(company, companyRecharge.getMoney(), 1);
-            if(!"200".equals(r.get("code").toString())){
-                return r;
-            }
-            // 充值后,需要同步更新余额到数据库,否则余额与缓存中的不一致
-            String newMoney = r.get("newMoney").toString();
-            company.setMoney(new BigDecimal(newMoney));
+            company.setMoney(company.getMoney().add(companyRecharge.getMoney()));
             companyService.updateCompany(company);
             CompanyMoneyLogs log=new CompanyMoneyLogs();
             log.setCompanyId(companyRecharge.getCompanyId());

+ 572 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyUserAllController.java

@@ -0,0 +1,572 @@
+package com.fs.company.controller;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.json.JSONUtil;
+import com.baidu.dev2.thirdparty.jackson.databind.ObjectMapper;
+import com.fs.common.annotation.Log;
+import com.fs.common.constant.UserConstants;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.core.redis.RedisCache;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.PatternUtils;
+import com.fs.common.utils.SecurityUtils;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.*;
+import com.fs.company.param.CompanyUserAreaParam;
+import com.fs.company.param.CompanyUserCodeParam;
+import com.fs.company.param.CompanyUserQwParam;
+import com.fs.company.service.*;
+import com.fs.company.vo.BatchUserRolesVO;
+import com.fs.company.vo.CompanyUserImportVO;
+import com.fs.company.vo.CompanyUserQwListVO;
+import com.fs.company.vo.CompanyUserVO;
+import com.fs.course.config.CourseConfig;
+import com.fs.framework.web.service.TokenService;
+import com.fs.his.utils.qrcode.QRCodeUtils;
+import com.fs.his.vo.OptionsVO;
+import com.fs.hisStore.vo.FsStoreProductExportVO;
+import com.fs.im.config.IMConfig;
+import com.fs.im.dto.OpenImResponseDTO;
+import com.fs.im.service.OpenIMService;
+import com.fs.qw.domain.QwCompany;
+import com.fs.qw.service.IQwCompanyService;
+import com.fs.qw.service.IQwUserService;
+import com.fs.qw.vo.CompanyUserQwVO;
+import com.fs.qw.vo.QwUserVO;
+import com.fs.system.service.ISysConfigService;
+import com.fs.utils.DomainUtil;
+import com.fs.utils.QwStatusEnum;
+import com.fs.voice.utils.StringUtil;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.ApiOperation;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.util.Assert;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.stream.Collectors;
+
+
+/**
+ * 用户信息
+ */
+@RestController
+@RequestMapping("/company/CompanyUserAll")
+public class CompanyUserAllController extends BaseController {
+
+    @Autowired
+    private ICompanyRoleService roleService;
+
+    @Autowired
+    private ICompanyPostService postService;
+
+    @Autowired
+    private ICompanyUserService companyUserService;
+
+    @Autowired
+    private ICompanyService companyService;
+
+    @Autowired
+    private ICompanyUserDelayTimeService companyUserDelayTimeService;
+
+    @Autowired
+    private ISysConfigService configService;
+
+    @Autowired
+    private RedisCache redisCache;
+
+    @Autowired
+    private OpenIMService openIMService;
+
+    @Autowired
+    IQwCompanyService iQwCompanyService;
+
+    @Autowired
+    private IQwUserService qwUserService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    private static final String appLink = "https://jump.ylrztop.com/jumpapp/pages/index/index?link=";
+
+
+    @GetMapping("/getList")
+    public TableDataInfo getList(CompanyUser user)
+    {
+        startPage();
+        List<CompanyUser> list = companyUserService.selectCompanyUserList(user);
+        return getDataTable(list);
+    }
+    @GetMapping("/qwList")
+    public TableDataInfo qwList(CompanyUserQwParam user) {
+        List<CompanyUserQwListVO> list = companyUserService.selectCompanyUserQwListVO(user);
+        if (!list.isEmpty()){
+            String json = configService.selectConfigByKey("course.config");
+            CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+            Long sendDelayTime = config.getSendDelayTime();
+            List<CompletableFuture<Void>> futures = new ArrayList<>();
+            for (CompanyUserQwListVO companyUserQwListVO : list) {
+                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
+                    CompanyUserDelayTime companyUserDelayTime = companyUserDelayTimeService.selectCompanyUserDelayTimeByCompanyUser(companyUserQwListVO.getCompanyId(), companyUserQwListVO.getUserId());
+                    if (ObjectUtil.isEmpty(companyUserDelayTime)) {
+                        companyUserQwListVO.setSendDelayTime(sendDelayTime);
+                    } else {
+                        companyUserQwListVO.setSendDelayTime(companyUserDelayTime.getSendDelayTime());
+                    }
+                    //是否绑定
+                    if(QwStatusEnum.BOUND.getCode() == companyUserQwListVO.getQwStatus()){
+                        if(!companyUserQwListVO.getQwUserId().isEmpty()){
+                            Long[] ids = Arrays.stream(companyUserQwListVO.getQwUserId().split(","))
+                                    .map(Long::parseLong)
+                                    .toArray(Long[]::new);
+                            List<QwUserVO> qwUserVOS = qwUserService.selectQwUserVOByIds(ids);
+                            companyUserQwListVO.setQwUsers(qwUserVOS);
+                        }
+                    }
+                });
+                futures.add(future);
+            }
+            CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
+        }
+        return getDataTable(list);
+    }
+
+    @Log(title = "用户管理导出", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('company:user:export')")
+    @GetMapping("/export")
+    public AjaxResult export(CompanyUser user)
+    {
+        List<CompanyUser> list = companyUserService.selectCompanyUserList(user);
+        ExcelUtil<CompanyUser> util = new ExcelUtil<CompanyUser>(CompanyUser.class);
+        return util.exportExcel(list, "用户数据");
+    }
+
+
+    @Log(title = "销售信息导入", businessType = BusinessType.IMPORT,isStoreLog = true,logParam = {"销售","信息导入"})
+    @PreAuthorize("@ss.hasPermi('company:user:import')")
+    @PostMapping("/importCompanyUser")
+    public AjaxResult importData(@RequestParam("file") MultipartFile file, boolean updateSupport) throws Exception
+    {
+        ExcelUtil<CompanyUserImportVO> util = new ExcelUtil<>(CompanyUserImportVO.class);
+        List<CompanyUserImportVO> list = util.importExcel(file.getInputStream());
+        String message = companyUserService.importCompanyUser(list, updateSupport);
+        return AjaxResult.success(message);
+    }
+
+
+    @GetMapping("/importTemplate")
+    public AjaxResult importTemplate()
+    {
+        ExcelUtil<CompanyUserImportVO> util = new ExcelUtil<>(CompanyUserImportVO.class);
+        return util.importTemplateExcel("销售数据");
+    }
+
+
+
+    /**
+     * 根据用户编号获取详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:user:query')")
+    @GetMapping(value = { "/", "/{userId}" })
+    public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId)
+    {
+        AjaxResult ajax = AjaxResult.success();
+        CompanyRole companyRoleMap=new CompanyRole();
+
+        CompanyUser userById = companyUserService.selectCompanyUserById(userId);
+        companyRoleMap.setCompanyId(userById.getCompanyId());
+        List<CompanyRole> roles = roleService.selectCompanyRoleList(companyRoleMap);
+
+        ajax.put("roles", CompanyUser.isAdmin(userById.getUserType()) ? roles : roles.stream().filter(r -> r.getRoleKey()!="admin").collect(Collectors.toList()));
+
+        CompanyPost postMap=new CompanyPost();
+        postMap.setCompanyId(userById.getCompanyId());
+        ajax.put("posts", postService.selectCompanyPostList(postMap));
+        if (StringUtils.isNotNull(userId))
+        {
+            CompanyUser companyUser=companyUserService.selectCompanyUserById(userId);
+            ajax.put(AjaxResult.DATA_TAG, companyUser);
+            ajax.put("postIds", postService.selectPostListByUserId(userId));
+            ajax.put("roleIds", roleService.selectRoleListByUserId(userId));
+
+
+        }
+        return ajax;
+    }
+
+    /**
+     * 根据用户编号获取详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:user:query')")
+    @GetMapping("/addInfo/{companyId}")
+    public AjaxResult addInfo(@PathVariable(value = "companyId", required = true) Long companyId)
+    {
+        AjaxResult ajax = AjaxResult.success();
+
+        CompanyRole companyRoleMap=new CompanyRole();
+        companyRoleMap.setCompanyId(companyId);
+        List<CompanyRole> roles = roleService.selectCompanyRoleList(companyRoleMap);
+
+        ajax.put("roles", CompanyUser.isAdmin("01") ? roles : roles.stream().filter(r -> r.getRoleKey()!="admin").collect(Collectors.toList()));
+
+        CompanyPost postMap=new CompanyPost();
+        postMap.setCompanyId(companyId);
+        ajax.put("posts", postService.selectCompanyPostList(postMap));
+
+        return ajax;
+    }
+
+    /**
+     * 新增用户
+     */
+    @PreAuthorize("@ss.hasPermi('company:user:add')")
+    @Log(title = "用户管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody CompanyUser user)
+    {
+        if (!PatternUtils.checkPassword(user.getPassword())) {
+            return AjaxResult.error("密码格式不正确,需包含字母、数字和特殊字符,长度为 8-20 位");
+        }
+
+        //判断用户数量是否已达到上线
+
+        Integer count=companyUserService.selectCompanyUserCountByCompanyId(user.getCompanyId());
+        Company company=companyService.selectCompanyById(user.getCompanyId());
+
+        if(count>company.getLimitUserCount()){
+            return AjaxResult.error("用户数量已达到上限");
+        }
+        user.setCompanyId(user.getCompanyId());
+        if (UserConstants.NOT_UNIQUE.equals(String.valueOf(companyUserService.checkUserName(user.getUserName()))))
+        {
+            return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
+        }
+        if (!StringUtil.strIsNullOrEmpty(user.getDomain())){
+            user.setDomain(user.getDomain().replaceAll("^[\\s\\u2005]+", ""));
+        }
+
+        user.setCreateBy(SecurityUtils.getUsername());
+        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
+        user.setCreateTime(new Date());
+        user.setUserType("01");//一般用户
+        user.setIsAudit(1);
+        return toAjax(companyUserService.insertUser(user));
+    }
+
+    /**
+     * 生成创建销售的二维码
+     */
+
+    @PreAuthorize("@ss.hasPermi('company:user:addCodeUrl')")
+    @Log(title = "生成创建销售的二维码", businessType = BusinessType.INSERT)
+    @PostMapping("/addCodeUrl")
+    public R addCodeUrl( @RequestBody CompanyUserCodeParam user) throws Exception {
+
+        QwCompany qwCompany = iQwCompanyService.getQwCompanyByRedis(user.getCorpId());
+        if (qwCompany == null || qwCompany.getCorpId() == null){
+            return R.error("企业信息不存在");
+        }
+
+        //部门
+        Long deptId = user.getDeptId();
+
+        //角色组
+        Long[] roleIds = user.getRoleIds();
+
+        //区域
+        String addressId = user.getAddressId();
+
+
+        Map<String, Object> stateMap = new HashMap<>();
+        stateMap.put("companyId", user.getCompanyId());
+        stateMap.put("deptId", deptId);
+        stateMap.put("roleIds", roleIds); // 数组可以直接存放
+        stateMap.put("addressId", addressId);
+
+        // 使用JSON库将Map转换为字符串
+        ObjectMapper objectMapper = new ObjectMapper();
+        String status = objectMapper.writeValueAsString(stateMap);
+
+        // 如果要将status作为URL参数传递,记得进行URL编码!
+        String encodedStatus = URLEncoder.encode(status, StandardCharsets.UTF_8.toString());
+
+        String url="https://open.weixin.qq.com/connect/oauth2/authorize?appid="+user.getCorpId()+"&redirect_uri=" +
+                "http://"+qwCompany.getRealmNameUrl()+"/loginqw/pages/companyLogin/index?corpId="+user.getCorpId() +
+                "&response_type=code&scope=snsapi_base&state="+encodedStatus+"&agentid="+qwCompany.getServerAgentId()+"#wechat_redirect";
+
+        R andUpload = QRCodeUtils.createAndUpload(url);
+        return  R.ok().put("data",andUpload);
+    }
+    /**
+     * 修改用户
+     */
+    @PreAuthorize("@ss.hasPermi('company:user:edit')")
+    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody CompanyUser user)
+    {
+
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        user.setUpdateBy(SecurityUtils.getUsername());
+
+        if (!StringUtil.strIsNullOrEmpty(user.getDomain())){
+            user.setDomain(user.getDomain().replaceAll("^[\\s\\u2005]+", ""));
+        }
+
+        CompanyUser companyUser = companyUserService.selectCompanyUserById(user.getUserId());
+
+        if (!companyUser.getUserName().equals(user.getUserName())){
+            if (UserConstants.NOT_UNIQUE.equals(String.valueOf(companyUserService.checkUserName(user.getUserName()))))
+            {
+                return AjaxResult.error("修改员工账号'" + user.getUserName() + "'失败,员工账号已存在");
+            }
+        }
+
+
+        logger.info("用户管理-修改用户:"+user.getUserName()+"/登陆人:"+loginUser.getUser().getUserId()+"/名字:"+loginUser.getUser().getUserName()+"/修改的角色:"+ Arrays.toString(user.getRoleIds()));
+        return toAjax(companyUserService.updateUser(user));
+    }
+
+    /**
+     * 删除用户
+     */
+    @PreAuthorize("@ss.hasPermi('company:user:remove')")
+    @Log(title = "用户管理", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{userIds}")
+    public AjaxResult remove(@PathVariable Long[] userIds)
+    {
+        for (Long userId : userIds) {
+            CompanyUser companyUser = companyUserService.selectCompanyUserById(userId);
+            CompanyUserDelayTime companyUserDelayTime = companyUserDelayTimeService.selectCompanyUserDelayTimeByCompanyUser(companyUser.getCompanyId(),userId);
+            if (ObjectUtil.isNotEmpty(companyUserDelayTime)){
+                companyUserDelayTimeService.deleteCompanyUserDelayTimeById(companyUserDelayTime.getId());
+            }
+        }
+        return toAjax(companyUserService.deleteCompanyUserByIds(userIds));
+    }
+
+    /**
+     * 重置密码
+     */
+    @PreAuthorize("@ss.hasPermi('company:user:edit')")
+    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
+    @PutMapping("/resetPwd")
+    public AjaxResult resetPwd(@RequestBody CompanyUser user)
+    {
+        if (!PatternUtils.checkPassword(user.getPassword())) {
+            return AjaxResult.error("密码格式不正确,需包含字母、数字和特殊字符,长度为 8-20 位");
+        }
+
+        String newPassword = SecurityUtils.encryptPassword(user.getPassword());
+        int i = companyUserService.resetUserPwdByUserId(user.getUserId(), newPassword);
+
+        if (i > 0) {
+            // 更新缓存用户密码
+            redisCache.deleteObject("newCompanyUser:" + user.getCompanyId() + ":" + user.getUserName());
+        }
+
+        return toAjax(i);
+    }
+
+    /**
+     * 状态修改
+     */
+    @PreAuthorize("@ss.hasPermi('company:user:edit')")
+    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
+    @PutMapping("/changeStatus")
+    public AjaxResult changeStatus(@RequestBody CompanyUser user)
+    {
+        //管理员的状态不能修改
+        CompanyUser companyUser=companyUserService.selectCompanyUserById(user.getUserId());
+        if(companyUser.isAdmin()){
+            return AjaxResult.error("不能修改管理员状态");
+        }
+        user.setUpdateBy(SecurityUtils.getUsername());
+        return toAjax(companyUserService.updateCompanyUser(user));
+    }
+
+
+
+
+    /**
+     * 获取区域
+     */
+    @GetMapping("/getCitysAreaList")
+    public R getCitysAreaList(){
+        return R.ok().put("data",companyUserService.getCitysAreaList());
+    }
+
+    /**
+     * 批量修改 销售的所属区域(临时的)
+     */
+    @PostMapping("/updateCompanyUserAreaList")
+    public R updateCompanyUserAreaList(@RequestBody CompanyUserAreaParam param)
+    {
+        return companyUserService.updateCompanyUserAreaList(param);
+    }
+
+
+    @GetMapping("/generateSubDomain")
+    public R generateSubDomain(CompanyUser user){
+        //获取后台配置
+        String json= configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        // 生成二级域名
+        String subDomain = "http://" + DomainUtil.generateSubDomain(config.getCourseDomainName(), 6, String.valueOf(SecurityUtils.getLoginUser().getUser().getUserId()));
+        return  R.ok().put("data",subDomain);
+    }
+
+    @Log(title = "设置是否需要单独注册会员", businessType = BusinessType.UPDATE)
+    @PutMapping("/setRegister")
+    public AjaxResult setIsRegisterMember(@RequestParam Boolean status, @RequestBody List<Long> userIds) {
+        Boolean r = companyUserService.setIsRegisterMember(status, userIds);
+        if (r) {
+            return AjaxResult.success();
+        } else {
+            return AjaxResult.error("操作失败");
+        }
+    }
+
+    @Log(title = "是否允许所有方式注册会员", businessType = BusinessType.UPDATE)
+    @PutMapping("/allowedAllRegister")
+    public AjaxResult isAllowedAllRegister(@RequestParam Boolean status, @RequestBody List<Long> userIds) {
+        Boolean r = companyUserService.isAllowedAllRegister(status, userIds);
+        if (r) {
+            return AjaxResult.success();
+        } else {
+            return AjaxResult.error("操作失败");
+        }
+    }
+    @PostMapping("/common/uploadOSS")
+    public R uploadOSS(@RequestParam("file") MultipartFile file,
+                       @RequestParam("userId") String userId) throws Exception {
+        String url = companyUserService.uploadQrCode(file, userId);
+        return R.ok().put("url", url);
+    }
+
+
+    /**
+     * 销售解除绑定医生
+     */
+    @PreAuthorize("@ss.hasPermi('qw:companyUser:unBindDoctorId')")
+    @Log(title = "销售解除绑定医生", businessType = BusinessType.UPDATE)
+    @GetMapping("/unBindDoctorId/{userId}")
+    public R bindDoctorId(@PathVariable("userId") Long userId){
+        return companyUserService.unBindDoctor(userId);
+    }
+
+    /**
+     * 销售绑定医生
+     */
+    @PreAuthorize("@ss.hasPermi('qw:companyUser:bindDoctorId')")
+    @Log(title = "销售绑定医生", businessType = BusinessType.UPDATE)
+    @PostMapping("/bindDoctorId")
+    public R unBindDoctorId(@RequestBody CompanyUser companyUser){
+        return companyUserService.bindDoctor(companyUser);
+    }
+
+    /**
+     * 批量修改角色
+     * @param batchUserRolesVO
+     */
+    @PreAuthorize("@ss.hasPermi('company:user:edit')")
+    @Log(title = "批量修改角色", businessType = BusinessType.UPDATE)
+    @PostMapping("/updateBatchUserRoles")
+    public R updateBatchUserRoles(@RequestBody BatchUserRolesVO batchUserRolesVO){
+        Assert.notEmpty(batchUserRolesVO.getRoleIds(), "角色不能为空");
+        Assert.notEmpty(batchUserRolesVO.getUserIds(), "用户不能为空");
+        return companyUserService.updateBatchUserRoles(batchUserRolesVO);
+    }
+
+
+    @ApiOperation("校验客服是否注册新的im")
+    @PostMapping("/accountCheck")
+    public R accountCheck(@RequestBody Map<String, String> userIdMap){
+        //获取管理员token
+        String userId = userIdMap.get("userId");
+        String adminToken = openIMService.getAdminToken();
+        JSONObject requestBody = new JSONObject();
+        // 解析响应
+        if (StringUtils.isNotEmpty(adminToken)) {
+            //查询用户是否注册
+            ArrayList<String> userIds = new ArrayList<>();
+            requestBody = new JSONObject();
+            userIds.add(userId);
+            requestBody.put("checkUserIDs", userIds);
+            String body = HttpRequest.post(IMConfig.URL+"/user/account_check")
+                    .header("operationID", String.valueOf(System.currentTimeMillis()))
+                    .header("token", adminToken)
+                    .body(requestBody.toString())
+                    .execute()
+                    .body();
+            JSONObject jsonObject = new JSONObject(body);
+            JSONArray results = jsonObject.getJSONObject("data").getJSONArray("results");
+            if (results != null && results.length() > 0) {
+                JSONObject resultObj = results.getJSONObject(0);
+                int accountStatus = resultObj.getInt("accountStatus");
+                //未注册自动注册
+                if (accountStatus==0){
+                    String s = userId.replaceFirst("^C", "");
+                    CompanyUser companyUser = companyUserService.selectCompanyUserById(Long.parseLong(s));
+                    if (null==companyUser){
+                        return R.error("用户不存在");
+                    }
+                    ArrayList<Object> users = new ArrayList<>();
+                    HashMap<String, String> map = new HashMap<>();
+                    map.put("userID",userId);
+                    map.put("nickname",companyUser.getNickName());
+                    map.put("faceURL",companyUser.getAvatar());
+                    users.add(map);
+                    requestBody = new JSONObject();
+                    //userIds.add(userId);
+                    requestBody.put("users", users);
+                    String registerBody = HttpRequest.post(IMConfig.URL+"/user/user_register")
+                            .header("operationID", String.valueOf(System.currentTimeMillis()))
+                            .header("token", adminToken).body(requestBody.toString()).execute().body();
+                }
+            } else {
+                return R.error("返回结果为空");
+            }
+           /* HashMap<String, String> tokenMap = new HashMap<>();
+            tokenMap.put("platformID","1");
+            tokenMap.put("userID",userId);*/
+            requestBody = new JSONObject();
+            requestBody.put("platformID",5);
+            requestBody.put("userID",userId);
+            String body1 = HttpRequest.post(IMConfig.URL+"/auth/get_user_token")
+                    .header("operationID", String.valueOf(System.currentTimeMillis()))
+                    .header("token", adminToken)
+                    .body(requestBody.toString()).execute().body();
+            JSONObject userJson = new JSONObject(body1);
+            JSONObject userData = userJson.getJSONObject("data");
+            String userToken = userData.getString("token");
+            return R.ok().put("token", userToken);
+        } else {
+            return R.error("获取管理员token失败");
+        }
+    }
+    @ApiOperation("添加好友")
+    @PostMapping("/importFriend")
+    public R importFriend(@RequestBody HashMap<String,Object> map){
+        String ownerUserID = (String) map.get("ownerUserID");
+        List<String> friendUserIDs = (List<String>)map.get("friendUserIDs");
+        OpenImResponseDTO openImResponseDTO = openIMService.importFriend(ownerUserID, friendUserIDs);
+        return R.ok().put("data",openImResponseDTO);
+    }
+}

+ 1 - 1
fs-admin/src/main/java/com/fs/course/controller/FsCoursePlaySourceConfigController.java

@@ -42,7 +42,7 @@ public class FsCoursePlaySourceConfigController extends BaseController {
     private final TokenService tokenService;
     private final ISysConfigService configService;
 
-    @PreAuthorize("@ss.hasPermi('course:playSourceConfig:list')")
+//    @PreAuthorize("@ss.hasPermi('course:playSourceConfig:list')")
     @GetMapping("/list")
     public TableDataInfo list(@RequestParam(required = false) String name,
                               @RequestParam(required = false) String appid,

+ 35 - 8
fs-admin/src/main/java/com/fs/course/controller/FsCourseQuestionBankController.java

@@ -13,6 +13,7 @@ import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.FsCourseQuestionBank;
 import com.fs.course.dto.FsCourseQuestionBankImportDTO;
+import com.fs.course.dto.ImportResultDTO;
 import com.fs.course.service.IFsCourseQuestionBankService;
 import com.fs.framework.web.service.TokenService;
 import com.fs.system.service.ISysConfigService;
@@ -21,7 +22,9 @@ import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 题库Controller
@@ -80,6 +83,15 @@ public class FsCourseQuestionBankController extends BaseController
         return util.exportExcel(list, "题库数据");
     }
 
+    @PreAuthorize("@ss.hasPermi('course:courseQuestionBank:exportFail')")
+    @Log(title = "题库", businessType = BusinessType.EXPORT)
+    @PostMapping("/exportFail")
+    public AjaxResult export( @RequestBody List<FsCourseQuestionBankImportDTO> list)
+    {
+        ExcelUtil<FsCourseQuestionBankImportDTO> util = new ExcelUtil<>(FsCourseQuestionBankImportDTO.class);
+        return util.exportExcel(list, "题库错误数据");
+    }
+
     /**
      * 获取题库详细信息
      */
@@ -144,19 +156,34 @@ public class FsCourseQuestionBankController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:courseQuestionBank:importData')")
     @PostMapping("/importData")
     public AjaxResult importData(MultipartFile file) throws Exception {
-        ExcelUtil<FsCourseQuestionBankImportDTO> util = new ExcelUtil<>(FsCourseQuestionBankImportDTO.class);
-        List<FsCourseQuestionBankImportDTO> list = util.importExcel(file.getInputStream());
+
+        ExcelUtil<FsCourseQuestionBankImportDTO> util =
+                new ExcelUtil<>(FsCourseQuestionBankImportDTO.class);
+        List<FsCourseQuestionBankImportDTO> list =
+                util.importExcel(file.getInputStream());
 
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         Long userId = loginUser.getUser().getUserId();
+
+        // 读取配置
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        if (ObjectUtil.isNotEmpty(config.getIsBound())&&config.getIsBound()){
-            String message = fsCourseQuestionBankService.importData(list, loginUser.getUser().getNickName(),userId);
-            return AjaxResult.success(message);
-        }
-        String message = fsCourseQuestionBankService.importData(list, loginUser.getUser().getNickName(),null);
-        return AjaxResult.success(message);
+
+        // 绑定状态控制 userId
+        Long finalUserId = (ObjectUtil.isNotEmpty(config.getIsBound()) && config.getIsBound())
+                ? userId
+                : null;
+
+        // 调用 service
+        ImportResultDTO result =
+                fsCourseQuestionBankService.importData(list, loginUser.getUser().getNickName(), finalUserId);
+
+        // 返回 message + failList
+        Map<String, Object> resp = new HashMap<>();
+        resp.put("message", result.buildResultMessage());
+        resp.put("failList", result.getFailureList());
+
+        return AjaxResult.success(resp);
     }
 
     @GetMapping(value = "/getByIds")

+ 35 - 1
fs-admin/src/main/java/com/fs/course/controller/FsCourseTrafficLogController.java

@@ -9,7 +9,9 @@ import com.fs.common.core.domain.R;
 import com.fs.common.exception.CustomException;
 import com.fs.course.param.FsCourseTrafficLogParam;
 import com.fs.course.param.InternetTrafficParam;
+import com.fs.course.param.StatisticsSummaryParam;
 import com.fs.course.vo.FsCourseTrafficLogListVO;
+import com.fs.course.vo.StatisticsSummaryVO;
 import com.fs.qw.param.QwWatchLogStatisticsListParam;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -70,7 +72,11 @@ public class FsCourseTrafficLogController extends BaseController
             param.setYear(Integer.parseInt(parts[0]));
             param.setMonth(Integer.parseInt(parts[1]));
         }
-        List<FsCourseTrafficLogListVO> list = fsCourseTrafficLogService.selectTrafficByCompany(param);
+        List<FsCourseTrafficLogListVO> list = fsCourseTrafficLogService.selectTrafficNew(param);
+        //格式化每个记录的流量为 GB 字符串
+        for (FsCourseTrafficLogListVO vo : list) {
+            vo.formatTraffic();
+        }
         ExcelUtil<FsCourseTrafficLogListVO> util = new ExcelUtil<FsCourseTrafficLogListVO>(FsCourseTrafficLogListVO.class);
         return util.exportExcel(list, "短链课程流量记录数据");
     }
@@ -131,4 +137,32 @@ public class FsCourseTrafficLogController extends BaseController
         return R.ok().put("data", null);  // 返回计算结果
     }
 
+    /**
+     * 流量统计汇总
+     * @param param
+     * @return
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseTrafficLog:statistics')")
+    @GetMapping("/statisticsSummaryList")
+    public TableDataInfo statisticsSummaryList(StatisticsSummaryParam param)
+    {
+        List<StatisticsSummaryVO> list = fsCourseTrafficLogService.getStatisticsSummaryList(param);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出汇总统计报表
+     * @param param
+     * @return
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseTrafficLog:statisticsExport')")
+    @GetMapping("/exportStatisticsSummary")
+    public AjaxResult exportStatisticsSummary(StatisticsSummaryParam param)
+    {
+        List<StatisticsSummaryVO> list = fsCourseTrafficLogService.getStatisticsSummaryListNotPage(param);
+        ExcelUtil<StatisticsSummaryVO> util = new ExcelUtil<StatisticsSummaryVO>(StatisticsSummaryVO.class);
+        return util.exportExcel(list, "看课流量统计汇总");
+
+    }
+
 }

+ 43 - 31
fs-admin/src/main/java/com/fs/course/controller/FsUserCourseCompanyStatisticsController.java

@@ -89,44 +89,56 @@ public class FsUserCourseCompanyStatisticsController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:statistics:export')")
     @Log(title = "会员每日看课统计", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
-    public AjaxResult export(FsUserCourseCompanyStatistics fsUserCourseCompanyStatistics)
-    {
+    public AjaxResult export(FsUserCourseCompanyStatistics fsUserCourseCompanyStatistics) {
+
         List<FsUserCourseCompanyStatistics> list =
                 fsUserCourseCompanyStatisticsService.selectFsUserCourseCompanyStatisticsTotal(fsUserCourseCompanyStatistics);
 
-        Optional.ofNullable(list).orElse(Collections.emptyList())
-                .forEach(item -> {
-                    // 计算完播率 (完播次数 / 观看次数 * 100)
-                    item.setCompleteRate(
-                            Optional.ofNullable(item.getWatchCount())
-                                    .filter(watchCount -> watchCount > 0)
-                                    .map(watchCount -> BigDecimal.valueOf(
-                                                    Optional.ofNullable(item.getCompleteWatchCount()).orElse(0L))
-                                            .multiply(BigDecimal.valueOf(100))
-                                            .divide(BigDecimal.valueOf(watchCount), 2, RoundingMode.HALF_UP)
-                                            .longValue()
-                                    )
-                                    .orElse(0L)
-                    );
-
-                    // 计算正确率 (正确人次 / 答题人次 * 100)
-                    item.setCorrectRate(
-                            Optional.ofNullable(item.getAnswerCount())
-                                    .filter(answerCount -> answerCount > 0)
-                                    .map(answerCount -> BigDecimal.valueOf(
-                                                    Optional.ofNullable(item.getCorrectCount()).orElse(0L))
-                                            .multiply(BigDecimal.valueOf(100))
-                                            .divide(BigDecimal.valueOf(answerCount), 2, RoundingMode.HALF_UP)
-                                            .longValue()
-                                    )
-                                    .orElse(0L)
-                    );
-                });
+        if (list == null) {
+            list = Collections.emptyList();
+        }
+
+        for (FsUserCourseCompanyStatistics item : list) {
 
-        ExcelUtil<FsUserCourseCompanyStatistics> util = new ExcelUtil<FsUserCourseCompanyStatistics>(FsUserCourseCompanyStatistics.class);
+            Long watchCount = item.getWatchCount();
+            Long completeWatchCount = Optional.ofNullable(item.getCompleteWatchCount()).orElse(0L);
+
+            // 完播率 = 完播次数 / 观看次数 * 100  (放大100倍存入long,再格式化两位小数)
+            if (watchCount != null && watchCount > 0) {
+                Long rateValue = BigDecimal.valueOf(completeWatchCount)
+                        .multiply(BigDecimal.valueOf(10000)) // 100*100
+                        .divide(BigDecimal.valueOf(watchCount), 0, RoundingMode.HALF_UP)
+                        .longValue();
+                item.setCompleteRate(rateValue);
+                item.setCompleteRateStr(String.format("%.2f%%", rateValue / 100.0));  // Excel 格式化
+            } else {
+                item.setCompleteRate(0L);
+                item.setCompleteRateStr("0.00%");
+            }
+
+            Long answerCount = item.getAnswerCount();
+            Long correctCount = Optional.ofNullable(item.getCorrectCount()).orElse(0L);
+
+            // 正确率 = 正确人次 / 答题人次 * 100
+            if (answerCount != null && answerCount > 0) {
+                Long rateValue = BigDecimal.valueOf(correctCount)
+                        .multiply(BigDecimal.valueOf(10000))
+                        .divide(BigDecimal.valueOf(answerCount), 0, RoundingMode.HALF_UP)
+                        .longValue();
+                item.setCorrectRate(rateValue);
+                item.setCorrectRateStr(String.format("%.2f%%", rateValue / 100.0));
+            } else {
+                item.setCorrectRate(0L);
+                item.setCorrectRateStr("0.00%");
+            }
+        }
+
+        ExcelUtil<FsUserCourseCompanyStatistics> util = new ExcelUtil<>(FsUserCourseCompanyStatistics.class);
         return util.exportExcel(list, "会员每日看课统计数据");
     }
 
+
+
     /**
      * 获取会员每日看课统计详细信息
      */

+ 79 - 74
fs-admin/src/main/java/com/fs/course/controller/FsUserCourseController.java

@@ -1,38 +1,34 @@
 package com.fs.course.controller;
 
-import java.util.List;
-
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.json.JSONUtil;
+import com.fs.common.annotation.Log;
+import com.fs.common.annotation.RepeatSubmit;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.course.config.CourseConfig;
+import com.fs.course.domain.FsUserCourse;
+import com.fs.course.params.FsUserCourseConfigParam;
+import com.fs.course.service.IFsUserCourseService;
 import com.fs.course.service.IFsUserCourseVideoService;
 import com.fs.course.vo.FsUserCourseListPVO;
 import com.fs.framework.web.service.TokenService;
 import com.fs.his.utils.RedisCacheUtil;
 import com.fs.his.vo.OptionsVO;
 import com.fs.qw.param.FsUserCourseRedPageParam;
+import com.fs.sop.service.IQwSopTempService;
 import com.fs.system.service.ISysConfigService;
-import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.fs.common.annotation.Log;
-import com.fs.common.core.controller.BaseController;
-import com.fs.common.core.domain.AjaxResult;
-import com.fs.common.enums.BusinessType;
-import com.fs.course.domain.FsUserCourse;
-import com.fs.course.service.IFsUserCourseService;
-import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.common.core.page.TableDataInfo;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
 
 /**
  * 课程Controller
@@ -42,8 +38,7 @@ import com.fs.common.core.page.TableDataInfo;
  */
 @RestController
 @RequestMapping("/course/userCourse")
-public class FsUserCourseController extends BaseController
-{
+public class FsUserCourseController extends BaseController {
     @Autowired
     private IFsUserCourseService fsUserCourseService;
 
@@ -59,19 +54,21 @@ public class FsUserCourseController extends BaseController
     @Autowired
     private ISysConfigService configService;
 
+    @Autowired
+    private IQwSopTempService sopTempService;
+
     /**
      * 查询课程列表
      */
     @PreAuthorize("@ss.hasPermi('course:userCourse:list')")
     @GetMapping("/list")
-    public TableDataInfo list(FsUserCourse fsUserCourse)
-    {
+    public TableDataInfo list(FsUserCourse fsUserCourse) {
         startPage();
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         Long userId = loginUser.getUser().getUserId();
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        if (ObjectUtil.isNotEmpty(config.getIsBound())&&config.getIsBound()){
+        if (ObjectUtil.isNotEmpty(config.getIsBound()) && config.getIsBound()) {
             fsUserCourse.setUserId(userId);
         }
         List<FsUserCourseListPVO> list = fsUserCourseService.selectFsUserCourseListPVO(fsUserCourse);
@@ -83,14 +80,13 @@ public class FsUserCourseController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('course:userCourse:publicList')")
     @GetMapping("/publicList")
-    public TableDataInfo publicList(FsUserCourse fsUserCourse)
-    {
+    public TableDataInfo publicList(FsUserCourse fsUserCourse) {
         startPage();
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         Long userId = loginUser.getUser().getUserId();
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        if (ObjectUtil.isNotEmpty(config.getIsBound())&&config.getIsBound()){
+        if (ObjectUtil.isNotEmpty(config.getIsBound()) && config.getIsBound()) {
             fsUserCourse.setUserId(userId);
         }
         List<FsUserCourseListPVO> list = fsUserCourseService.selectFsUserCourseListPVO(fsUserCourse);
@@ -103,13 +99,12 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:export')")
     @Log(title = "课程", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
-    public AjaxResult export(FsUserCourse fsUserCourse)
-    {
+    public AjaxResult export(FsUserCourse fsUserCourse) {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         Long userId = loginUser.getUser().getUserId();
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        if (ObjectUtil.isNotEmpty(config.getIsBound())&&config.getIsBound()){
+        if (ObjectUtil.isNotEmpty(config.getIsBound()) && config.getIsBound()) {
             fsUserCourse.setUserId(userId);
         }
         List<FsUserCourse> list = fsUserCourseService.selectFsUserCourseList(fsUserCourse);
@@ -123,13 +118,12 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:publicExport')")
     @Log(title = "课程", businessType = BusinessType.EXPORT)
     @GetMapping("/publicExport")
-    public AjaxResult publicExport(FsUserCourse fsUserCourse)
-    {
+    public AjaxResult publicExport(FsUserCourse fsUserCourse) {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         Long userId = loginUser.getUser().getUserId();
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        if (ObjectUtil.isNotEmpty(config.getIsBound())&&config.getIsBound()){
+        if (ObjectUtil.isNotEmpty(config.getIsBound()) && config.getIsBound()) {
             fsUserCourse.setUserId(userId);
         }
         List<FsUserCourse> list = fsUserCourseService.selectFsUserCourseList(fsUserCourse);
@@ -142,8 +136,7 @@ public class FsUserCourseController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('course:userCourse:query')")
     @GetMapping(value = "/{courseId}")
-    public AjaxResult getInfo(@PathVariable("courseId") Long courseId)
-    {
+    public AjaxResult getInfo(@PathVariable("courseId") Long courseId) {
         return AjaxResult.success(fsUserCourseService.selectFsUserCourseByCourseId(courseId));
     }
 
@@ -152,8 +145,7 @@ public class FsUserCourseController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('course:userCourse:publicQuery')")
     @GetMapping(value = "/public/{courseId}")
-    public AjaxResult publicGetInfo(@PathVariable("courseId") Long courseId)
-    {
+    public AjaxResult publicGetInfo(@PathVariable("courseId") Long courseId) {
         return AjaxResult.success(fsUserCourseService.selectFsUserCourseByCourseId(courseId));
     }
 
@@ -163,13 +155,12 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:add')")
     @Log(title = "课程", businessType = BusinessType.INSERT)
     @PostMapping
-    public AjaxResult add(@RequestBody FsUserCourse fsUserCourse)
-    {
+    public AjaxResult add(@RequestBody FsUserCourse fsUserCourse) {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         Long userId = loginUser.getUser().getUserId();
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        if (ObjectUtil.isNotEmpty(config.getIsBound())&&config.getIsBound()){
+        if (ObjectUtil.isNotEmpty(config.getIsBound()) && config.getIsBound()) {
             fsUserCourse.setUserId(userId);
         }
         fsUserCourseService.insertFsUserCourse(fsUserCourse);
@@ -184,13 +175,12 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:publicAdd')")
     @Log(title = "课程", businessType = BusinessType.INSERT)
     @PostMapping("/public")
-    public AjaxResult publicAdd(@RequestBody FsUserCourse fsUserCourse)
-    {
+    public AjaxResult publicAdd(@RequestBody FsUserCourse fsUserCourse) {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         Long userId = loginUser.getUser().getUserId();
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        if (ObjectUtil.isNotEmpty(config.getIsBound())&&config.getIsBound()){
+        if (ObjectUtil.isNotEmpty(config.getIsBound()) && config.getIsBound()) {
             fsUserCourse.setUserId(userId);
         }
         fsUserCourseService.insertFsUserCourse(fsUserCourse);
@@ -205,8 +195,7 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:edit')")
     @Log(title = "课程", businessType = BusinessType.UPDATE)
     @PutMapping
-    public AjaxResult edit(@RequestBody FsUserCourse fsUserCourse)
-    {
+    public AjaxResult edit(@RequestBody FsUserCourse fsUserCourse) {
         fsUserCourseService.updateFsUserCourse(fsUserCourse);
         redisCacheUtil.delRedisKey("getCourseList");
         return toAjax(1);
@@ -218,8 +207,7 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:editRedPage')")
     @Log(title = "修改课程红包", businessType = BusinessType.UPDATE)
     @PostMapping("/editRedPage")
-    public AjaxResult editRedPage(@RequestBody FsUserCourseRedPageParam redPageParam)
-    {
+    public AjaxResult editRedPage(@RequestBody FsUserCourseRedPageParam redPageParam) {
         courseVideoService.updateFsUserCourseRedPage(redPageParam);
         return toAjax(1);
     }
@@ -230,8 +218,7 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:publicEdit')")
     @Log(title = "课程", businessType = BusinessType.UPDATE)
     @PutMapping("/public")
-    public AjaxResult publicEdit(@RequestBody FsUserCourse fsUserCourse)
-    {
+    public AjaxResult publicEdit(@RequestBody FsUserCourse fsUserCourse) {
         fsUserCourseService.updateFsUserCourse(fsUserCourse);
         redisCacheUtil.delRedisKey("getCourseList");
         return toAjax(1);
@@ -243,8 +230,7 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:copy')")
     @Log(title = "课程", businessType = BusinessType.DELETE)
     @GetMapping("/copy/{courseId}")
-    public AjaxResult copy(@PathVariable Long courseId)
-    {
+    public AjaxResult copy(@PathVariable Long courseId) {
         int i = fsUserCourseService.copyFsUserCourse(courseId);
         return toAjax(i);
     }
@@ -254,8 +240,8 @@ public class FsUserCourseController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('course:userCourse:remove')")
     @Log(title = "课程", businessType = BusinessType.DELETE)
-	@DeleteMapping("/{courseIds}")
-    public AjaxResult remove(@PathVariable Long[] courseIds){
+    @DeleteMapping("/{courseIds}")
+    public AjaxResult remove(@PathVariable Long[] courseIds) {
         fsUserCourseService.deleteFsUserCourseByCourseIds(courseIds);
         redisCacheUtil.delRedisKey("getCourseList");
         return toAjax(1);
@@ -267,8 +253,7 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:publicRemove')")
     @Log(title = "课程", businessType = BusinessType.DELETE)
     @DeleteMapping("/public/{courseIds}")
-    public AjaxResult publicRemove(@PathVariable Long[] courseIds)
-    {
+    public AjaxResult publicRemove(@PathVariable Long[] courseIds) {
         fsUserCourseService.deleteFsUserCourseByCourseIds(courseIds);
         redisCacheUtil.delRedisKey("getCourseList");
         return toAjax(1);
@@ -276,8 +261,7 @@ public class FsUserCourseController extends BaseController
 
 
     @GetMapping("/getAllList")
-    public R getAllList()
-    {
+    public R getAllList() {
         List<OptionsVO> list = fsUserCourseService.selectFsUserCourseAllList();
         return R.ok().put("data", list);
     }
@@ -285,18 +269,16 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:updateIsShow')")
     @Log(title = "课程上架", businessType = BusinessType.UPDATE)
     @PostMapping("/updateIsShow")
-    public AjaxResult updateIsShow(@RequestBody FsUserCourse fsUserCourse)
-    {
+    public AjaxResult updateIsShow(@RequestBody FsUserCourse fsUserCourse) {
         fsUserCourseService.updateFsUserCourse(fsUserCourse);
         redisCacheUtil.delRedisKey("getCourseList");
-       return toAjax(1);
+        return toAjax(1);
     }
 
     @PreAuthorize("@ss.hasPermi('course:userCourse:publicUpdateIsShow')")
     @Log(title = "课程上架", businessType = BusinessType.UPDATE)
     @PostMapping("/publicUpdateIsShow")
-    public AjaxResult publicUpdateIsShow(@RequestBody FsUserCourse fsUserCourse)
-    {
+    public AjaxResult publicUpdateIsShow(@RequestBody FsUserCourse fsUserCourse) {
         fsUserCourseService.updateFsUserCourse(fsUserCourse);
         redisCacheUtil.delRedisKey("getCourseList");
         return toAjax(1);
@@ -305,9 +287,8 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:putOn')")
     @Log(title = "课程批量上架", businessType = BusinessType.UPDATE)
     @PostMapping("/putOn/{courseIds}")
-    public AjaxResult putOn(@PathVariable Long[] courseIds)
-    {
-        fsUserCourseService.updateFsUserCourseIsShow(courseIds,1);
+    public AjaxResult putOn(@PathVariable Long[] courseIds) {
+        fsUserCourseService.updateFsUserCourseIsShow(courseIds, 1);
         redisCacheUtil.delRedisKey("getCourseList");
         return toAjax(1);
     }
@@ -315,9 +296,8 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:publicPutOn')")
     @Log(title = "课程批量上架", businessType = BusinessType.UPDATE)
     @PostMapping("/publicPutOn/{courseIds}")
-    public AjaxResult publicPutOn(@PathVariable Long[] courseIds)
-    {
-        fsUserCourseService.updateFsUserCourseIsShow(courseIds,1);
+    public AjaxResult publicPutOn(@PathVariable Long[] courseIds) {
+        fsUserCourseService.updateFsUserCourseIsShow(courseIds, 1);
         redisCacheUtil.delRedisKey("getCourseList");
         return toAjax(1);
     }
@@ -325,9 +305,8 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:putOn')")
     @Log(title = "课程批量下架", businessType = BusinessType.UPDATE)
     @PostMapping("/pullOff/{courseIds}")
-    public AjaxResult pullOff(@PathVariable Long[] courseIds)
-    {
-        fsUserCourseService.updateFsUserCourseIsShow(courseIds,0);
+    public AjaxResult pullOff(@PathVariable Long[] courseIds) {
+        fsUserCourseService.updateFsUserCourseIsShow(courseIds, 0);
         redisCacheUtil.delRedisKey("getCourseList");
         return toAjax(1);
     }
@@ -335,10 +314,36 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:publicPutOff')")
     @Log(title = "课程批量下架", businessType = BusinessType.UPDATE)
     @PostMapping("/publicPutOff/{courseIds}")
-    public AjaxResult publicPutOff(@PathVariable Long[] courseIds)
-    {
-        fsUserCourseService.updateFsUserCourseIsShow(courseIds,0);
+    public AjaxResult publicPutOff(@PathVariable Long[] courseIds) {
+        fsUserCourseService.updateFsUserCourseIsShow(courseIds, 0);
         redisCacheUtil.delRedisKey("getCourseList");
         return toAjax(1);
     }
+
+    /**
+     * 修改配置
+     **/
+    @PreAuthorize("@ss.hasPermi('course:userCourse:editConfig')")
+    @Log(title = "课程配置", businessType = BusinessType.UPDATE)
+    @PostMapping("/editConfig")
+    public R editConfig(@RequestBody FsUserCourseConfigParam params) {
+        fsUserCourseService.editConfig(params.getId(), params.getConfigJson());
+        redisCacheUtil.delRedisKey("getCourseList");
+        redisCacheUtil.delRedisKey("h5user:course:video:list:all");
+        redisCacheUtil.delRedisKey("h5user:course:list:all");
+        redisCacheUtil.delRedisKey("cache:video");
+        return R.ok();
+    }
+
+    /**
+     * 同步课程模板
+     */
+    @PreAuthorize("@ss.hasPermi('course:userCourseVideo:sync')")
+    @Log(title = "同步课程模板", businessType = BusinessType.UPDATE)
+    @RepeatSubmit
+    @PostMapping("/syncTemplate/{courseId}")
+    public AjaxResult syncTemplate(@PathVariable Long courseId) {
+        sopTempService.syncTemplate(courseId);
+        return toAjax(1);
+    }
 }

+ 4 - 0
fs-admin/src/main/java/com/fs/course/controller/FsUserCoursePeriodController.java

@@ -194,14 +194,17 @@ public class FsUserCoursePeriodController extends BaseController {
 
     @PreAuthorize("@ss.hasPermi('course:period:updateCourseTime')")
     @PostMapping("/updateCourseTime")
+    @Log(title = "会员营期修改课程时间", businessType = BusinessType.UPDATE)
     public R updateCourseTime(@RequestBody UpdateCourseTimeVo vo){
         return fsUserCoursePeriodDaysService.updateCourseTime(vo);
     }
     @PostMapping("/updateCourseDate")
+    @Log(title = "会员营期修改CourseDate", businessType = BusinessType.UPDATE)
     public R updateCourseDate(@RequestBody UpdateCourseTimeVo vo){
         return fsUserCoursePeriodDaysService.updateCourseDate(vo);
     }
     @PostMapping("/updateListCourseData")
+    @Log(title = "会员营期修改ListCourseData", businessType = BusinessType.UPDATE)
     public R updateListCourseData(@RequestBody List<FsUserCoursePeriodDays> entity){
         return fsUserCoursePeriodDaysService.updateListCourseData(entity);
     }
@@ -308,6 +311,7 @@ public class FsUserCoursePeriodController extends BaseController {
 
     @PreAuthorize("@ss.hasPermi('course:period:setCompanyRedPacket')")
     @ApiOperation("按公司批量保存设置红包金额")
+    @Log(title = "按公司批量保存设置红包金额", businessType = BusinessType.UPDATE)
     @PostMapping("/batchRedPacket/byCompany")
     public R batchRedPacketByCompany(@Validated @RequestBody BatchCompanyRedPackageParam param) {
         try {

+ 13 - 0
fs-admin/src/main/java/com/fs/course/controller/qw/QwFsCourseWatchLogController.java

@@ -23,6 +23,7 @@ import com.fs.qw.param.QwWatchLogStatisticsListParam;
 import com.fs.qw.service.IQwWatchLogService;
 import com.fs.qw.vo.QwWatchLogAllStatisticsListVO;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
@@ -39,6 +40,9 @@ import java.util.List;
 @RequestMapping("/qw/course/courseWatchLog")
 public class QwFsCourseWatchLogController extends BaseController
 {
+    @Value("${cloud_host.company_name}")
+    private String signProjectName;
+
     @Autowired
     private IFsCourseWatchLogService fsCourseWatchLogService;
 
@@ -78,9 +82,18 @@ public class QwFsCourseWatchLogController extends BaseController
         }
         param.setSendType(2); //企微
         List<FsCourseWatchLogStatisticsListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogStatisticsListVO(param);
+        if("济南联志健康".equals(signProjectName)){
+            FsCourseWatchLogStatisticsListVO totalData = fsCourseWatchLogService.getTotalDataAddItem(param);
+            list.add(totalData);
+        }
         return getDataTable(list);
     }
 
+    @GetMapping("/getSignProjectName")
+    public R getSignProjectName(){
+        return R.ok().put("signProjectName", signProjectName);
+    }
+
     @GetMapping("/statisticsListByCompany")
     public R statisticsListByCompany(FsCourseWatchLogStatisticsListParam param)
     {

+ 21 - 0
fs-admin/src/main/java/com/fs/course/params/FsUserCourseConfigParam.java

@@ -0,0 +1,21 @@
+package com.fs.course.params;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@ApiModel("过程页配置参数实体")
+@Data
+public class FsUserCourseConfigParam {
+
+    @NotNull(message = "课程ID不能为空")
+    @ApiModelProperty("课程ID")
+    private Long id;
+
+    @NotBlank(message = "配置信息不能为空")
+    @ApiModelProperty("配置信息")
+    private String configJson;
+}

+ 59 - 0
fs-admin/src/main/java/com/fs/his/controller/FsCompanyController.java

@@ -217,6 +217,65 @@ public class FsCompanyController extends BaseController {
 
     }
 
+
+    /**
+     * @Description: 红包充值功能 因公司余额的变动关联的地方太多,现在把充值红包的金额单独提出来 不合计到公司余额中
+     * @Param:
+     * @Return:
+     * @Author xgb
+     * @Date 2025/11/3 11:08
+     */
+    @PreAuthorize("@ss.hasPermi('his:company:redRecharge')")
+    @Log(title = "红包充值", businessType = BusinessType.INSERT)
+    @PostMapping(value = "/redRecharge")
+    @Transactional
+    @RepeatSubmit
+    public R redRecharge(@RequestBody CompanyRechargeParam param)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        CompanyRecharge redRecharge=new CompanyRecharge();
+        String orderSn =  OrderCodeUtils.getOrderSn();
+        if(StringUtils.isEmpty(orderSn)){
+            return R.error("订单生成失败,请重试");
+        }
+        redRecharge.setRechargeNo(orderSn);
+        redRecharge.setCompanyId(param.getCompanyId());
+        redRecharge.setMoney(param.getMoney());
+        redRecharge.setCreateUserId(loginUser.getUser().getUserId());
+        redRecharge.setIsAudit(0);
+        redRecharge.setStatus(0);
+        redRecharge.setRemark(param.getRemark());
+        redRecharge.setPayType(3);
+        redRecharge.setBusinessType(1);// 红包充值
+        rechargeService.insertCompanyRecharge(redRecharge);
+        return R.ok("提交成功,等待审核");
+
+    }
+
+    @PreAuthorize("@ss.hasPermi('his:company:redDeduct')")
+    @Log(title = "企业扣款", businessType = BusinessType.INSERT)
+    @PostMapping(value = "/redDeduct")
+    @Transactional
+    @RepeatSubmit
+    public R redDeduct(@RequestBody CompanyDeductParam param)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        CompanyDeduct deduct=new CompanyDeduct();
+        String orderSn =  OrderCodeUtils.getOrderSn();
+        if(StringUtils.isEmpty(orderSn)){
+            return R.error("订单生成失败,请重试");
+        }
+        deduct.setDeductNo(orderSn);
+        deduct.setCompanyId(param.getCompanyId());
+        deduct.setMoney(param.getMoney());
+        deduct.setCreateUserId(loginUser.getUser().getUserId());
+        deduct.setIsAudit(0);
+        deduct.setRemark(param.getRemark());
+        deduct.setBusinessType(1); // 红包扣款
+        deductService.insertCompanyDeduct(deduct);
+        return R.ok("提交成功,等待审核");
+    }
+
     @PreAuthorize("@ss.hasPermi('his:company:deduct')")
     @Log(title = "企业扣款", businessType = BusinessType.INSERT)
     @PostMapping(value = "/deduct")

+ 18 - 13
fs-admin/src/main/java/com/fs/his/controller/FsCompanyDeductController.java

@@ -139,19 +139,24 @@ public class FsCompanyDeductController extends BaseController
         deduct.setRemark(param.getRemark());
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         if(deduct.getIsAudit()==1){
-            Company company=companyService.selectCompanyByIdForUpdate(deduct.getCompanyId());
-            company.setMoney(company.getMoney().subtract(deduct.getMoney()));
-            deduct.setBalance(company.getMoney());
-            companyService.updateCompany(company);
-            //生成流水
-            CompanyMoneyLogs log=new CompanyMoneyLogs();
-            log.setCompanyId(deduct.getCompanyId());
-            log.setMoney(deduct.getMoney().multiply(new BigDecimal(-1)));
-            log.setRemark(deduct.getRemark());
-            log.setLogsType(2);
-            log.setBalance(company.getMoney());
-            log.setCreateTime(new Date());
-            moneyLogsService.insertCompanyMoneyLogs(log);
+            if(1==param.getBusinessType()){// 红包充值
+                // 更新红包充值余额redis字段
+                companyService.redPacketTopUpCompany(deduct.getCompanyId(),deduct.getMoney(),"2");
+            }else {
+                Company company=companyService.selectCompanyByIdForUpdate(deduct.getCompanyId());
+                company.setMoney(company.getMoney().subtract(deduct.getMoney()));
+                deduct.setBalance(company.getMoney());
+                companyService.updateCompany(company);
+                //生成流水
+                CompanyMoneyLogs log=new CompanyMoneyLogs();
+                log.setCompanyId(deduct.getCompanyId());
+                log.setMoney(deduct.getMoney().multiply(new BigDecimal(-1)));
+                log.setRemark(deduct.getRemark());
+                log.setLogsType(2);
+                log.setBalance(company.getMoney());
+                log.setCreateTime(new Date());
+                moneyLogsService.insertCompanyMoneyLogs(log);
+            }
         }
         deduct.setAuditTime(new Date());
         deduct.setAuditUserId(loginUser.getUser().getUserId());

+ 24 - 0
fs-admin/src/main/java/com/fs/his/controller/FsCompanyDivItemController.java

@@ -1,6 +1,8 @@
 package com.fs.his.controller;
 
 import java.util.List;
+
+import com.fs.common.core.domain.R;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -68,6 +70,28 @@ public class FsCompanyDivItemController extends BaseController
         return AjaxResult.success(companyDivItemService.selectCompanyDivItemById(id));
     }
 
+    /**
+     * 分账确认
+     */
+    @PreAuthorize("@ss.hasPermi('his:divItem:confirm')")
+    @Log(title = "延迟分账确认", businessType = BusinessType.UPDATE)
+    @PostMapping("/confirm")
+    public R confirm(@RequestBody List<String> payCodes)
+    {
+        return companyDivItemService.confirmByPayCodes(payCodes);
+    }
+
+    /**
+     * 分账确认Scrm
+     */
+    @PreAuthorize("@ss.hasPermi('his:divItem:confirm')")
+    @Log(title = "延迟分账确认", businessType = BusinessType.UPDATE)
+    @PostMapping("/confirmScrm")
+    public R confirmScrm(@RequestBody List<String> payCodes)
+    {
+        return companyDivItemService.confirmByPayCodesScrm(payCodes);
+    }
+
 //    /**
 //     * 新增分账明细
 //     */

+ 20 - 13
fs-admin/src/main/java/com/fs/his/controller/FsCompanyRechargeController.java

@@ -137,21 +137,28 @@ public class FsCompanyRechargeController extends BaseController
         companyRecharge.setRemark(param.getRemark());
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         if(companyRecharge.getIsAudit()==1){
-            Company company=companyService.selectCompanyByIdForUpdate(companyRecharge.getCompanyId());
-            company.setMoney(company.getMoney().add(companyRecharge.getMoney()));
-            companyRecharge.setBalance(company.getMoney());
-            companyService.updateCompany(company);
-            //生成流水
-            CompanyMoneyLogs log=new CompanyMoneyLogs();
-            log.setCompanyId(companyRecharge.getCompanyId());
-            log.setMoney(companyRecharge.getMoney());
-            log.setRemark(companyRecharge.getRemark());
-            log.setLogsType(1);
-            log.setBalance(company.getMoney());
-            log.setCreateTime(new Date());
-            moneyLogsService.insertCompanyMoneyLogs(log);
+            if(1==companyRecharge.getBusinessType()){// 红包充值
+                // 更新红包充值余额redis字段
+                companyService.redPacketTopUpCompany(companyRecharge.getCompanyId(),companyRecharge.getMoney(),"1");
+            }else {
+                Company company=companyService.selectCompanyByIdForUpdate(companyRecharge.getCompanyId());
+                company.setMoney(company.getMoney().add(companyRecharge.getMoney()));
+                companyRecharge.setBalance(company.getMoney());
+                companyService.updateCompany(company);
+                //生成流水
+                CompanyMoneyLogs log=new CompanyMoneyLogs();
+                log.setCompanyId(companyRecharge.getCompanyId());
+                log.setMoney(companyRecharge.getMoney());
+                log.setRemark(companyRecharge.getRemark());
+                log.setLogsType(1);
+                log.setBalance(company.getMoney());
+                log.setCreateTime(new Date());
+                moneyLogsService.insertCompanyMoneyLogs(log);
+
+            }
             companyRecharge.setPayTime(new Date());
             companyRecharge.setStatus(1);
+
         }
 
         companyRecharge.setAuditTime(new Date());

+ 23 - 0
fs-admin/src/main/java/com/fs/his/controller/FsDoctorController.java

@@ -26,6 +26,9 @@ import com.fs.his.service.IFsDoctorService;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.common.core.page.TableDataInfo;
 
+import static com.fs.his.utils.PhoneUtil.decryptAutoPhoneMk;
+import static com.fs.his.utils.PhoneUtil.encryptPhone;
+
 /**
  * 医生管理Controller
  *
@@ -291,4 +294,24 @@ public class FsDoctorController extends BaseController
         return R.ok().put("data", new PageInfo<>(list));
     }
 
+
+    @GetMapping("/getDocVoList")
+    public TableDataInfo getDocVoList(FsDoctorParam param) {
+        startPage();
+        List<FsDoctorVO> list = fsDoctorService.selectDocVOByNameAndPhone(param);
+        if (list == null || list.isEmpty()) {
+            param.setMobile(encryptPhone(param.getMobile()));
+            list = fsDoctorService.selectDocVOByNameAndPhone(param);
+        }
+
+        if (list != null) {
+            list.forEach( item -> {
+                if (item.getMobile() != null)
+                    item.setMobile(decryptAutoPhoneMk(item.getMobile()));
+            });
+        }
+        return getDataTable(list);
+    }
+
+
 }

+ 29 - 0
fs-admin/src/main/java/com/fs/his/controller/FsInquiryOrderController.java

@@ -30,6 +30,7 @@ import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
@@ -57,6 +58,20 @@ public class FsInquiryOrderController extends BaseController
    public TableDataInfo list(FsInquiryOrderParam fsInquiryOrder)
     {
         startPage();
+        //根据订单权限查询相关公司订单
+        try {
+            Long companyId = getLoginUser().getUser().getCompanyId();
+            if (companyId!=null){
+                if (fsInquiryOrder.getCompanyId()!=null){
+                    if (!companyId.equals(fsInquiryOrder.getCompanyId())) {
+                        return getDataTable(new ArrayList<>());
+                    }
+                }
+                fsInquiryOrder.setCompanyId(companyId);
+            }
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
+        }
         if(!StringUtils.isEmpty(fsInquiryOrder.getCreateTimeRange())){
             fsInquiryOrder.setCreateTimeList(fsInquiryOrder.getCreateTimeRange().split("--"));
         }
@@ -84,6 +99,20 @@ public class FsInquiryOrderController extends BaseController
         }
         Integer inquiryType = fsInquiryOrder.getInquiryType();
         fsInquiryOrder.setInquiryType(null);
+        //根据订单权限查询相关公司订单
+        try {
+            Long companyId = getLoginUser().getUser().getCompanyId();
+            if (companyId!=null){
+                if (fsInquiryOrder.getCompanyId()!=null){
+                    if (!companyId.equals(fsInquiryOrder.getCompanyId())) {
+                        return AjaxResult.error("请筛选数据自己公司数据");
+                    }
+                }
+                fsInquiryOrder.setCompanyId(companyId);
+            }
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
+        }
         logger.info("导出问诊订单:"+ SecurityUtils.getUserId());
         if (fsInquiryOrderService.isEntityNull(fsInquiryOrder)){
             return AjaxResult.error("请筛选数据导出");

+ 27 - 4
fs-admin/src/main/java/com/fs/his/controller/FsInquiryOrderReportController.java

@@ -22,6 +22,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
@@ -51,8 +52,19 @@ public class FsInquiryOrderReportController extends BaseController
     public TableDataInfo list(FsInquiryOrderReportParam fsInquiryOrderReport)
     {
         startPage();
-        if (getUserId().equals(54L)||getUserId().equals(211L)){
-            fsInquiryOrderReport.setCompanyId(188L);
+        //根据订单权限查询相关公司订单
+        try {
+            Long companyId = getLoginUser().getUser().getCompanyId();
+            if (companyId!=null){
+                if (fsInquiryOrderReport.getCompanyId()!=null){
+                    if (!companyId.equals(fsInquiryOrderReport.getCompanyId())) {
+                        return getDataTable(new ArrayList<>());
+                    }
+                }
+                fsInquiryOrderReport.setCompanyId(companyId);
+            }
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
         }
         List<FsInquiryOrderReportListVO> list = fsInquiryOrderReportService.selectFsInquiryOrderReportListVO(fsInquiryOrderReport);
         for (FsInquiryOrderReportListVO vo : list){
@@ -78,8 +90,19 @@ public class FsInquiryOrderReportController extends BaseController
         if (fsInquiryOrderReportService.isEntityNull(fsInquiryOrderReport)){
             return AjaxResult.error("请筛选数据导出");
         }
-        if (getUserId().equals(54L)||getUserId().equals(211L)){
-            fsInquiryOrderReport.setCompanyId(188L);
+        //根据订单权限查询相关公司订单
+        try {
+            Long companyId = getLoginUser().getUser().getCompanyId();
+            if (companyId!=null){
+                if (fsInquiryOrderReport.getCompanyId()!=null){
+                    if (!companyId.equals(fsInquiryOrderReport.getCompanyId())) {
+                        return AjaxResult.error("请筛选数据自己公司数据");
+                    }
+                }
+                fsInquiryOrderReport.setCompanyId(companyId);
+            }
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
         }
         Integer exportType1 = exportTaskService.isExportType1(SecurityUtils.getUserId());
         if (exportType1>0){

+ 246 - 14
fs-admin/src/main/java/com/fs/his/controller/FsIntegralOrderController.java

@@ -1,29 +1,38 @@
 package com.fs.his.controller;
 
+import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.util.StrUtil;
-import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.CloudHostUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.his.domain.FsIntegralOrder;
-import com.fs.his.domain.FsStoreOrder;
+import com.fs.common.utils.uuid.IdUtils;
+import com.fs.his.domain.*;
 import com.fs.his.dto.ExpressInfoDTO;
 import com.fs.his.enums.ShipperCodeEnum;
-import com.fs.his.param.FsIntegralOrderParam;
-import com.fs.his.service.IFsExpressService;
-import com.fs.his.service.IFsIntegralOrderService;
-import com.fs.his.utils.PhoneUtil;
+import com.fs.his.mapper.FsIntegralOrderMapper;
+import com.fs.his.param.BatchCreateErpOrderParam;
+import com.fs.his.param.BatchSetErpOrderParam;
 import com.fs.his.vo.*;
+import com.fs.his.param.FsIntegralOrderParam;
+import com.fs.his.service.*;
+import com.fs.utils.OrderContextHolder;
+import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
+import java.text.ParseException;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
@@ -44,6 +53,23 @@ public class FsIntegralOrderController extends BaseController
     private IFsIntegralOrderService fsIntegralOrderService;
     @Autowired
     private IFsExpressService expressService;
+
+    @Autowired
+    private IFsStoreOrderService fsStoreOrderService;
+
+    @Autowired
+    private IFsIntegralOrderLogsService integralOrderLogsService;
+
+    @Autowired
+    private IFsIntegralOrderDfService integralOrderDfService;
+
+    @Autowired
+    private IFsDfAccountService fsDfAccountService;
+    @Autowired
+    private FsIntegralOrderMapper integralOrderMapper;
+    @Autowired
+    private FsIntegralOrderMapper fsIntegralOrderMapper;
+
     /**
      * 查询积分商品订单列表
      */
@@ -52,6 +78,18 @@ public class FsIntegralOrderController extends BaseController
     public TableDataInfo list(FsIntegralOrderParam fsIntegralOrder)
     {
         startPage();
+        if (CloudHostUtils.hasCloudHostName("金牛明医")){
+            /*目前只有金牛有状态为6的查询,其他项目避免使用6状态码*/
+            if (fsIntegralOrder.getStatus() != null && fsIntegralOrder.getStatus().equals("6")) {
+                fsIntegralOrder.setStatus("1");
+                fsIntegralOrder.setIsPush(0);
+            }
+            List<FsIntegralOrderListVO> list = fsIntegralOrderService.selectFsIntegralOrderListByJn(fsIntegralOrder);
+            for (FsIntegralOrderListVO vo : list) {
+                vo.setUserPhone(decryptAutoPhoneMk(vo.getUserPhone()));
+            }
+            return getDataTable(list);
+        }
         List<FsIntegralOrderListVO> list = fsIntegralOrderService.selectFsIntegralOrderListVO(fsIntegralOrder);
         for (FsIntegralOrderListVO vo : list) {
             vo.setUserPhone(decryptAutoPhoneMk(vo.getUserPhone()));
@@ -67,6 +105,16 @@ public class FsIntegralOrderController extends BaseController
     @GetMapping("/export")
     public AjaxResult export(FsIntegralOrder fsIntegralOrder)
     {
+        if (CloudHostUtils.hasCloudHostName("金牛明医")&&fsIntegralOrder.getStatus() != null && fsIntegralOrder.getStatus().equals(6)) {
+            /*目前只有金牛有状态为6的查询,其他项目避免使用6状态码*/
+            FsIntegralOrderParam param = new FsIntegralOrderParam();
+            BeanUtil.copyProperties(fsIntegralOrder, param);
+            param.setStatus("1");
+            param.setIsPush(0);
+            List<FsIntegralOrderListVO> fsIntegralOrderListVOS = fsIntegralOrderService.selectFsIntegralOrderListByJn(param);
+            ExcelUtil<FsIntegralOrderListVO> util = new ExcelUtil<>(FsIntegralOrderListVO.class);
+            return util.exportExcel(new ArrayList<>(fsIntegralOrderListVOS), "积分商品订单数据");
+        }
         return fsIntegralOrderService.export(fsIntegralOrder);
     }
     /**
@@ -98,18 +146,33 @@ public class FsIntegralOrderController extends BaseController
     @GetMapping(value = "/getExpress/{id}")
     public R getExpress(@PathVariable("id") Long id)
     {
+        /**
+         * selectFsIntegralOrderByOrderId查询的数据表:fs_integral_order
+         * 需要执行添加字段的DDL语句
+         * ALTER TABLE `fs_integral_order`
+         * ADD COLUMN `login_account` VARCHAR(20) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '代服物流查询账号';
+         * */
         FsIntegralOrder fsIntegralOrder = fsIntegralOrderService.selectFsIntegralOrderByOrderId(id);
         ExpressInfoDTO expressInfoDTO=null;
-        if(StringUtils.isNotEmpty(fsIntegralOrder.getDeliverySn())){
-            String lastFourNumber = "";
-            if (fsIntegralOrder.getDeliveryCode().equals(ShipperCodeEnum.SF.getValue())) {
+        //代服管家 查询自己的物流
+        if (CloudHostUtils.hasCloudHostName("金牛明医")) {
+            FsStoreOrder fsStoreOrder = new FsStoreOrder();
+            fsStoreOrder.setOrderCode(fsIntegralOrder.getOrderCode());
+            //线程携带订单信息
+            OrderContextHolder.setIntegralOrder(fsIntegralOrder);
+            expressInfoDTO = fsStoreOrderService.getDfExpressInfoDTO(fsStoreOrder);
+        }else {
+            if (StringUtils.isNotEmpty(fsIntegralOrder.getDeliverySn())) {
+                String lastFourNumber = "";
+                if (fsIntegralOrder.getDeliveryCode().equals(ShipperCodeEnum.SF.getValue())) {
 
-                lastFourNumber = fsIntegralOrder.getUserPhone();
-                if (lastFourNumber.length() == 11) {
-                    lastFourNumber = StrUtil.sub(lastFourNumber, lastFourNumber.length(), -4);
+                    lastFourNumber = fsIntegralOrder.getUserPhone();
+                    if (lastFourNumber.length() == 11) {
+                        lastFourNumber = StrUtil.sub(lastFourNumber, lastFourNumber.length(), -4);
+                    }
                 }
+                expressInfoDTO = expressService.getExpressInfo(fsIntegralOrder.getOrderCode(), fsIntegralOrder.getDeliveryCode(), fsIntegralOrder.getDeliverySn(), lastFourNumber);
             }
-            expressInfoDTO=expressService.getExpressInfo(fsIntegralOrder.getOrderCode(),fsIntegralOrder.getDeliveryCode(),fsIntegralOrder.getDeliverySn(),lastFourNumber);
         }
         return R.ok().put("data",expressInfoDTO);
     }
@@ -178,4 +241,173 @@ public class FsIntegralOrderController extends BaseController
         String orderCode = requestBody.get("orderCode");
         return toAjax(fsIntegralOrderService.cancelOrder(orderCode));
     }
+    /**
+     * 申请退款
+     * 接口不校验是否发货
+     * */
+    @PreAuthorize("@ss.hasPermi('his:integralOrder:cancel')")
+    @Log(title = "积分商品订单", businessType = BusinessType.UPDATE)
+    @PostMapping("/mandatoryRefunds")
+    public AjaxResult mandatoryRefunds(@RequestBody Map<String, String> requestBody){
+        String orderCode = requestBody.get("orderCode");
+        return toAjax(fsIntegralOrderService.mandatoryRefunds(orderCode));
+    }
+
+    /**
+     * 确认收货
+     * todo:权限标识符待定
+     */
+    @Log(title = "积分商品订单", businessType = BusinessType.UPDATE)
+    @GetMapping("/finishOrder/{orderCode}")
+    public AjaxResult finishOrder(@PathVariable("orderCode") String orderCode) {
+        return toAjax(fsIntegralOrderService.finishOrder(orderCode));
+    }
+
+    @ApiOperation("批量设置订单账户")
+    @Log(title = "积分商品订单", businessType = BusinessType.UPDATE)
+//    @PreAuthorize("@ss.hasPermi('his:storeOrder:createErpOrder')")
+    @PostMapping(value = "/batchSetErpOrder")
+    @Transactional(rollbackFor = Exception.class)
+    public R batchSetErpOrder(@RequestBody BatchSetErpOrderParam param)
+    {
+        String nickName = getLoginUser().getUser().getNickName();
+        String loginAccount = param.getLoginAccount();
+        if (StringUtils.isBlank(loginAccount)){
+            return R.error("未选择erp账户");
+        }
+        FsIntegralOrderDf df = getDFInfo(loginAccount);
+        if (df.getLoginAccount() == null){
+            return R.error("未查询到所选erp账户");
+        }
+        List<Long> orderIds = param.getOrderIds();
+        List<FsIntegralOrder> list = null;
+        if (!orderIds.isEmpty()) {
+            list = fsIntegralOrderService.selectFsIntegralOrderByOrderIds(orderIds);
+//            orderIds = list.stream().map(FsIntegralOrder::getOrderId).collect(Collectors.toList());
+        }else{
+            return R.ok();
+        }
+        if (list.isEmpty())
+            return R.ok();
+        List<String> erpPhones = param.getErpPhones();
+        int[] index = {0}; // 使用数组模拟可变引用
+        list.forEach(item->{
+            df.setOrderId(item.getOrderId());
+            df.setOrderCode(item.getOrderCode());
+            if (!erpPhones.isEmpty()) {
+                int currentIndex = index[0] % erpPhones.size(); // 循环使用
+                df.setErpPhone(erpPhones.get(currentIndex));
+                index[0]++; // 顺序递增
+            }
+            FsIntegralOrder order = new FsIntegralOrder();
+            //更新一下积分订单的loginaccount这个字段
+            order.setOrderId(item.getOrderId());
+            order.setLoginAccount(df.getLoginAccount());
+//            fsIntegralOrderService.updateFsIntegralOrder(order);
+            fsIntegralOrderMapper.updateById(order);
+            FsIntegralOrderDf temp = integralOrderDfService.getOne(Wrappers.<FsIntegralOrderDf>lambdaQuery().eq(FsIntegralOrderDf::getOrderId,item.getOrderId()));
+            df.setParcelQuantity(param.getParcelQuantity());
+//            df.setErpPhone(param.getErpPhone().trim());
+            if (temp != null){
+                df.setUpdateTime(LocalDateTime.now());
+                integralOrderDfService.updateById(df);
+            } else {
+                integralOrderDfService.insertFsIntegralOrderDf(df);
+            }
+            // 添加积分订单操作记录
+            FsIntegralOrderLogs logs = new FsIntegralOrderLogs();
+            logs.setLogsId(IdUtils.fastUUID());
+            logs.setOrderId(item.getOrderId());
+            logs.setChangeType("set_erp_account");
+            logs.setChangeMessage(nickName+"设置ERP账户为:" + loginAccount);
+            logs.setChangeTime(LocalDateTime.now());
+            logs.setOperator(nickName);
+            integralOrderLogsService.insertFsIntegralOrderLogs(logs);
+        });
+        return R.ok();
+    }
+
+    //    @Log(title = "手动推管易", businessType = BusinessType.INSERT)
+    @ApiOperation("批量创建ERP订单")
+//    @PreAuthorize("@ss.hasPermi('his:storeOrder:createErpOrder')")
+    @Log(title = "积分商品订单", businessType = BusinessType.UPDATE)
+    @PostMapping(value = "/batchCreateErpOrder")
+    public R batchCreateErpOrder(@RequestBody BatchCreateErpOrderParam param) throws ParseException {
+//        String nickName = getLoginUser().getUser().getNickName();
+        String loginAccount = param.getLoginAccount();
+        if (StringUtils.isBlank(loginAccount)){
+            return R.error("未选择推送erp账户");
+        }
+        FsIntegralOrderDf df = getDFInfo(loginAccount);
+        if (df.getLoginAccount() == null){
+            return R.error("未查询到所选erp账户");
+        }
+        List<Long> orderIds = param.getOrderIds();
+        List<String> erpPhones = param.getErpPhones();
+        int[] index = {0}; // 使用数组模拟可变引用
+        if (!orderIds.isEmpty()) {
+            List<FsIntegralOrder> orders = integralOrderMapper.selectList(Wrappers.<FsIntegralOrder>lambdaQuery().in(FsIntegralOrder::getOrderId, orderIds));
+            for (FsIntegralOrder order : orders) {
+                df.setOrderId(order.getOrderId());
+                df.setOrderCode(order.getOrderCode());
+                FsIntegralOrderDf temp = integralOrderDfService.getBaseMapper().selectById(order.getOrderId());
+                //如果是没有代服表数据,就用传过来的df账号,如果有就不更新df数据直接拿之前的数据创建erp
+                if (temp == null){
+                    if (!erpPhones.isEmpty()) {
+                        int currentIndex = index[0] % erpPhones.size(); // 循环使用
+                        df.setErpPhone(erpPhones.get(currentIndex));
+                        index[0]++; // 顺序递增
+                    }
+                    df.setParcelQuantity(param.getParcelQuantity()); //设置包裹数量
+                    integralOrderDfService.getBaseMapper().insert(df);
+                    order.setLoginAccount(df.getLoginAccount());
+                    integralOrderMapper.updateById(order);
+                }
+                fsIntegralOrderService.createErpOrder(order.getOrderId());
+
+                // 添加积分订单操作记录
+                FsIntegralOrderLogs logs = new FsIntegralOrderLogs();
+                logs.setLogsId(IdUtils.fastUUID());
+                logs.setOrderId(order.getOrderId());
+                logs.setChangeType("create_erp_order");
+                logs.setChangeMessage(getLoginUser().getUser().getNickName()+"创建ERP订单,账户:" + loginAccount);
+                logs.setChangeTime(LocalDateTime.now());
+                logs.setOperator(getLoginUser().getUser().getNickName());
+                integralOrderLogsService.insertFsIntegralOrderLogs(logs);
+            }
+        }
+        return R.ok("推送成功");
+    }
+
+    @Log(title = "导入修改订单", businessType = BusinessType.IMPORT)
+    @PostMapping("/importOrderStatusData")
+    public AjaxResult importOrderStatusData(MultipartFile file) throws Exception
+    {
+        ExcelUtil<FsIntegralOrderExcelVO> util = new ExcelUtil<>(FsIntegralOrderExcelVO.class);
+        List<FsIntegralOrderExcelVO> list = util.importExcel(file.getInputStream());
+        String message = fsIntegralOrderService.importOrderStatusData(list);
+        return AjaxResult.success(message);
+    }
+
+    @GetMapping("/importUpdateOrderTemplate")
+    public AjaxResult importUpdateOrderTemplate()
+    {
+        ExcelUtil<FsIntegralOrderExcelVO> util = new ExcelUtil<>(FsIntegralOrderExcelVO.class);
+        return util.importTemplateExcel("修改订单");
+    }
+    private FsIntegralOrderDf getDFInfo(String loginAccount) {
+        //查询订单账户 判断是否存在该订单账户
+        FsDfAccount erpAccount = fsDfAccountService.selectFsDfAccountByAccount(loginAccount);
+        FsIntegralOrderDf df = new FsIntegralOrderDf();
+        if (erpAccount != null){
+            //添加df记录
+            df.setAppKey(erpAccount.getDfAppKey());
+            df.setAppSecret(erpAccount.getDfAppsecret());
+            df.setLoginAccount(loginAccount);
+            df.setMonthlyCard(erpAccount.getMonthlyCard());
+            df.setExpressProductCode(erpAccount.getExpressProductCode());
+            df.setStatus(0);
+        }
+        return df;
+    }
 }

+ 109 - 0
fs-admin/src/main/java/com/fs/his/controller/FsIntegralOrderLogsController.java

@@ -0,0 +1,109 @@
+package com.fs.his.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.his.domain.FsIntegralOrderLogs;
+import com.fs.his.service.IFsIntegralOrderLogsService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 订单操作记录Controller
+ *
+ * @author fs
+ * @date 2025-11-25
+ */
+@RestController
+@RequestMapping("/his/logs")
+public class FsIntegralOrderLogsController extends BaseController
+{
+    @Autowired
+    private IFsIntegralOrderLogsService fsIntegralOrderLogsService;
+
+    /**
+     * 查询订单操作记录列表
+     */
+//    @PreAuthorize("@ss.hasPermi('his:logs:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsIntegralOrderLogs fsIntegralOrderLogs)
+    {
+        startPage();
+        List<FsIntegralOrderLogs> list = fsIntegralOrderLogsService.selectFsIntegralOrderLogsList(fsIntegralOrderLogs);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出订单操作记录列表
+     */
+//    @PreAuthorize("@ss.hasPermi('his:logs:export')")
+    @Log(title = "订单操作记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsIntegralOrderLogs fsIntegralOrderLogs)
+    {
+        List<FsIntegralOrderLogs> list = fsIntegralOrderLogsService.selectFsIntegralOrderLogsList(fsIntegralOrderLogs);
+        ExcelUtil<FsIntegralOrderLogs> util = new ExcelUtil<FsIntegralOrderLogs>(FsIntegralOrderLogs.class);
+        return util.exportExcel(list, "订单操作记录数据");
+    }
+
+    /**
+     * 获取订单操作记录详细信息
+     */
+//    @PreAuthorize("@ss.hasPermi('his:logs:query')")
+    @GetMapping(value = "/{logsId}")
+    public AjaxResult getInfo(@PathVariable("logsId") String logsId)
+    {
+        return AjaxResult.success(fsIntegralOrderLogsService.selectFsIntegralOrderLogsByLogsId(logsId));
+    }
+
+    /**
+     * 新增订单操作记录
+     */
+//    @PreAuthorize("@ss.hasPermi('his:logs:add')")
+    @Log(title = "订单操作记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsIntegralOrderLogs fsIntegralOrderLogs)
+    {
+        return toAjax(fsIntegralOrderLogsService.insertFsIntegralOrderLogs(fsIntegralOrderLogs));
+    }
+
+    /**
+     * 修改订单操作记录
+     */
+//    @PreAuthorize("@ss.hasPermi('his:logs:edit')")
+    @Log(title = "订单操作记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsIntegralOrderLogs fsIntegralOrderLogs)
+    {
+        return toAjax(fsIntegralOrderLogsService.updateFsIntegralOrderLogs(fsIntegralOrderLogs));
+    }
+
+    /**
+     * 根据订单ID查询操作记录
+     */
+//    @PreAuthorize("@ss.hasPermi('his:logs:query')")
+    @GetMapping("/order/{orderId}")
+    public AjaxResult getLogsByOrderId(@PathVariable("orderId") Long orderId)
+    {
+        FsIntegralOrderLogs queryParam = new FsIntegralOrderLogs();
+        queryParam.setOrderId(orderId);
+        List<FsIntegralOrderLogs> list = fsIntegralOrderLogsService.selectFsIntegralOrderLogsList(queryParam);
+        return AjaxResult.success(list);
+    }
+
+    /**
+     * 删除订单操作记录
+     */
+//    @PreAuthorize("@ss.hasPermi('his:logs:remove')")
+    @Log(title = "订单操作记录", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{logsIds}")
+    public AjaxResult remove(@PathVariable String[] logsIds)
+    {
+        return toAjax(fsIntegralOrderLogsService.deleteFsIntegralOrderLogsByLogsIds(logsIds));
+    }
+}

+ 30 - 4
fs-admin/src/main/java/com/fs/his/controller/FsPackageOrderController.java

@@ -1,5 +1,6 @@
 package com.fs.his.controller;
 
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
@@ -10,10 +11,7 @@ import com.fs.his.domain.FsExportTask;
 import com.fs.his.mapper.FsStorePaymentMapper;
 import com.fs.his.param.FsPackageOrderParam;
 import com.fs.his.service.IFsExportTaskService;
-import com.fs.his.vo.FsPackageOrderExcelVO;
-import com.fs.his.vo.FsPackageOrderListVO;
-import com.fs.his.vo.FsPackageOrderVO;
-import com.fs.his.vo.FsStoreOrderVO;
+import com.fs.his.vo.*;
 import com.fs.ybPay.service.IPayService;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -62,6 +60,20 @@ public class FsPackageOrderController extends BaseController
     public TableDataInfo list(FsPackageOrderParam  fsPackageOrder)
     {
         startPage();
+        //根据订单权限查询相关公司订单
+        try {
+            Long companyId = getLoginUser().getUser().getCompanyId();
+            if (companyId!=null){
+                if (fsPackageOrder.getCompanyId()!=null){
+                    if (!companyId.equals(fsPackageOrder.getCompanyId())) {
+                        return getDataTable(new ArrayList<FsStoreOrderListAndStatisticsVo>());
+                    }
+                }
+                fsPackageOrder.setCompanyId(companyId);
+            }
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
+        }
         if (fsPackageOrder.getPhoneMk()!=null&&fsPackageOrder.getPhoneMk()!=""){
             fsPackageOrder.setPhone(encryptPhone(fsPackageOrder.getPhoneMk()));
         }
@@ -86,6 +98,20 @@ public class FsPackageOrderController extends BaseController
         if (fsPackageOrderService.isEntityNull(fsPackageOrder)){
             return AjaxResult.error("请筛选数据导出");
         }
+        //根据订单权限查询相关公司订单
+        try {
+            Long companyId = getLoginUser().getUser().getCompanyId();
+            if (companyId!=null){
+                if (fsPackageOrder.getCompanyId()!=null){
+                    if (!companyId.equals(fsPackageOrder.getCompanyId())) {
+                        return AjaxResult.error("请筛选数据自己公司数据");
+                    }
+                }
+                fsPackageOrder.setCompanyId(companyId);
+            }
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
+        }
         fsPackageOrder.setStatus(status); //解决isEntityNull方法后status缺失
         Long count = fsPackageOrderService.selectFsPackageOrderExcelListVOCount(fsPackageOrder);
         if (count>30000){

+ 42 - 1
fs-admin/src/main/java/com/fs/his/controller/FsPrescribeController.java

@@ -72,6 +72,20 @@ public class FsPrescribeController extends BaseController
     public TableDataInfo list(FsPrescribeParam fsPrescribe)
     {
         startPage();
+        //根据订单权限查询相关公司订单
+        try {
+            Long companyId = getLoginUser().getUser().getCompanyId();
+            if (companyId!=null){
+                if (fsPrescribe.getCompanyId()!=null){
+                    if (!companyId.equals(fsPrescribe.getCompanyId())) {
+                        return getDataTable(new ArrayList<>());
+                    }
+                }
+                fsPrescribe.setCompanyId(companyId);
+            }
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
+        }
         List<FsPrescribeListVO> list = fsPrescribeService.selectFsPrescribeListVO(fsPrescribe);
         for (FsPrescribeListVO vo : list){
             if (vo.getPatientTel()!=null){
@@ -97,6 +111,20 @@ public class FsPrescribeController extends BaseController
             return AjaxResult.error("请筛选数据导出");
         }
         logger.info("tc>\n【导出处方】:{}", SecurityUtils.getUserId());
+        //根据订单权限查询相关公司订单
+        try {
+            Long companyId = getLoginUser().getUser().getCompanyId();
+            if (companyId!=null){
+                if (fsPrescribe.getCompanyId()!=null){
+                    if (!companyId.equals(fsPrescribe.getCompanyId())) {
+                        return AjaxResult.error("请筛选数据自己公司数据");
+                    }
+                }
+                fsPrescribe.setCompanyId(companyId);
+            }
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
+        }
         Long count = fsPrescribeService.selectFsPrescribeExcelListVOCount(fsPrescribe);
         if (count>30000){
             return AjaxResult.error("导出数据不可超过3w条");
@@ -131,7 +159,20 @@ public class FsPrescribeController extends BaseController
         if (exportType1>0){
             return AjaxResult.error("你已经有正在导出的任务");
         }
-
+        //根据订单权限查询相关公司订单
+        try {
+            Long companyId = getLoginUser().getUser().getCompanyId();
+            if (companyId!=null){
+                if (fsPrescribe.getCompanyId()!=null){
+                    if (!companyId.equals(fsPrescribe.getCompanyId())) {
+                        return AjaxResult.error("请筛选数据自己公司数据");
+                    }
+                }
+                fsPrescribe.setCompanyId(companyId);
+            }
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
+        }
         FsExportTask task=new FsExportTask();
         task.setTaskType(6);
         task.setStatus(0);

+ 108 - 0
fs-admin/src/main/java/com/fs/his/controller/FsQuestionAndAnswerController.java

@@ -0,0 +1,108 @@
+package com.fs.his.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.his.domain.FsQuestionAndAnswer;
+import com.fs.his.service.IFsQuestionAndAnswerService;
+import com.fs.his.vo.OptionsVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 问答Controller
+ *
+ * @author fs
+ * @date 2025-09-29
+ */
+@RestController
+@RequestMapping("/his/answer")
+public class FsQuestionAndAnswerController extends BaseController
+{
+    @Autowired
+    private IFsQuestionAndAnswerService fsQuestionAndAnswerService;
+
+    /**
+     * 查询问答列表
+     */
+    @PreAuthorize("@ss.hasPermi('his:answer:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsQuestionAndAnswer fsQuestionAndAnswer)
+    {
+        startPage();
+        List<FsQuestionAndAnswer> list = fsQuestionAndAnswerService.selectFsQuestionAndAnswerList(fsQuestionAndAnswer);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出问答列表
+     */
+    @PreAuthorize("@ss.hasPermi('his:answer:export')")
+    @Log(title = "问答", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsQuestionAndAnswer fsQuestionAndAnswer)
+    {
+        List<FsQuestionAndAnswer> list = fsQuestionAndAnswerService.selectFsQuestionAndAnswerList(fsQuestionAndAnswer);
+        ExcelUtil<FsQuestionAndAnswer> util = new ExcelUtil<FsQuestionAndAnswer>(FsQuestionAndAnswer.class);
+        return util.exportExcel(list, "问答数据");
+    }
+
+    /**
+     * 获取问答详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('his:answer:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsQuestionAndAnswerService.selectFsQuestionAndAnswerById(id));
+    }
+
+    /**
+     * 新增问答
+     */
+    @PreAuthorize("@ss.hasPermi('his:answer:add')")
+    @Log(title = "问答", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsQuestionAndAnswer fsQuestionAndAnswer)
+    {
+        return toAjax(fsQuestionAndAnswerService.insertFsQuestionAndAnswer(fsQuestionAndAnswer));
+    }
+
+    /**
+     * 修改问答
+     */
+    @PreAuthorize("@ss.hasPermi('his:answer:edit')")
+    @Log(title = "问答", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsQuestionAndAnswer fsQuestionAndAnswer)
+    {
+        return toAjax(fsQuestionAndAnswerService.updateFsQuestionAndAnswer(fsQuestionAndAnswer));
+    }
+
+    /**
+     * 删除问答
+     */
+    @PreAuthorize("@ss.hasPermi('his:answer:remove')")
+    @Log(title = "问答", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsQuestionAndAnswerService.deleteFsQuestionAndAnswerByIds(ids));
+    }
+
+    /**
+     * 查询问答列表
+     */
+    @GetMapping("/allList")
+    public TableDataInfo getHospital()
+    {
+        List<OptionsVO> list = fsQuestionAndAnswerService.selectAllQuestionOptions();
+        return getDataTable(list);
+    }
+}

+ 114 - 0
fs-admin/src/main/java/com/fs/his/controller/FsStoreActivityController.java

@@ -0,0 +1,114 @@
+package com.fs.his.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.his.domain.FsPackage;
+import com.fs.his.service.IFsPackageService;
+import com.fs.store.domain.FsStoreActivity;
+import com.fs.store.service.IFsStoreActivityService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 活动Controller
+ *
+ * @author fs
+ * @date 2022-11-18
+ */
+@RestController
+@RequestMapping("/his/storeActivity")
+public class FsStoreActivityController extends BaseController
+{
+    @Autowired
+    private IFsStoreActivityService fsStoreActivityService;
+    @Autowired
+    private IFsPackageService packageService;
+    /**
+     * 查询活动列表
+     */
+    @PreAuthorize("@ss.hasPermi('his:storeActivity:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreActivity fsStoreActivity)
+    {
+        startPage();
+        List<FsStoreActivity> list = fsStoreActivityService.selectFsStoreActivityList(fsStoreActivity);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出活动列表
+     */
+    @PreAuthorize("@ss.hasPermi('his:storeActivity:export')")
+    @Log(title = "活动", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreActivity fsStoreActivity)
+    {
+        List<FsStoreActivity> list = fsStoreActivityService.selectFsStoreActivityList(fsStoreActivity);
+        ExcelUtil<FsStoreActivity> util = new ExcelUtil<FsStoreActivity>(FsStoreActivity.class);
+        return util.exportExcel(list, "storeActivity");
+    }
+
+    /**
+     * 获取活动详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('his:storeActivity:query')")
+    @GetMapping(value = "/{activityId}")
+    public R getInfo(@PathVariable("activityId") Long activityId)
+    {
+        FsStoreActivity activity=fsStoreActivityService.selectFsStoreActivityById(activityId);
+        List<FsPackage> packages =new ArrayList<>();
+        String productIds = activity.getProductIds();
+        if(StringUtils.isNotBlank(productIds)){
+            Long[] list = Arrays.stream(productIds.split(","))
+                    .map(Long::valueOf)
+                    .toArray(Long[]::new);
+            packages = packageService.selectFsPackageListByIds(list);
+        }
+        return R.ok().put("activity",activity).put("packages",packages);
+    }
+
+    /**
+     * 新增活动
+     */
+    @PreAuthorize("@ss.hasPermi('his:storeActivity:add')")
+    @Log(title = "活动", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreActivity fsStoreActivity)
+    {
+        return toAjax(fsStoreActivityService.insertFsStoreActivity(fsStoreActivity));
+    }
+
+    /**
+     * 修改活动
+     */
+    @PreAuthorize("@ss.hasPermi('his:storeActivity:edit')")
+    @Log(title = "活动", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreActivity fsStoreActivity)
+    {
+        return toAjax(fsStoreActivityService.updateFsStoreActivity(fsStoreActivity));
+    }
+
+    /**
+     * 删除活动
+     */
+    @PreAuthorize("@ss.hasPermi('his:storeActivity:remove')")
+    @Log(title = "活动", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{activityIds}")
+    public AjaxResult remove(@PathVariable Long[] activityIds)
+    {
+        return toAjax(fsStoreActivityService.deleteFsStoreActivityByIds(activityIds));
+    }
+}

+ 29 - 0
fs-admin/src/main/java/com/fs/his/controller/FsStoreAfterSalesController.java

@@ -1,5 +1,6 @@
 package com.fs.his.controller;
 
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
@@ -66,6 +67,20 @@ public class FsStoreAfterSalesController extends BaseController
     public TableDataInfo list(FsStoreAfterSalesParam fsStoreAfterSales)
     {
         startPage();
+        //根据订单权限查询相关公司订单
+        try {
+            Long companyId = getLoginUser().getUser().getCompanyId();
+            if (companyId!=null){
+                if (fsStoreAfterSales.getCompanyId()!=null){
+                    if (!companyId.equals(fsStoreAfterSales.getCompanyId())) {
+                        return getDataTable(new ArrayList<FsStoreAfterSalesListVO>());
+                    }
+                }
+                fsStoreAfterSales.setCompanyId(companyId);
+            }
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
+        }
         if(!StringUtils.isEmpty(fsStoreAfterSales.getCreateTimeRange())){
             fsStoreAfterSales.setCreateTimeList(fsStoreAfterSales.getCreateTimeRange().split("--"));
         }
@@ -88,6 +103,20 @@ public class FsStoreAfterSalesController extends BaseController
         if (exportType1>0){
             return AjaxResult.error("你已经有正在导出的任务");
         }
+        //根据订单权限查询相关公司订单
+        try {
+            Long companyId = getLoginUser().getUser().getCompanyId();
+            if (companyId!=null){
+                if (fsStoreAfterSales.getCompanyId()!=null){
+                    if (!companyId.equals(fsStoreAfterSales.getCompanyId())) {
+                        return AjaxResult.error("请筛选数据自己公司数据");
+                    }
+                }
+                fsStoreAfterSales.setCompanyId(companyId);
+            }
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
+        }
         if(!StringUtils.isEmpty(fsStoreAfterSales.getCreateTimeRange())){
             fsStoreAfterSales.setCreateTimeList(fsStoreAfterSales.getCreateTimeRange().split("--"));
         }

+ 60 - 5
fs-admin/src/main/java/com/fs/his/controller/FsStoreOrderController.java

@@ -34,6 +34,7 @@ import com.fs.his.dto.TracesDTO;
 import com.fs.his.enums.FsStoreOrderLogEnum;
 import com.fs.his.enums.FsStoreOrderStatusEnum;
 import com.fs.his.enums.ShipperCodeEnum;
+import com.fs.his.mapper.FsUserInformationCollectionMapper;
 import com.fs.his.param.FsFollowMsgParam;
 import com.fs.his.param.FsStoreOrderParam;
 import com.fs.his.param.FsStoreOrderSalesParam;
@@ -125,16 +126,36 @@ public class FsStoreOrderController extends BaseController
 
     @Autowired
     private IFsDfAccountService fsDfAccountService;
+    @Autowired
+    private FsUserInformationCollectionMapper userInformationCollectionMapper;
     /**
      * 查询订单列表
      */
     @PostMapping("/list")
     public FsStoreOrderListAndStatisticsVo list(@RequestBody FsStoreOrderParam fsStoreOrder)
     {
+        FsStoreOrderListAndStatisticsVo vo = new FsStoreOrderListAndStatisticsVo();
         PageHelper.startPage(fsStoreOrder);
         if (fsStoreOrder.getUserPhoneMk()!=null&& !fsStoreOrder.getUserPhoneMk().isEmpty()){
             fsStoreOrder.setUserPhone(encryptPhone(fsStoreOrder.getUserPhoneMk()));
         }
+        //根据订单权限查询相关公司订单
+        try {
+            Long companyId = getLoginUser().getUser().getCompanyId();
+            if (companyId!=null){
+                if (fsStoreOrder.getCompanyId()!=null){
+                    if (!companyId.equals(fsStoreOrder.getCompanyId())) {
+                        vo.setRows(new ArrayList<FsStoreOrderListAndStatisticsVo>());
+                        vo.setTotal(0);
+                        return vo;
+                    }
+                }
+                fsStoreOrder.setCompanyId(companyId);
+            }
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
+        }
+
         List<FsStoreOrderListVO> list;
         if (StringUtils.isNotBlank(fsStoreOrder.getErpAccount())){
             //金牛erp查询
@@ -146,17 +167,17 @@ public class FsStoreOrderController extends BaseController
         TableDataInfo dataTable = getDataTable(list);
         if ("金牛明医".equals(cloudHostProper.getCompanyName())){
             if (fsStoreOrder.getStatus() !=null && fsStoreOrder.getStatus() != 1){
-                list.forEach(vo->{
+                list.forEach(fsStoreOrderListVO->{
                     //查询顺丰代服账号
-                    FsStoreOrderDf df = fsStoreOrderDfService.selectFsStoreOrderDfByOrderId(vo.getOrderId());
+                    FsStoreOrderDf df = fsStoreOrderDfService.selectFsStoreOrderDfByOrderId(fsStoreOrderListVO.getOrderId());
                     if (df != null){
-                        vo.setErpAccount(df.getLoginAccount());
+                        fsStoreOrderListVO.setErpAccount(df.getLoginAccount());
                     }
                 });
             }
             dataTable.setMsg("jnmy");
         }
-        FsStoreOrderListAndStatisticsVo vo = new FsStoreOrderListAndStatisticsVo();
+
         BeanUtils.copyProperties(dataTable, vo);
         if (dataTable.getTotal()>0){
             Map<String,BigDecimal> statistics= fsStoreOrderService.selectFsStoreOrderStatistics(fsStoreOrder);
@@ -197,6 +218,20 @@ public class FsStoreOrderController extends BaseController
             return AjaxResult.error("请筛选数据导出");
         }
         logger.info("tc>\n【订单导出】:{}", SecurityUtils.getUserId());
+        //根据订单权限查询相关公司订单
+        try {
+            Long companyId = getLoginUser().getUser().getCompanyId();
+            if (companyId!=null){
+                if (fsStoreOrder.getCompanyId()!=null){
+                    if (!companyId.equals(fsStoreOrder.getCompanyId())) {
+                        return AjaxResult.error("请筛选数据自己公司数据");
+                    }
+                }
+                fsStoreOrder.setCompanyId(companyId);
+            }
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
+        }
         Long count = fsStoreOrderService.selectFsStoreOrderExcelListVOCount(fsStoreOrder);
         if (count>30000){
             return AjaxResult.error("导出数据不可超过3w条");
@@ -239,7 +274,21 @@ public class FsStoreOrderController extends BaseController
             return AjaxResult.error("请筛选数据导出");
         }
         logger.info("tc>\n【咨询报告】:{}", SecurityUtils.getUserId());
-        Long count;
+        //根据订单权限查询相关公司订单
+        try {
+            Long companyId = getLoginUser().getUser().getCompanyId();
+            if (companyId!=null){
+                if (param.getCompanyId()!=null){
+                    if (!companyId.equals(param.getCompanyId())) {
+                        return AjaxResult.error("请筛选数据自己公司数据");
+                    }
+                }
+                param.setCompanyId(companyId);
+            }
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
+        }
+        Long count = 0L;
         if (StringUtils.isNotBlank(param.getErpAccount())){
             //金牛erp查询
             count = fsStoreOrderService.selectFsStoreOrderListVOByErpAccountByExportCount(param);
@@ -602,6 +651,12 @@ public class FsStoreOrderController extends BaseController
     public AjaxResult sendGoods(@RequestBody FsStoreOrder fsStoreOrder)
     {
         String nickName = getLoginUser().getUser().getNickName();
+        if(CloudHostUtils.hasCloudHostName("金牛明医")){
+            FsUserInformationCollection fsUserInformationCollection = userInformationCollectionMapper.selectFsUserInformationCollectionByOrderCode(fsStoreOrder.getOrderCode());
+            if (fsUserInformationCollection != null&&fsUserInformationCollection.getDoctorType2Confirm()!=1) {
+                return AjaxResult.error("药师未确认");
+            }
+        }
         return toAjax(fsStoreOrderService.sendGoods(fsStoreOrder,nickName));
     }
     /**

+ 29 - 0
fs-admin/src/main/java/com/fs/his/controller/FsStoreSubOrderController.java

@@ -1,5 +1,6 @@
 package com.fs.his.controller;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import com.fs.his.domain.FsStoreOrder;
@@ -46,6 +47,20 @@ public class FsStoreSubOrderController extends BaseController
     public TableDataInfo list(FsStoreOrderParam fsStoreSubOrder)
     {
         startPage();
+        //根据订单权限查询相关公司订单
+        try {
+            Long companyId = getLoginUser().getUser().getCompanyId();
+            if (companyId!=null){
+                if (fsStoreSubOrder.getCompanyId()!=null){
+                    if (!companyId.equals(fsStoreSubOrder.getCompanyId())) {
+                        return getDataTable(new ArrayList<>());
+                    }
+                }
+                fsStoreSubOrder.setCompanyId(companyId);
+            }
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
+        }
         List<FsStoreSubOrderListVO> list = fsStoreSubOrderService.selectFsStoreSubOrderList(fsStoreSubOrder);
         return getDataTable(list);
     }
@@ -61,6 +76,20 @@ public class FsStoreSubOrderController extends BaseController
         if (fsStoreSubOrderService.isEntityNull(fsStoreSubOrder)){
             return AjaxResult.error("请筛选数据导出");
         }
+        //根据订单权限查询相关公司订单
+        try {
+            Long companyId = getLoginUser().getUser().getCompanyId();
+            if (companyId!=null){
+                if (fsStoreSubOrder.getCompanyId()!=null){
+                    if (!companyId.equals(fsStoreSubOrder.getCompanyId())) {
+                        return AjaxResult.error("请筛选数据自己公司数据");
+                    }
+                }
+                fsStoreSubOrder.setCompanyId(companyId);
+            }
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
+        }
         Long count = fsStoreSubOrderService.selectFsStoreSubOrderListCount(fsStoreSubOrder);
         if (count>30000){
             return AjaxResult.error("导出数据不可超过3w条");

+ 20 - 2
fs-admin/src/main/java/com/fs/his/controller/FsUserController.java

@@ -99,7 +99,7 @@ public class FsUserController extends BaseController
             fsUser.setPhone(encryptPhone(fsUser.getPhoneMk()));
         }
         if(StringUtils.isNotEmpty(fsUser.getPhone())){
-            fsUser.setPhone(encryptPhone(fsUser.getPhone()));
+            fsUser.setEncryptPhone(encryptPhone(fsUser.getPhone()));
         }
         List<FsUserVO> list = fsUserService.selectFsUserListVO(fsUser);
         SysRole sysRole = isCheckPermission();
@@ -190,7 +190,15 @@ public class FsUserController extends BaseController
         if(StringUtils.isNotEmpty(fsUser.getPhone())){
             fsUser.setPhone(encryptPhone(fsUser.getPhone()));
         }
-        List<FsUserVO> list = fsUserService.selectFsUserVOListByProject(fsUser);
+        if(StringUtils.isNotEmpty(fsUser.getCompanyUserIdMulti())){
+            String[] split = fsUser.getCompanyUserIdMulti().split(",");
+            fsUser.setCompanyUserIds(split);
+        }
+//        List<FsUserVO> list = fsUserService.selectFsUserVOListByProject(fsUser);
+
+        // xgb sql执行太慢,优化修改
+        List<FsUserVO> list = fsUserService.selectFsUserVOListByProjectNew(fsUser);
+
         SysRole sysRole = isCheckPermission();
         for (FsUserVO fsUserVO : list) {
             if(fsUserVO.getPhone() != null&&fsUserVO.getPhone()!=""){
@@ -399,5 +407,15 @@ public class FsUserController extends BaseController
         return userIntegralLogsService.addIntegralTemplate(integralTemplateParam);
     }
 
+    @PreAuthorize("@ss.hasPermi('his:user:unbind')")
+    @Log(title = "批量解绑会员(删除销售和会员的关系)", businessType = BusinessType.DELETE)
+    @DeleteMapping("/batchUnbind")
+    public AjaxResult batchUnbind(@RequestBody List<Long> userIds){
+        if(!userIds.isEmpty()){
+            return toAjax(userCompanyUserService.batchUnbind(userIds));
+        } else {
+            return error("请先选择会员");
+        }
+    }
 
 }

+ 94 - 0
fs-admin/src/main/java/com/fs/his/controller/FsUserExtractController.java

@@ -3,17 +3,35 @@ package com.fs.his.controller;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.IPUtils;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.core.config.WxPayProperties;
+import com.fs.his.domain.FsUser;
 import com.fs.his.domain.FsUserExtract;
 import com.fs.his.param.FsUserExtractParam;
+import com.fs.his.service.IFsUserBillService;
 import com.fs.his.service.IFsUserExtractService;
+import com.fs.his.service.IFsUserService;
 import com.fs.his.vo.FsUserExtractVO;
+import com.fs.hisStore.enums.BillDetailEnum;
+import com.fs.hisStore.service.IFsUserBillScrmService;
+import com.github.binarywang.wxpay.bean.entpay.EntPayRequest;
+import com.github.binarywang.wxpay.bean.entpay.EntPayResult;
+import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
+import com.github.binarywang.wxpay.config.WxPayConfig;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.service.EntPayService;
+import com.github.binarywang.wxpay.service.WxPayService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.interceptor.TransactionAspectSupport;
 import org.springframework.web.bind.annotation.*;
 
+import javax.servlet.http.HttpServletRequest;
 import java.util.List;
 
 /**
@@ -29,6 +47,17 @@ public class FsUserExtractController extends BaseController
     @Autowired
     private IFsUserExtractService fsUserExtractService;
 
+    @Autowired
+    private WxPayProperties wxPayProperties;
+    @Autowired
+    private IFsUserService fsUserService;
+
+    @Autowired
+    private WxPayService wxPayService;
+
+    @Autowired
+    private IFsUserBillScrmService billService;
+
     /**
      * 查询用户提现管理列表
      */
@@ -96,4 +125,69 @@ public class FsUserExtractController extends BaseController
     {
         return toAjax(fsUserExtractService.deleteFsUserExtractByExtractIds(extractIds));
     }
+
+
+
+    @PreAuthorize("@ss.hasPermi('his:userExtract:audit')")
+    @PostMapping("/audit")
+    @Transactional
+    public R audit(@RequestBody FsUserExtract fsUserExtract, HttpServletRequest servletRequest)
+    {
+        FsUserExtract extract=fsUserExtractService.selectFsUserExtractByExtractId(fsUserExtract.getExtractId());
+        if(extract.getStatus().equals(0)){
+            FsUser user=fsUserService.selectFsUserById(Long.valueOf(extract.getUserId()));
+            if(fsUserExtract.getStatus()==1){
+                WxPayConfig payConfig = new WxPayConfig();
+                payConfig.setAppId(wxPayProperties.getAppId());
+                payConfig.setMchId(wxPayProperties.getMchId());
+                payConfig.setMchKey(wxPayProperties.getMchKey());
+                payConfig.setSubAppId(org.apache.commons.lang3.StringUtils.trimToNull(null));
+                payConfig.setSubMchId(org.apache.commons.lang3.StringUtils.trimToNull(null));
+                payConfig.setKeyPath(null);
+                payConfig.setNotifyUrl(wxPayProperties.getNotifyUrl());
+                wxPayService.setConfig(payConfig);
+                EntPayService entPayService=wxPayService.getEntPayService();
+                EntPayRequest request=new EntPayRequest();
+                request.setAppid(wxPayProperties.getAppId());
+                request.setMchId(wxPayProperties.getMchId());
+                request.setOpenid(user.getMaOpenId());
+                request.setCheckName("NO_CHECK");
+                request.setSpbillCreateIp(IPUtils.getIpAddr(servletRequest));
+                request.setReUserName(user.getRealName());
+                request.setPartnerTradeNo(extract.getExtractId().toString());
+                request.setDescription("会员提现");
+                request.setAmount(WxPayUnifiedOrderRequest.yuanToFen(extract.getExtractPrice().toString()));
+                try {
+                    EntPayResult result=entPayService.entPay(request);
+                    if(result.getResultCode().equals(0)){
+                        extract.setStatus(1L);
+                        fsUserExtractService.updateFsUserExtract(extract);
+                    }
+                    return R.ok();
+                } catch (WxPayException e) {
+                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
+                    e.printStackTrace();
+                    return R.error(e.getMessage());
+                }
+
+            }
+            else if(fsUserExtract.getStatus()==-1){
+                extract.setStatus(-1L);
+                extract.setFailMsg(fsUserExtract.getFailMsg());
+                fsUserExtractService.updateFsUserExtract(extract);
+                user.setNowMoney(user.getNowMoney().add(extract.getExtractPrice()));
+                fsUserService.updateFsUser(user);
+                //插入流水
+                billService.addBill(user.getUserId(), BillDetailEnum.CATEGORY_1.getValue(),1,BillDetailEnum.TYPE_5.getDesc(),extract.getExtractPrice(),user.getNowMoney(),"提现申请驳回",extract.getExtractId().toString(),0l);
+                return R.ok();
+            }
+            else{
+                return R.error("非法操作");
+            }
+        }
+        else{
+            return R.error("非法操作");
+        }
+
+    }
 }

+ 12 - 0
fs-admin/src/main/java/com/fs/his/param/BatchCreateErpOrderParam.java

@@ -0,0 +1,12 @@
+package com.fs.his.param;
+
+import lombok.Data;
+
+import java.util.List;
+@Data
+public class BatchCreateErpOrderParam {
+    private List<Long> orderIds;
+    private String loginAccount;
+    private Integer parcelQuantity; //包裹数量
+    private List<String> erpPhones;
+}

+ 13 - 0
fs-admin/src/main/java/com/fs/his/param/BatchSetErpOrderParam.java

@@ -0,0 +1,13 @@
+package com.fs.his.param;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class BatchSetErpOrderParam {
+    private List<Long> orderIds;
+    private String loginAccount;
+    private Integer parcelQuantity; //包裹数量
+    private List<String> erpPhones;
+}

+ 247 - 0
fs-admin/src/main/java/com/fs/his/param/FurtherConsultationParam.java

@@ -0,0 +1,247 @@
+package com.fs.his.param;
+
+import lombok.Builder;
+import lombok.Data;
+
+/**
+ * 复诊信息实体请求参数
+ */
+@Data
+@Builder
+public class FurtherConsultationParam {
+
+    /**
+     * 接口调用凭证,可能不用传
+     */
+    private String accessToken;
+
+    /**
+     * 第三方厂商标识
+     */
+    private String clientId;
+
+    /**
+     * 唯一标识,用于唯一确定某条记录,避免重复上传,一般传该条数据的主键
+     */
+    private String thirdUniqueid;
+
+    /**
+     * 机构名称
+     */
+    private String orgName;
+
+    /**
+     * 机构编码,组织机构代码
+     */
+    private String orgCode;
+
+    /**
+     * 诊疗渠道,平台名称
+     */
+    private String channelName;
+
+    /**
+     * 复诊科室
+     */
+    private String section;
+
+    /**
+     * 科室编码,三医
+     */
+    private String sectionCode;
+
+    /**
+     * 复诊医师姓名
+     */
+    private String docName;
+
+    /**
+     * 执业资格证号
+     */
+    private String certificateNum;
+
+    /**
+     * 患者姓名
+     */
+    private String patientName;
+
+    /**
+     * 患者年龄,低于6岁为低龄儿童
+     */
+    private Integer patientAge;
+
+    /**
+     * 患者性别,1男/2女
+     */
+    private String patientSex;
+
+    /**
+     * 证件类型,1 身份证  2 护照
+     */
+    private Integer patientIdcardType;
+
+    /**
+     * 患者证件号码,18位
+     */
+    private String patientIdcardNum;
+
+    /**
+     * 网络复诊编号
+     */
+    private String furtherConsultNo;
+
+    /**
+     * 复诊类别,1、图文诊疗 2语音诊疗 3、视频诊疗
+     */
+    private Integer furtherConsulType;
+
+    /**
+     * 监护人姓名,患者年龄小于6岁,需填此项
+     */
+    private String guardianName;
+
+    /**
+     * 监护人身份证号,患者年龄小于6岁,需填此项
+     */
+    private String guardianIdcardNum;
+
+    /**
+     * 患者简要病史描述,病史摘要
+     */
+    private String medicalHistory;
+
+    /**
+     * 首诊诊断类型,1文字 2图片jpg格式 3图片png格式 4图片bmp格式
+     */
+    private Integer consultDiagnosisType;
+
+    /**
+     * 首诊诊断,复诊患者在首诊医院的诊断,如有多条,使用"|"进行分隔;当传图片时,需要传图片的base64字符串
+     */
+    private String consultDiagnosis;
+
+    /**
+     * 首诊时间,YYYY-MM-DD HH:mm:ss
+     */
+    private String consultTime;
+
+    /**
+     * 首诊机构
+     */
+    private String consultOrg;
+
+    /**
+     * 复诊申请时间,YYYY-MM-DD HH:mm:ss
+     */
+    private String furtherConsultApplyTime;
+
+    /**
+     * 复诊开始时间,YYYY-MM-DD HH:mm:ss
+     */
+    private String furtherConsulStartTime;
+
+    /**
+     * 复诊结束时间,YYYY-MM-DD HH:mm:ss
+     */
+    private String furtherConsulEndTime;
+
+    /**
+     * 复诊是否回复,0未回复 1已回复
+     */
+    private Integer furtherConsulIsReply;
+
+    /**
+     * 费别,1自费 2医保
+     */
+    private Integer feeType;
+
+    /**
+     * 复诊诊断,复诊患者在实体医院的诊断名称,如有多条,使用"|"进行分隔
+     */
+    private String furtherConsultDiagnosis;
+
+    /**
+     * 复诊icd诊断编码
+     */
+    private String furtherConsultDiagnosisNo;
+
+    /**
+     * 复诊价格,单位:元
+     */
+    private Double furtherConsultPrice;
+
+    /**
+     * 患者满意度,1-5,1代表非常满意,5代表非常不满意
+     */
+    private Integer patientEvaluate;
+
+    /**
+     * 投诉举报信息,文本信息
+     */
+    private String complainInfo;
+
+    /**
+     * 处理结果信息,文本信息
+     */
+    private String disposeResult;
+
+    /**
+     * 是否进行诊前风险提示,0否 1是
+     */
+    private Integer isRiskWarn;
+
+    /**
+     * 是否确认患者为签约对象,0否 1是
+     */
+    private Integer isPatientSign;
+
+    /**
+     * 是否开具处方,0否 1是
+     */
+    private Integer isPrescription;
+
+    /**
+     * 上传时间,YYYY-MM-DD HH:mm:ss
+     */
+    private String uploadTime;
+
+    /**
+     * 复诊拒绝时间
+     */
+    private String furtherConsultRefuseTime;
+
+    /**
+     * 复诊拒绝类别,1医生主动拒绝 2超时未回复系统自动拒绝
+     */
+    private Integer furtherConsultRefuseType;
+
+    /**
+     * 复诊拒绝、取消原因
+     */
+    private String furtherConsultRefuseReason;
+
+    /**
+     * ca登录值
+     */
+    private String caLoginSign;
+
+    /**
+     * ca登录时间,YYYY-MM-DD HH:mm:ss
+     */
+    private String caLoginTime;
+
+    /**
+     * 城市id(参考地区字段)
+     */
+    private String cityId;
+
+    /**
+     * 年
+     */
+    private String year;
+
+    /**
+     * 是否留痕,1:代表留痕;0代表未留痕
+     */
+    private String isMark;
+}

+ 329 - 0
fs-admin/src/main/java/com/fs/his/param/PrescriptionParam.java

@@ -0,0 +1,329 @@
+package com.fs.his.param;
+
+import lombok.Builder;
+import lombok.Data;
+
+/**
+ * 电子处方信息上传请求参数
+ */
+@Data
+@Builder
+public class PrescriptionParam {
+
+    /**
+     * 接口调用凭证
+     */
+    private String accessToken;
+
+    /**
+     * 第三方厂商标识
+     */
+    private String clientId;
+
+    /**
+     * 唯一标识,用于唯一确定某条记录,避免重复上传,一般传该条数据的主键
+     */
+    private String thirdUniqueid;
+
+    /**
+     * 机构名称
+     */
+    private String orgName;
+
+    /**
+     * 机构编码
+     */
+    private String orgCode;
+
+    /**
+     * 科室名称
+     */
+    private String section;
+
+    /**
+     * 科室编码
+     */
+    private String sectionCode;
+
+    /**
+     * 医师姓名
+     */
+    private String docName;
+
+    /**
+     * 医师执业资格证号
+     */
+    private String docCertificateNum;
+
+    /**
+     * 药师姓名
+     */
+    private String pharmacistName;
+
+    /**
+     * 药师执业机构
+     */
+    private String pharmacistOrg;
+
+    /**
+     * 药师执业资格证号
+     */
+    private String pharmacistCertificateNum;
+
+    /**
+     * 网络复诊编号,对应接口二
+     */
+    private String furtherConsultNo;
+
+    /**
+     * 复诊诊断,复诊患者在实体医院的诊断名称,如有多条,使用"|"进行分隔
+     */
+    private String furtherConsultDiagnosis;
+
+    /**
+     * 患者姓名
+     */
+    private String patientName;
+
+    /**
+     * 患者性别,1男/2女
+     */
+    private String patientSex;
+
+    /**
+     * 患者年龄,示例:19
+     */
+    private Integer patientAge;
+
+    /**
+     * 证件类型,1 身份证  2 护照
+     */
+    private Integer patientIdcardType;
+
+    /**
+     * 患者证件号码
+     */
+    private String patientIdcardNum;
+
+    /**
+     * 监护人姓名,患者年龄小于6岁需填此项
+     */
+    private String guardianName;
+
+    /**
+     * 监护人身份证,患者年龄小于6岁需填此项
+     */
+    private String guardianIdcardNum;
+
+    /**
+     * 陪伴医师姓名,患者年龄小于6岁需填此项
+     */
+    private String accompanyDocName;
+
+    /**
+     * 陪伴医师执业证号码,患者年龄小于6岁需填此项
+     */
+    private String accompanyCertificateNum;
+
+    /**
+     * 费别,1自费 2医保
+     */
+    private Integer feeType;
+
+    /**
+     * 患者简要病史描述,病史摘要
+     */
+    private String medicalHistory;
+
+    /**
+     * 处方日期,格式:YYYY-MM-DD HH:mm:ss
+     */
+    private String recipeTime;
+
+    /**
+     * 处方类型,1中药 2西药 3成药(三医)
+     */
+    private Integer recipeType;
+
+    /**
+     * 审方日期,格式:YYYY-MM-DD HH:mm:ss
+     */
+    private String reviewTime;
+
+    /**
+     * 处方单价,单位:元
+     */
+    private Double recipeUnitPrice;
+
+    /**
+     * 药品名称商品名,以|作为分隔,相同index位置的为一组数据
+     * 示例:"快克|板蓝根颗粒|阿莫西林胶囊"
+     */
+    private String drugName;
+
+    /**
+     * 药品编码
+     */
+    private String drugCode;
+
+    /**
+     * 药品通用名
+     */
+    private String drugCommonName;
+
+    /**
+     * 规格
+     */
+    private String specification;
+
+    /**
+     * 使用频度
+     * 示例:"2次/天|3次/天|3次/天"
+     */
+    private String frequency;
+
+    /**
+     * 用法
+     */
+    private String usage;
+
+    /**
+     * 剂量单位
+     */
+    private String doseUnit;
+
+    /**
+     * 每次剂量
+     */
+    private String doseEachTime;
+
+    /**
+     * 用药天数
+     */
+    private Double medicationDays;
+
+    /**
+     * 帖数
+     */
+    private Double packetNum;
+
+    /**
+     * 数量
+     */
+    private Double quantity;
+
+    /**
+     * 药品包装
+     */
+    private String drugPackage;
+
+    /**
+     * 处方总价,单位:元
+     */
+    private Double recipeAllPrice;
+
+    /**
+     * 是否经过合理用药判断标志,0 否 1 是
+     */
+    private Integer isRationalDrugUse;
+
+    /**
+     * 合理用药审核结果
+     */
+    private String rationalDrugUseReason;
+
+    /**
+     * 配送单位,配送药企、医院药房发药或药店名称
+     */
+    private String deliveryOrg;
+
+    /**
+     * 核销方式,0 医院取药 1物流配送 2药店取药 3自动失效
+     */
+    private Integer cancelAfterVerifyWay;
+
+    /**
+     * 处方核销状态,0未核销 1已核销
+     */
+    private Integer cancelAfterVerifyStatus;
+
+    /**
+     * 处方核销时间,物流配送、医院药房发药或药店自购时间、自动失效时间
+     */
+    private String cancelAfterVerifyTime;
+
+    /**
+     * 配送金额
+     */
+    private Double deliveryPrice;
+
+    /**
+     * 上传时间,格式:YYYY-MM-DD HH:mm:ss
+     */
+    private String uploadTime;
+
+    /**
+     * 医师ca签名订单id
+     */
+    private String docCaSignOrderId;
+
+    /**
+     * 医师ca签名值
+     */
+    private String docCaSign;
+
+    /**
+     * 医师ca签名时间,格式:YYYY-MM-DD HH:mm:ss
+     */
+    private String docCaSignTime;
+
+    /**
+     * 医师ca登录值
+     */
+    private String docCaLoginSign;
+
+    /**
+     * 医师ca登录时间,格式:YYYY-MM-DD HH:mm:ss
+     */
+    private String docCaLoginTime;
+
+    /**
+     * 药师ca签名订单id
+     */
+    private String pharmacistCaSignOrderId;
+
+    /**
+     * 药师ca签名值
+     */
+    private String pharmacistCaSign;
+
+    /**
+     * 药师ca签名时间,格式:YYYY-MM-DD HH:mm:ss
+     */
+    private String pharmacistCaSignTime;
+
+    /**
+     * 药师ca登录值
+     */
+    private String pharmacistCaLoginSign;
+
+    /**
+     * 药师ca登录时间,格式:YYYY-MM-DD HH:mm:ss
+     */
+    private String pharmacistCaLoginTime;
+
+    /**
+     * 医院处方编号
+     */
+    private String recipeNo;
+
+    /**
+     * 所在城市id(参考地区字段)
+     */
+    private String cityId;
+
+    /**
+     * 职称
+     */
+    private String jobTitle;
+}

+ 31 - 4
fs-admin/src/main/java/com/fs/course/task/CompanyBalanceTask.java → fs-admin/src/main/java/com/fs/his/task/CompanyBalanceTask.java

@@ -1,14 +1,16 @@
-package com.fs.course.task;
+package com.fs.his.task;
 
 import com.fs.company.service.ICompanyService;
+import com.fs.company.vo.RedPacketMoneyVO;
 import com.fs.course.service.BalanceRollbackErrorService;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.context.event.ApplicationReadyEvent;
-import org.springframework.context.event.EventListener;
+import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 
+import java.util.List;
+
 /**
- * @description: 公司余额同步定时任务
+ * @description: 公司余额同步定时任务 (红包余额)
  * @author: Xgb
  * @createDate: 2025/10/22
  * @version: 1.0
@@ -59,6 +61,31 @@ public class CompanyBalanceTask {
 
     }
 
+    /**
+     * @Description: 红包余额回滚(回滚的是客户没领取的红包),红包记录表中,两天没领取的记录不会再发送
+     * @Param: 每天0点执行一次
+     * @Return:
+     * @Author xgb
+     * @Date 2025/11/7 9:48
+     */
+    public void rollbackRedPacketMoney() throws Exception {
+        // 这个地方真加的是company money字段 xgb 红包余额独立后这个方法弃用
+        companyService.rollbackRedPacketMoney();
+    }
+
+    /**
+     * @Description: 每天晚上0点定时获取获取公司余额,记录到数据库中
+     * @Param:
+     * @Return:
+     * @Author xgb
+     * @Date 2025/11/4 10:43
+     */
+    public void recordRedPacketBalance() {
+        companyService.recordRedPacketBalance();
+    }
+
+
+
 
 
 }

+ 480 - 0
fs-admin/src/main/java/com/fs/his/task/NetMedicalService.java

@@ -0,0 +1,480 @@
+package com.fs.his.task;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.file.PathUtil;
+import cn.hutool.core.util.IdcardUtil;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import cn.hutool.http.HttpUtil;
+import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.fs.common.utils.file.ImageUtils;
+import com.fs.framework.interceptor.impl.SameUrlDataInterceptor;
+import com.fs.his.domain.FsInquiryOrderDTO;
+import com.fs.his.domain.FsPrescribeDrugDTO;
+import com.fs.his.dto.FsInquiryOrderPatientDTO;
+import com.fs.his.mapper.FsInquiryOrderMapper;
+import com.fs.his.mapper.FsPrescribeDrugMapper;
+import com.fs.his.param.FurtherConsultationParam;
+import com.fs.his.param.PrescriptionParam;
+import com.fs.his.service.IFsPrescribeService;
+import com.qiniu.util.Json;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+
+/**
+ * 互联网医疗服务定时任务
+ * 润天推送参考:每天从中午12点到下午17点,每个小时的整点执行一次
+ */
+@Component("netMedicalService")
+@AllArgsConstructor
+@Slf4j
+public class NetMedicalService {
+
+    private final String prefix = "https://202.61.88.184:19200/";
+    private final String prescriptionPath = "wjw/upload/uploadRecipe";
+    private final String reconsultPath = "wjw/upload/uploadFurtherConsult";
+
+    private final IFsPrescribeService iFsPrescribeService;
+    private final FsPrescribeDrugMapper durgMapper;
+    private final FsInquiryOrderMapper inquiryOrderMapper;
+
+    public void uploadPrescription() {
+        log.info("互联网医疗服务定时任务启动,时间{}", LocalDateTime.now());
+
+        try {
+            // 1.抽取有生成电子处方and上传了首诊记录的数据
+            LocalDate today = LocalDate.now().minusDays(1);
+            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+            String date = today.format(formatter);
+
+            // 此任务准备在凌晨执行,上传前一天的电子处方。
+            List<Map<String, Object>> result = iFsPrescribeService.selectUploadDate("2025-09-21");//TODO:测试修改
+            log.info("查询到 {} 条待上传处方数据", result.size());
+
+            if (result.isEmpty()) {
+                log.info("没有需要上传的处方数据");
+                return;
+            }
+
+            List<PrescriptionParam> paramList = processPrescriptions(result);
+
+            uploadToRemoteService(paramList);
+
+        } catch (Exception e) {
+            log.error("上传处方任务执行失败", e);
+        }
+    }
+
+    /**
+     * 网络诊疗服务数据上传
+     * TODO:请求体太大,可能需要分批请求;
+     */
+    public void uploadReconsultDate() {
+        log.info("开始执行网络诊疗服务数据上传任务");
+
+        // 使用 DateTimeFormatter 替代 SimpleDateFormat
+        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+        LocalDate today = LocalDate.now().minusDays(1);
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        String date = today.format(formatter);
+
+        log.info("查询日期: {}", date);
+        List<FsInquiryOrderDTO> fsInquiryOrderDTOS = inquiryOrderMapper.selectNeedUploadData("2025-01-01");//TODO:测试修改
+        log.info("查询到需要上传的数据条数: {}", fsInquiryOrderDTOS.size());
+
+        ArrayList<FurtherConsultationParam> paramList = new ArrayList<>();
+        int successCount = 0;
+        int skipCount = 0;
+        int errorCount = 0;
+
+        for (int i = 0; i < fsInquiryOrderDTOS.size(); i++) {
+            FsInquiryOrderDTO fsInquiryOrder = fsInquiryOrderDTOS.get(i);
+            String orderSn = fsInquiryOrder.getOrderSn();
+
+            log.debug("正在处理第 {}/{} 条数据, 订单号: {}", i + 1, fsInquiryOrderDTOS.size(), orderSn);
+
+            try {
+                // 检查是否开具处方
+                int isPrescribe = iFsPrescribeService.selectPrescribeByinquiryOrderId(fsInquiryOrder.getOrderId());
+                log.debug("订单 {} 处方检查结果: {}", orderSn, isPrescribe > 0 ? "有处方" : "无处方");
+
+                String imageUrl = fsInquiryOrder.getReportImages();
+                if (imageUrl == null || imageUrl.trim().isEmpty()) {
+                    log.warn("订单 {} 报告图片URL为空,跳过处理", orderSn);
+                    skipCount++;
+                    continue;
+                }
+
+                log.debug("订单 {} 报告图片URL: {}", orderSn, imageUrl);
+
+                Integer supportedImageFormat = getSupportedImageFormat(imageUrl);
+                if (Objects.isNull(supportedImageFormat)) {
+                    log.warn("订单 {} 不支持的文件后缀,跳过处理,图片URL: {}", orderSn, imageUrl);
+                    skipCount++;
+                    continue;
+                }
+                log.debug("订单 {} 图片格式识别成功: {}", orderSn, supportedImageFormat);
+
+                byte[] image = ImageUtils.getImage(imageUrl);
+                if (image == null || image.length == 0) {
+                    log.warn("订单 {} 无法获取图片数据,图片URL: {}", orderSn, imageUrl);
+                    skipCount++;
+                    continue;
+                }
+                log.debug("订单 {} 成功获取图片数据,图片大小: {} bytes", orderSn, image.length);
+
+                String base64Image = Base64.getEncoder().encodeToString(image);
+                log.debug("订单 {} Base64编码完成,编码后长度: {}", orderSn, base64Image.length());
+
+                // 安全处理时间字段
+                String applyTime = formatDateTimeSafely(fsInquiryOrder.getCreateTime(), dateTimeFormatter);
+                String startTime = formatDateTimeSafely(fsInquiryOrder.getStartTime(), dateTimeFormatter);
+                String endTime = formatDateTimeSafely(fsInquiryOrder.getFinishTime(), dateTimeFormatter);
+                String uploadTime = LocalDateTime.now().format(dateTimeFormatter);//TODO:这个完成时间必须传,业务上判断是否需要未完结的复诊数据
+
+                if (applyTime == null || startTime == null || endTime == null) {
+                    log.warn("订单 {} 时间字段存在空值,跳过处理", orderSn);
+                    skipCount++;
+                    continue;
+                }
+
+                FurtherConsultationParam param = FurtherConsultationParam.builder()
+                        .thirdUniqueid(orderSn)
+                        .orgName(fsInquiryOrder.getHospitalName())
+                        .orgCode("组织结构代码")
+                        .channelName("平台名称")
+                        .section(fsInquiryOrder.getDeptName())
+                        .sectionCode(fsInquiryOrder.getDeptCode())
+                        .docName(fsInquiryOrder.getDoctorName())
+                        .certificateNum(fsInquiryOrder.getCertificateCode())
+                        .patientName(fsInquiryOrder.getPatientName())
+                        .patientAge(IdcardUtil.getAgeByIdCard(fsInquiryOrder.getIdCard()))
+                        .patientSex(fsInquiryOrder.getSex())
+                        .patientIdcardType(1)
+                        .patientIdcardNum(fsInquiryOrder.getIdCard())
+                        .furtherConsultNo(orderSn)
+                        .furtherConsulType(1)
+                        .medicalHistory(fsInquiryOrder.getSelfMedHistory())
+                        .furtherConsultApplyTime(applyTime)
+                        .furtherConsulStartTime(startTime)
+                        .furtherConsulEndTime(endTime)
+                        .furtherConsulIsReply(1)
+                        .feeType(1)
+                        .furtherConsultDiagnosis(fsInquiryOrder.getInquiryResult())
+                        .furtherConsultDiagnosisNo("复诊icd诊断编码")
+                        .furtherConsultPrice(fsInquiryOrder.getMoney().toBigInteger().doubleValue())
+                        .patientEvaluate(1)
+                        .complainInfo("")
+                        .disposeResult("")
+                        .isRiskWarn(1)
+                        .isPatientSign(1)
+                        .isPrescription(isPrescribe > 0 ? 1 : 0)
+                        .uploadTime(uploadTime)
+                        .consultDiagnosisType(supportedImageFormat)
+                        .consultOrg("首诊机构")
+                        .consultDiagnosis(base64Image)
+                        .cityId("")
+                        .isMark("1")
+                        .build();
+
+                paramList.add(param);
+                successCount++;
+                log.debug("订单 {} 参数构建完成,已添加到上传列表", orderSn);
+
+            } catch (Exception e) {
+                errorCount++;
+                log.error("处理订单 {} 时发生异常: {}", orderSn, e.getMessage(), e);
+            }
+        }
+
+        log.info("数据处理完成 - 成功: {}条, 跳过: {}条, 异常: {}条", successCount, skipCount, errorCount);
+
+        if (paramList.isEmpty()) {
+            log.info("没有需要上传的数据,任务结束");
+            return;
+        }
+
+        try {
+            String jsonParam = JSON.toJSONString(paramList);
+            log.info("准备上传数据,参数条数: {}", paramList.size());
+//            log.debug("请求参数JSON: {}", jsonParam);
+
+            String urlPath = prefix + reconsultPath;
+            log.info("请求URL: {}", urlPath);
+
+            HttpRequest post = HttpUtil.createPost(urlPath);
+            post.body(jsonParam, "application/json; charset=utf-8");
+
+            log.info("开始发送HTTP请求...");
+            long startTime = System.currentTimeMillis();
+            HttpResponse response = post.execute();
+            long endTime = System.currentTimeMillis();
+
+            log.info("HTTP请求完成,状态码: {}, 耗时: {}ms", response.getStatus(), endTime - startTime);
+
+            if (response.isOk()) {
+                String responseBody = response.body();
+                log.info("上传成功,响应内容: {}", responseBody);
+
+                // 可以在这里添加响应结果解析和业务逻辑判断
+                try {
+                    JSONObject responseJson = JSON.parseObject(responseBody);
+                    if (responseJson != null) {
+                        String code = responseJson.getString("status");
+                        String message = responseJson.getString("message");
+                        log.info("响应解析 - 状态码: {}, 消息: {}", code, message);
+                    }
+                } catch (Exception e) {
+                    log.warn("响应内容解析失败: {}", e.getMessage());
+                }
+            } else {
+                log.error("上传失败,状态码: {}, 响应内容: {}", response.getStatus(), response.body());
+            }
+
+        } catch (Exception e) {
+            log.error("数据上传过程中发生异常: {}", e.getMessage(), e);
+        }
+        log.info("网络诊疗服务数据上传任务执行完毕");
+    }
+
+    private List<PrescriptionParam> processPrescriptions(List<Map<String, Object>> prescriptions) {
+        List<PrescriptionParam> paramList = new ArrayList<>();
+
+        for (Map<String, Object> prescribe : prescriptions) {
+            try {
+                PrescriptionParam param = processSinglePrescription(prescribe);
+                if (param != null) {
+                    paramList.add(param);
+                }
+            } catch (Exception e) {
+                log.error("处理处方失败, prescribe_id: {}", prescribe.get("prescribe_id"), e);
+            }
+        }
+
+        log.info("成功处理 {} 个处方", paramList.size());
+        return paramList;
+    }
+
+    private PrescriptionParam processSinglePrescription(Map<String, Object> prescribe) {
+        Long prescribeId = Convert.toLong(prescribe.get("prescribe_id"));
+        if (prescribeId == null) {
+            log.warn("处方ID为空,跳过处理");
+            return null;
+        }
+
+        // 药品信息查询
+        List<FsPrescribeDrugDTO> drugs = durgMapper.selectDrugList(prescribeId);
+        if (drugs == null || drugs.isEmpty()) {
+            log.warn("处方 {} 没有药品信息,跳过处理", prescribeId);
+            return null;
+        }
+
+        // 计算总量
+        Double quantity = calculateTotalQuantity(drugs);
+        Double days = calculateTotalDays(drugs);
+
+        // 组装药品信息
+        Map<String, String> drugInfoMap = buildDrugInfoMap(drugs);
+
+        // 构建处方参数
+        return buildPrescriptionParam(prescribe, drugInfoMap, quantity, days);
+    }
+
+    private Double calculateTotalQuantity(List<FsPrescribeDrugDTO> drugs) {
+        return drugs.stream().map(FsPrescribeDrugDTO::getDrugNum).filter(Objects::nonNull).mapToDouble(Convert::toDouble).sum();
+    }
+
+    private Double calculateTotalDays(List<FsPrescribeDrugDTO> drugs) {
+        return drugs.stream().map(FsPrescribeDrugDTO::getUsageDays).filter(Objects::nonNull).mapToDouble(Convert::toDouble).sum();
+    }
+
+    private Map<String, String> buildDrugInfoMap(List<FsPrescribeDrugDTO> drugs) {
+        Map<String, String> resultMap = new HashMap<>();
+        resultMap.put("drugName", join(drugs, FsPrescribeDrugDTO::getDrugName));
+        resultMap.put("specification", join(drugs, FsPrescribeDrugDTO::getDrugSpec));
+        resultMap.put("frequency", join(drugs, FsPrescribeDrugDTO::getUsageFrequencyUnit));
+        resultMap.put("useMethod", join(drugs, FsPrescribeDrugDTO::getUsageMethod));
+        resultMap.put("usagePerUseUnit", join(drugs, FsPrescribeDrugDTO::getUsagePerUseUnit));
+        resultMap.put("drugCode", join(drugs, FsPrescribeDrugDTO::getBarCode));
+        resultMap.put("doseEachTime", join(drugs, FsPrescribeDrugDTO::getUsagePerUseCount)); // 修复类型
+        return resultMap;
+    }
+
+    private PrescriptionParam buildPrescriptionParam(Map<String, Object> prescribe, Map<String, String> drugInfoMap, Double quantity, Double days) {
+        return PrescriptionParam.builder()
+                .thirdUniqueid(getString(prescribe, "prescribe_code"))
+                .orgName(getString(prescribe, "hospital_name"))
+                .orgCode("机构编码") // TODO: 不晓得从哪取
+                .section(getString(prescribe, "dept_name"))
+                .sectionCode(getString(prescribe, "dept_code"))
+                .docName(getString(prescribe, "doctor_name"))
+                .docCertificateNum(getString(prescribe, "certificate_code"))
+                .pharmacistName(getString(prescribe, "doctor_drug_name"))
+                .pharmacistCertificateNum(getString(prescribe, "doctor_drug_code"))
+                .patientName(getString(prescribe, "patient_name"))
+                .patientSex(getString(prescribe, "patient_gender"))
+                .patientAge(getInteger(prescribe, "patient_age"))
+                .patientIdcardType(1)
+                .feeType(1)
+                .patientIdcardNum(getString(prescribe, "id_card"))
+                .recipeTime(getString(prescribe, "create_time"))
+                .reviewTime(getString(prescribe, "create_time"))
+                .recipeUnitPrice(getDouble(prescribe, "total_price"))
+                .drugName(drugInfoMap.get("drugName"))
+                .drugCode(drugInfoMap.get("drugCode"))
+                .drugCommonName(drugInfoMap.get("drugName"))
+                .specification(drugInfoMap.get("specification"))
+                .frequency(drugInfoMap.get("frequency"))
+                .usage(drugInfoMap.get("useMethod"))
+                .doseUnit(drugInfoMap.get("usagePerUseUnit"))
+                .doseEachTime(drugInfoMap.get("doseEachTime"))
+                .medicationDays(days)
+                .quantity(quantity)
+                .drugPackage("药品包装") // TODO: 不晓得去哪取
+                .recipeAllPrice(getDouble(prescribe, "total_price"))
+                .uploadTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
+                .recipeNo(getString(prescribe, "prescribe_code"))
+                .cityId("") // TODO: 没有对应字典
+                .build();
+    }
+
+    private void uploadToRemoteService(List<PrescriptionParam> paramList) {
+        if (paramList.isEmpty()) {
+            log.info("没有需要上传的数据");
+            return;
+        }
+
+        try {
+            String url = prefix + prescriptionPath;
+            log.info("开始上传 {} 个处方到: {}", paramList.size(), url);
+
+            HttpRequest post = HttpUtil.createPost(url);
+            String requestBody = JSON.toJSONString(paramList);
+            log.debug("上传数据: {}", requestBody);//很大一坨
+
+            post.body(requestBody);
+            HttpResponse response = post.execute();
+
+//            log.info("上传完成,响应状态: {}", response.getStatus());
+            log.info("响应内容: {}", JSON.toJSONString(response));
+
+        } catch (Exception e) {
+            log.error("上传处方数据到远程服务失败", e);
+            throw new RuntimeException("上传失败", e);
+        }
+    }
+
+    // 工具方法
+    private String getString(Map<String, Object> map, String key) {
+        Object value = map.get(key);
+        return value != null ? value.toString() : "";
+    }
+
+    private Integer getInteger(Map<String, Object> map, String key) {
+        try {
+            Object value = map.get(key);
+            return value != null ? Integer.valueOf(value.toString()) : 0;
+        } catch (NumberFormatException e) {
+            log.warn("字段 {} 转换整数失败, 使用默认值0", key);
+            return 0;
+        }
+    }
+
+    private Double getDouble(Map<String, Object> map, String key) {
+        try {
+            Object value = map.get(key);
+            return value != null ? Double.valueOf(value.toString()) : 0.0;
+        } catch (NumberFormatException e) {
+            log.warn("字段 {} 转换浮点数失败, 使用默认值0.0", key);
+            return 0.0;
+        }
+    }
+
+    private String join(List<FsPrescribeDrugDTO> drugs, Function<FsPrescribeDrugDTO, String> fieldExtractor) {
+        return drugs.stream().map(fieldExtractor).filter(Objects::nonNull).filter(str -> !str.trim().isEmpty()).collect(Collectors.joining("|"));
+    }
+
+    /**
+     * 获取图片格式(只支持jpg、png、bmp)
+     *
+     * @param imagePath 图片路径
+     * @return 图片格式(jpeg, png, bmp),如果不支持则返回null
+     */
+    public static Integer getSupportedImageFormat(String imagePath) {
+        if (imagePath == null || imagePath.trim().isEmpty()) {
+            return null;
+        }
+
+        // 处理URL参数
+        String cleanPath = imagePath.split("[?#]")[0];
+
+        // 获取扩展名
+        String extension = "";
+        int lastDotIndex = cleanPath.lastIndexOf('.');
+        if (lastDotIndex > 0 && lastDotIndex < cleanPath.length() - 1) {
+            extension = cleanPath.substring(lastDotIndex + 1).toLowerCase();
+        }
+
+        // 只支持三种格式
+        switch (extension) {
+            case "jpg":
+            case "jpeg":
+                return 2;
+            case "png":
+                return 3;
+            case "bmp":
+                return 4;
+            default:
+                return null; // 不支持的格式返回null
+        }
+    }
+
+    /**
+     * 安全格式化时间方法,处理各种时间类型
+     */
+    private String formatDateTimeSafely(Object dateTime, DateTimeFormatter formatter) {
+        if (dateTime == null) {
+            log.warn("时间字段为null");
+            return null;
+        }
+
+        try {
+            if (dateTime instanceof java.util.Date) {
+                // 转换 java.util.Date 到 LocalDateTime
+                Instant instant = ((java.util.Date) dateTime).toInstant();
+                return LocalDateTime.ofInstant(instant, ZoneId.systemDefault()).format(formatter);
+            } else if (dateTime instanceof java.sql.Timestamp) {
+                // 转换 java.sql.Timestamp 到 LocalDateTime
+                return ((java.sql.Timestamp) dateTime).toLocalDateTime().format(formatter);
+            } else if (dateTime instanceof LocalDateTime) {
+                // 直接格式化 LocalDateTime
+                return ((LocalDateTime) dateTime).format(formatter);
+            } else if (dateTime instanceof LocalDate) {
+                // 处理 LocalDate,添加时间部分
+                return ((LocalDate) dateTime).atStartOfDay().format(formatter);
+            } else {
+                log.warn("不支持的时间类型: {}", dateTime.getClass().getName());
+                return null;
+            }
+        } catch (Exception e) {
+            log.error("时间格式化失败: {}, 原始值: {}", e.getMessage(), dateTime);
+            return null;
+        }
+    }
+}

+ 77 - 0
fs-admin/src/main/java/com/fs/his/task/Task.java

@@ -6,6 +6,7 @@ import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.service.impl.SmsServiceImpl;
 import com.fs.common.utils.DateUtils;
@@ -69,6 +70,7 @@ import com.fs.sop.service.IQwSopTempVoiceService;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.mapper.SysConfigMapper;
 import com.fs.system.service.ISysConfigService;
+import com.fs.utils.OrderContextHolder;
 import com.google.gson.Gson;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
@@ -217,6 +219,8 @@ public class Task {
 
     @Autowired
     private ThreadPoolTaskExecutor threadPoolTaskExecutor;
+    @Autowired
+    private FsIntegralOrderMapper fsIntegralOrderMapper;
 
     /**
      * sop任务token消耗统计
@@ -532,6 +536,19 @@ public class Task {
         }
     }
 
+    public void payment(){
+        List<FsStorePayment> fsStorePayments = fsStorePaymentService.selectAllPayment();
+        for (FsStorePayment fsStorePayment : fsStorePayments) {
+            try{
+                fsStorePaymentService.updateFsStorePaymentByDecryptForm(fsStorePayment.getPaymentId());
+            }catch (Exception e){
+                logger.error("同步支付失败:"+fsStorePayment.getPaymentId());
+            }
+
+        }
+
+    }
+
     public void addQwUserName() {
         QwCompany qwCompany = new QwCompany();
         List<QwCompany> companyList = qwCompanyService.selectQwCompanyList(qwCompany);
@@ -607,6 +624,7 @@ public class Task {
 
 
     public void redPacketAddMoney() throws Exception {
+        // 这个地方真加的是company money字段 xgb 红包余额独立后这个方法弃用
         List<RedPacketMoneyVO> redPacketMoneyVOS = fsCourseRedPacketLogMapper.selectFsCourseAddRedPacketLogByCompany();
         for (RedPacketMoneyVO redPacketMoneyVO : redPacketMoneyVOS) {
             companyService.addRedPacketCompanyMoney(redPacketMoneyVO.getMoney(), redPacketMoneyVO.getCompanyId());
@@ -674,6 +692,65 @@ public class Task {
         }
     }
 
+    @Autowired
+    private FsIntegralOrderDfMapper integralOrderDfMapper;
+
+
+    /**
+     * 创建了erp的订单,但是等待回调修改物流状态的定时任务
+     * */
+    public void deliveryIntegralOp() {
+        IErpOrderService erpOrderService = getErpService();
+        //查询没有物流字段但是创建过的,如果有则把待发货状态改成待收货
+        List<FsIntegralOrderDf> integralDf = integralOrderDfMapper.selectByIsPush();
+        if (integralDf.isEmpty()) {
+            log.info("⏹️ 没有需要推送的订单明细,流程结束");
+            return;
+        }
+        log.info("📊 查询到 {} 条未查询的订单明细", integralDf.size());
+        //只判断类型,给个对象
+        OrderContextHolder.setIntegralOrder(new FsIntegralOrder());
+        for (FsIntegralOrderDf df : integralDf) {
+            log.info("🔄 开始处理订单明细,订单号: {}, orderId: {}", df.getOrderCode(), df.getOrderId());
+            ErpOrderQueryRequert request = new ErpOrderQueryRequert();
+            request.setCode(df.getOrderCode());
+            erpOrderService.getOrder(request);
+        }
+        OrderContextHolder.clear();
+    }
+    /**
+     * 对待收货的订单,定时去更新物流状态
+     * */
+    public void getIntegralOrderDeliveryStatus() {
+        /*erp物流流程:
+        1.请求顺丰接口添加物流订单
+        2.修改df推送标识为1
+        3.查询订单结果更新order,或者回滚df表*/
+        //目的是查询创建成功erp的订单,应该在第三部之后改动的数据来作为查询条件;即为待收货订单and拥有deliverySn的数据;
+        List<FsIntegralOrder> orders = fsIntegralOrderMapper.selectList(Wrappers.<FsIntegralOrder>lambdaQuery().eq(FsIntegralOrder::getStatus, 2).isNotNull(FsIntegralOrder::getDeliverySn));
+        IErpOrderService erpOrderService = getErpService();
+        List<CompletableFuture<Void>> futures = new ArrayList<>();
+        for (FsIntegralOrder order : orders) {
+            // 创建局部final变量副本
+            final FsIntegralOrder currentOrder = order;
+            FsStoreOrder order1 = new FsStoreOrder();
+            order1.setDeliverySn(currentOrder.getDeliverySn());
+            order1.setOrderCode(currentOrder.getOrderCode());
+
+            // 异步执行,使用局部变量副本
+            CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
+                OrderContextHolder.setIntegralOrder(currentOrder);
+                try {
+                    erpOrderService.getOrderDeliveryStatus(order1);
+                } finally {
+                    OrderContextHolder.clear();
+                }
+            });
+            futures.add(future);
+        }
+        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
+    }
+
     public void deliveryOpScrm()
     {
         IErpOrderService erpOrderService = getErpService();

+ 114 - 4
fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreHealthOrderScrmController.java

@@ -7,14 +7,17 @@ import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.model.LoginUser;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.CloudHostUtils;
+import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.company.service.ICompanyMoneyLogsService;
 import com.fs.course.dto.FsOrderDeliveryNoteDTO;
 import com.fs.erp.service.IErpOrderService;
+import com.fs.framework.web.service.TokenService;
 import com.fs.his.domain.FsStoreOrderDf;
 import com.fs.his.service.IFsStoreOrderDfService;
 import com.fs.his.service.IFsUserService;
@@ -28,6 +31,7 @@ import com.fs.hisStore.vo.FsStoreOrderDeliveryNoteExportVO;
 import com.fs.hisStore.vo.FsStoreOrderExportVO;
 import com.fs.hisStore.vo.FsStoreOrderItemExportVO;
 import com.fs.hisStore.vo.FsStoreOrderVO;
+import com.fs.hisStore.vo.*;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -37,10 +41,8 @@ import org.springframework.web.multipart.MultipartFile;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
+import java.text.SimpleDateFormat;
+import java.util.*;
 
 @RestController
 @RequestMapping("/store/store/storeOrder")
@@ -57,6 +59,8 @@ public class FsStoreHealthOrderScrmController extends BaseController {
 
     @Autowired
     private IFsStoreOrderStatusScrmService orderStatusService;
+    @Autowired
+    private TokenService tokenService;
 
     @Autowired
     IErpOrderService erpOrderService;
@@ -102,6 +106,7 @@ public class FsStoreHealthOrderScrmController extends BaseController {
             dataTable.setMsg("knt");
         }
         if (list != null) {
+            LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
             for (FsStoreOrderVO vo : list) {
                 if(vo.getPhone()!=null){
                     vo.setPhone(vo.getPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
@@ -114,6 +119,17 @@ public class FsStoreHealthOrderScrmController extends BaseController {
                         vo.setErpAccount(df.getLoginAccount());
                     }
                 }
+                //
+                if (loginUser.getPermissions().contains("his:storeAfterSales:finance") || loginUser.getPermissions().contains("*:*:*")) {
+                    vo.setFPrice(vo.getCost().multiply(BigDecimal.valueOf(vo.getTotalNum())));
+                } else {
+                    vo.setPayPostage(BigDecimal.ZERO);
+                    vo.setCost(BigDecimal.ZERO);
+                    vo.setFPrice(BigDecimal.ZERO);
+                    vo.setPayDelivery(BigDecimal.ZERO);
+                    vo.setBarCode("");
+                    vo.setCateName("");
+                }
 
             }
         }
@@ -278,6 +294,7 @@ public class FsStoreHealthOrderScrmController extends BaseController {
         List<FsStoreOrderItemExportVO> list = orderItemService.selectFsStoreOrderItemListExportVO(param);
         //对手机号脱敏
         if (list != null) {
+            LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
             for (FsStoreOrderItemExportVO vo : list) {
                 if (vo.getUserPhone() != null) {
                     String phone = vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{1})", "$1****$2");
@@ -290,6 +307,16 @@ public class FsStoreHealthOrderScrmController extends BaseController {
                     } catch (Exception e) {
                     }
                 }
+                //
+                if (loginUser.getPermissions().contains("his:storeAfterSales:finance") || loginUser.getPermissions().contains("*:*:*")) {
+                    vo.setFPrice(vo.getCost().multiply(BigDecimal.valueOf(vo.getTotalNum())));
+                } else {
+                    vo.setPayPostage(BigDecimal.ZERO);
+                    vo.setCost(BigDecimal.ZERO);
+                    vo.setFPrice(BigDecimal.ZERO);
+                    vo.setBarCode("");
+                    vo.setCateName("");
+                }
             }
         }
         ExcelUtil<FsStoreOrderItemExportVO> util = new ExcelUtil<FsStoreOrderItemExportVO>(FsStoreOrderItemExportVO.class);
@@ -323,6 +350,7 @@ public class FsStoreHealthOrderScrmController extends BaseController {
         List<FsStoreOrderItemExportVO> list = orderItemService.selectFsStoreOrderItemListExportVO(param);
         //对手机号脱敏
         if (list != null) {
+            LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
             for (FsStoreOrderItemExportVO vo : list) {
                 if (!StringUtils.isEmpty(vo.getJsonInfo())) {
                     try {
@@ -331,6 +359,15 @@ public class FsStoreHealthOrderScrmController extends BaseController {
                     } catch (Exception e) {
                     }
                 }
+                if (loginUser.getPermissions().contains("his:storeAfterSales:finance") || loginUser.getPermissions().contains("*:*:*")) {
+                    vo.setFPrice(vo.getCost().multiply(BigDecimal.valueOf(vo.getTotalNum())));
+                } else {
+                    vo.setPayPostage(BigDecimal.ZERO);
+                    vo.setCost(BigDecimal.ZERO);
+                    vo.setFPrice(BigDecimal.ZERO);
+                    vo.setBarCode("");
+                    vo.setCateName("");
+                }
             }
         }
         ExcelUtil<FsStoreOrderItemExportVO> util = new ExcelUtil<FsStoreOrderItemExportVO>(FsStoreOrderItemExportVO.class);
@@ -423,4 +460,77 @@ public class FsStoreHealthOrderScrmController extends BaseController {
         }
         return false;
     }
+
+    //订单发货批量导入
+    @Log(title = "发货同步导入", businessType = BusinessType.IMPORT)
+    @PostMapping("/importDeliveryNoteExpressWithApp")
+    public R importDeliveryNoteExpressWithApp(@RequestParam("file") MultipartFile file,@RequestParam("miniAppId") String miniAppId) {
+        // 1. 检查文件是否为空
+        if (file.isEmpty()) {
+            return R.error("上传的文件不能为空");
+        }
+        // 2. 检查文件大小
+        if (file.getSize() > MAX_FILE_SIZE) {
+            return R.error("文件大小不能超过5MB");
+        }
+        // 3. 检查文件扩展名
+        String fileName = file.getOriginalFilename();
+        if (fileName == null || !isValidExcelFile(fileName)) {
+            return R.error("请上传Excel文件(.xlsx或.xls格式)");
+        }
+
+        ExcelUtil<FsOrderDeliveryNoteDTO> util=new ExcelUtil<>(FsOrderDeliveryNoteDTO.class);
+        try {
+            List<FsOrderDeliveryNoteDTO> dtoList = util.importExcel(file.getInputStream());
+            if(!dtoList.isEmpty()){
+                if(dtoList.size() > 200){
+                    R.error("操作失败,导入数据不能大于200条!");
+                }
+                return fsStoreOrderService.importDeliveryNoteExpress(dtoList,miniAppId);
+            }else {
+                R.error("操作失败,导入数据不能小于1条!");
+            }
+        }catch (Exception e){
+            e.getStackTrace();
+        }
+        return R.ok();
+    }
+
+
+//    /**
+//     * 发货单导出接口
+//     * **/
+//    @PreAuthorize("@ss.hasPermi('store:storeOrder:healthExportShippingOrder')")
+//    @GetMapping("/healthExportShippingOrder")
+//    public AjaxResult healthExportShippingOrder(FsStoreOrderParam param){
+//        if ("".equals(param.getBeginTime()) && "".equals(param.getEndTime())){
+//            param.setBeginTime(null);
+//            param.setEndTime(null);
+//        }
+//        if(fsStoreOrderService.isEntityNull(param)){
+//            param = new FsStoreOrderParam();
+//        }
+//        if(!StringUtils.isEmpty(param.getCreateTimeRange())){
+//            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+//        }
+//        if(!StringUtils.isEmpty(param.getPayTimeRange())){
+//            param.setPayTimeList(param.getPayTimeRange().split("--"));
+//        }
+//        if(!StringUtils.isEmpty(param.getDeliverySendTimeRange())){
+//            param.setDeliverySendTimeList(param.getDeliverySendTimeRange().split("--"));
+//        }
+//        if(!StringUtils.isEmpty(param.getDeliveryImportTimeRange())){
+//            param.setDeliveryImportTimeList(param.getDeliveryImportTimeRange().split("--"));
+//        }
+//        param.setIsHealth("1");
+//        List<FsStoreOrderDeliveryNoteExportVO> storeOrderDeliveryNoteExportVOList=fsStoreOrderService.getDeliveryNote(param);
+//        ExcelUtil<FsStoreOrderDeliveryNoteExportVO> util = new ExcelUtil<>(FsStoreOrderDeliveryNoteExportVO.class);
+//        //通过商品ID获取关键字
+//        String firstKeyword = storeOrderDeliveryNoteExportVOList.stream()
+//                .map(FsStoreOrderDeliveryNoteExportVO::getKeyword)
+//                .findFirst()
+//                .orElse("无订单");
+//        String fileName="077AC"+firstKeyword+new SimpleDateFormat("yyyyMMdd").format(new Date());
+//        return util.exportExcel(storeOrderDeliveryNoteExportVOList, fileName);
+//    }
 }

+ 35 - 0
fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreOrderScrmController.java

@@ -199,6 +199,7 @@ public class FsStoreOrderScrmController extends BaseController {
             dataTable.setMsg("knt");
         }
         if (list != null) {
+            LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
             for (FsStoreOrderVO vo : list) {
                 if(vo.getPhone()!=null){
                     vo.setPhone(vo.getPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
@@ -211,6 +212,17 @@ public class FsStoreOrderScrmController extends BaseController {
                         vo.setErpAccount(df.getLoginAccount());
                     }
                 }
+                //
+                if (loginUser.getPermissions().contains("his:storeAfterSales:finance") || loginUser.getPermissions().contains("*:*:*")) {
+                    vo.setFPrice(vo.getCost().multiply(BigDecimal.valueOf(vo.getTotalNum())));
+                } else {
+                    vo.setPayPostage(BigDecimal.ZERO);
+                    vo.setCost(BigDecimal.ZERO);
+                    vo.setFPrice(BigDecimal.ZERO);
+                    vo.setPayDelivery(BigDecimal.ZERO);
+                    vo.setBarCode("");
+                    vo.setCateName("");
+                }
             }
         }
         FsStoreOrderListAndStatisticsVo vo = new FsStoreOrderListAndStatisticsVo();
@@ -440,6 +452,8 @@ public class FsStoreOrderScrmController extends BaseController {
         List<FsStoreOrderItemExportVO> list = orderItemService.selectFsStoreOrderItemListExportVO(param);
         //对手机号脱敏
         if (list != null) {
+            LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+
             for (FsStoreOrderItemExportVO vo : list) {
                 if (vo.getUserPhone() != null) {
                     String phone = vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{1})", "$1****$2");
@@ -455,6 +469,16 @@ public class FsStoreOrderScrmController extends BaseController {
                     } catch (Exception e) {
                     }
                 }
+                //
+                if (loginUser.getPermissions().contains("his:storeAfterSales:finance") || loginUser.getPermissions().contains("*:*:*")) {
+                    vo.setFPrice(vo.getCost().multiply(BigDecimal.valueOf(vo.getTotalNum())));
+                } else {
+                    vo.setPayPostage(BigDecimal.ZERO);
+                    vo.setCost(BigDecimal.ZERO);
+                    vo.setFPrice(BigDecimal.ZERO);
+                    vo.setBarCode("");
+                    vo.setCateName("");
+                }
             }
         }
         ExcelUtil<FsStoreOrderItemExportVO> util = new ExcelUtil<FsStoreOrderItemExportVO>(FsStoreOrderItemExportVO.class);
@@ -491,6 +515,7 @@ public class FsStoreOrderScrmController extends BaseController {
         List<FsStoreOrderItemExportVO> list = orderItemService.selectFsStoreOrderItemListExportVO(param);
         //对手机号脱敏
         if (list != null) {
+            LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
             for (FsStoreOrderItemExportVO vo : list) {
                 if (!StringUtils.isEmpty(vo.getJsonInfo())) {
                     try {
@@ -499,6 +524,16 @@ public class FsStoreOrderScrmController extends BaseController {
                     } catch (Exception e) {
                     }
                 }
+                //
+                if (loginUser.getPermissions().contains("his:storeAfterSales:finance") || loginUser.getPermissions().contains("*:*:*")) {
+                    vo.setFPrice(vo.getCost().multiply(BigDecimal.valueOf(vo.getTotalNum())));
+                } else {
+                    vo.setPayPostage(BigDecimal.ZERO);
+                    vo.setCost(BigDecimal.ZERO);
+                    vo.setFPrice(BigDecimal.ZERO);
+                    vo.setBarCode("");
+                    vo.setCateName("");
+                }
             }
         }
         ExcelUtil<FsStoreOrderItemExportVO> util = new ExcelUtil<FsStoreOrderItemExportVO>(FsStoreOrderItemExportVO.class);

+ 13 - 2
fs-admin/src/main/java/com/fs/hisStore/controller/FsStorePaymentScrmController.java

@@ -11,6 +11,7 @@ import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.CloudHostUtils;
 import com.fs.common.utils.ParseUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.poi.ExcelUtil;
@@ -251,7 +252,15 @@ public class FsStorePaymentScrmController extends BaseController
         }
 
         if(payment.getPayTypeCode().equals("weixin")){
-            String json = configService.selectConfigByKey("store.pay");
+            String json;
+//            if (CloudHostUtils.hasCloudHostName("康年堂")){
+                json = configService.selectConfigByKey("his.pay");
+//            } else {
+//                json = configService.selectConfigByKey("store.pay");
+//            }
+            if (StringUtils.isBlank(json)) {
+                return R.error("缺少支付相关配置");
+            }
             FsPayConfigScrm fsPayConfig = JSON.parseObject(json, FsPayConfigScrm.class);
             if (payment.getPayMode()!=null&&payment.getPayMode().equals("hf")){
                 String huifuId="";
@@ -276,6 +285,7 @@ public class FsStorePaymentScrmController extends BaseController
                 Map<String, Object> extendInfoMap = new HashMap<>();
                 extendInfoMap.put("org_party_order_id", payment.getBankSerialNo());
                 request.setExtendInfo(extendInfoMap);
+                logger.info("请求参数:"+request);
                 HuiFuRefundResult refund = huiFuService.refund(request);
                 logger.info("退款:"+refund);
                 if((refund.getResp_code().equals("00000000")||refund.getResp_code().equals("00000100"))&&(refund.getTrans_stat().equals("S")||refund.getTrans_stat().equals("P"))){
@@ -293,7 +303,8 @@ public class FsStorePaymentScrmController extends BaseController
                     return R.error(refund.getResp_desc());
                 }
 
-            }else if (payment.getPayMode()!=null&&payment.getPayMode().equals("wx")){
+            }
+            else if (payment.getPayMode()!=null&&payment.getPayMode().equals("wx")){
 
             }
 

+ 12 - 0
fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreProductScrmController.java

@@ -113,6 +113,18 @@ public class FsStoreProductScrmController extends BaseController
     }
 
 
+    /**
+     * 导出商品列表
+     */
+    @PreAuthorize("@ss.hasPermi('store:storeProduct:copy')")
+    @Log(title = "商品管理", businessType = BusinessType.INSERT, isStoreLog = true,logParam = {"商品","复制商品信息"})
+    @GetMapping("/copyStoreProduct")
+    public R copyStoreProduct(@RequestParam Long productId)
+    {
+        return fsStoreProductService.copyStoreProduct(productId);
+    }
+
+
     @Log(title = "商品管理", businessType = BusinessType.IMPORT,isStoreLog = true,logParam = {"商品","商品导入"})
     @PreAuthorize("@ss.hasPermi('store:storeProduct:import')")
     @PostMapping("/importData")

+ 57 - 19
fs-admin/src/main/java/com/fs/hisStore/task/ErpTask.java

@@ -7,6 +7,8 @@ import com.fs.erp.mapper.FsErpFinishPushMapper;
 import com.fs.erp.service.IErpOrderService;
 import com.fs.hisStore.domain.FsStoreOrderScrm;
 import com.fs.hisStore.service.IFsStoreOrderScrmService;
+import com.fs.live.domain.LiveOrder;
+import com.fs.live.service.ILiveOrderService;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.exception.ExceptionUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -27,6 +29,9 @@ public class ErpTask {
     @Autowired
     private IFsStoreOrderScrmService fsStoreOrderService;
 
+    @Autowired
+    private ILiveOrderService liveOrderService;
+
 
     /**
      * 推送完成订单到ERP
@@ -35,34 +40,67 @@ public class ErpTask {
         List<FsErpFinishPush> fsErpFinishPushes = fsErpFinishPushMapper.queryPenddingOrder();
         for (FsErpFinishPush fsErpFinishPush : fsErpFinishPushes) {
             FsStoreOrderScrm fsStoreOrder = fsStoreOrderService.selectFsStoreOrderById(fsErpFinishPush.getOrderId());
+            if (fsStoreOrder != null) {
+                try {
 
-            try {
-
-                ErpOrder erpOrder = fsStoreOrderService.getErpOrder(fsStoreOrder);
+                    ErpOrder erpOrder = fsStoreOrderService.getErpOrder(fsStoreOrder);
 
-                ErpOrderResponse erpOrderResponse = erpOrderService.finishOrder(erpOrder);
+                    ErpOrderResponse erpOrderResponse = erpOrderService.finishOrder(erpOrder);
 
-                fsErpFinishPush.setParams(erpOrderResponse.getRequestRawData());
-                fsErpFinishPush.setResult(erpOrderResponse.getResponseRawData());
-                fsErpFinishPush.setUpdateTime(new Date());
+                    fsErpFinishPush.setParams(erpOrderResponse.getRequestRawData());
+                    fsErpFinishPush.setResult(erpOrderResponse.getResponseRawData());
+                    fsErpFinishPush.setUpdateTime(new Date());
 
-                if(erpOrderResponse.getSuccess()!= null && erpOrderResponse.getSuccess()){
-                    fsErpFinishPush.setTaskStatus(1);
+                    if(erpOrderResponse.getSuccess()!= null && erpOrderResponse.getSuccess()){
+                        fsErpFinishPush.setTaskStatus(1);
 
-                    log.error("推送完成订单到ERP成功! 订单号: {}",fsErpFinishPush.getOrderId());
-                } else {
-                    fsErpFinishPush.setTaskStatus(2);
+                        log.error("推送完成订单到ERP成功! 订单号: {}",fsErpFinishPush.getOrderId());
+                    } else {
+                        fsErpFinishPush.setTaskStatus(2);
+                        fsErpFinishPush.setRetryCount(fsErpFinishPush.getRetryCount()+1);
+                        log.error("推送完成订单到ERP失败! 订单号: {}",fsErpFinishPush.getOrderId());
+                    }
+                } catch (Throwable e) {
                     fsErpFinishPush.setRetryCount(fsErpFinishPush.getRetryCount()+1);
-                    log.error("推送完成订单到ERP失败! 订单号: {}",fsErpFinishPush.getOrderId());
+                    fsErpFinishPush.setErrorMessage(ExceptionUtils.getStackTrace(e));
+                    fsErpFinishPush.setTaskStatus(2);
+                    log.error("订单推送失败!原因: {}", ExceptionUtils.getStackTrace(e),e);
+                    continue;
+                }
+            } else {
+                LiveOrder liveOrder = liveOrderService.selectLiveOrderByOrderId(String.valueOf(fsErpFinishPush.getOrderId()));
+                if (liveOrder != null) {
+                    try {
+                        ErpOrder erpOrder = liveOrderService.getErpOrder(liveOrder);
+
+                        ErpOrderResponse erpOrderResponse = erpOrderService.finishOrder(erpOrder);
+
+                        fsErpFinishPush.setParams(erpOrderResponse.getRequestRawData());
+                        fsErpFinishPush.setResult(erpOrderResponse.getResponseRawData());
+                        fsErpFinishPush.setUpdateTime(new Date());
+
+                        if (erpOrderResponse.getSuccess() != null && erpOrderResponse.getSuccess()) {
+                            fsErpFinishPush.setTaskStatus(1);
+
+                            log.error("推送完成订单到ERP成功! 订单号: {}", fsErpFinishPush.getOrderId());
+                        } else {
+                            fsErpFinishPush.setTaskStatus(2);
+                            fsErpFinishPush.setRetryCount(fsErpFinishPush.getRetryCount() + 1);
+                            log.error("推送完成订单到ERP失败! 订单号: {}", fsErpFinishPush.getOrderId());
+                        }
+                    } catch (Throwable e) {
+                        fsErpFinishPush.setRetryCount(fsErpFinishPush.getRetryCount() + 1);
+                        fsErpFinishPush.setErrorMessage(ExceptionUtils.getStackTrace(e));
+                        fsErpFinishPush.setTaskStatus(2);
+                        log.error("订单推送失败!原因: {}", ExceptionUtils.getStackTrace(e), e);
+                        continue;
+                    }
+                } else {
+                    log.error("订单不存在! 订单号: {}",fsErpFinishPush.getOrderId());
+                    continue;
                 }
-            } catch (Throwable e) {
-                fsErpFinishPush.setRetryCount(fsErpFinishPush.getRetryCount()+1);
-                fsErpFinishPush.setErrorMessage(ExceptionUtils.getStackTrace(e));
-                fsErpFinishPush.setTaskStatus(2);
-                log.error("订单推送失败!原因: {}", ExceptionUtils.getStackTrace(e),e);
             }
 
-
             fsErpFinishPushMapper.updateById(fsErpFinishPush);
         }
 

+ 29 - 0
fs-admin/src/main/java/com/fs/hisStore/task/ExpressTask.java

@@ -0,0 +1,29 @@
+package com.fs.hisStore.task;
+
+
+import com.fs.hisStore.service.IFsStoreOrderScrmService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * 物流信息定时任务
+ */
+@Slf4j
+@Component("expressTask")
+public class ExpressTask {
+
+    @Autowired
+    private IFsStoreOrderScrmService fsStoreOrderScrmService;
+
+    public void syncExpressToWx(){
+        fsStoreOrderScrmService.syncExpressToWx();
+    }
+
+
+    //定时任务刷新订单结算状态
+    public void refreshOrderSettlementStatus(){
+        fsStoreOrderScrmService.refreshOrderSettlementStatus();
+    }
+
+}

+ 517 - 0
fs-admin/src/main/java/com/fs/hisStore/task/LiveTask.java

@@ -0,0 +1,517 @@
+package com.fs.hisStore.task;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
+import com.fs.common.core.redis.RedisCache;
+import com.fs.company.service.ICompanyService;
+import com.fs.company.vo.RedPacketMoneyVO;
+import com.fs.course.mapper.FsCourseRedPacketLogMapper;
+import com.fs.erp.domain.ErpDeliverys;
+import com.fs.erp.domain.ErpOrderQuery;
+import com.fs.erp.dto.ErpOrderQueryRequert;
+import com.fs.erp.dto.ErpOrderQueryResponse;
+import com.fs.erp.service.IErpOrderService;
+import com.fs.his.config.FsSysConfig;
+import com.fs.his.dto.ExpressInfoDTO;
+import com.fs.his.service.IFsExpressService;
+import com.fs.his.service.IFsUserService;
+import com.fs.his.utils.ConfigUtil;
+import com.fs.hisStore.domain.FsStoreProductAttrValueScrm;
+import com.fs.hisStore.dto.DateComparisonConfigDTO;
+import com.fs.hisStore.enums.ShipperCodeEnum;
+import com.fs.hisStore.mapper.FsStoreProductAttrValueScrmMapper;
+import com.fs.hisStore.param.FsStoreOrderAddTuiMoneyParam;
+import com.fs.hisStore.service.IFsStoreProductScrmService;
+import com.fs.live.domain.LiveAfterSales;
+import com.fs.live.domain.LiveOrder;
+import com.fs.live.domain.LiveOrderItem;
+import com.fs.live.domain.LiveOrderPayment;
+import com.fs.live.mapper.LiveOrderItemMapper;
+import com.fs.live.mapper.LiveOrderMapper;
+import com.fs.live.mapper.LiveOrderPaymentMapper;
+import com.fs.live.param.LiveAfterSalesAudit1Param;
+import com.fs.live.param.LiveAfterSalesParam;
+import com.fs.live.param.LiveAfterSalesProductParam;
+import com.fs.live.service.*;
+import com.fs.pay.pay.dto.OrderQueryDTO;
+import com.fs.pay.service.IPayService;
+import com.fs.store.config.StoreConfig;
+import com.fs.system.service.ISysConfigService;
+import com.fs.ybPay.domain.OrderResult;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import java.text.ParseException;
+import java.time.LocalTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+
+import static com.fs.hisStore.constants.StoreConstants.DELIVERY;
+
+/**
+ * 定时任务调度测试
+ *
+ * @author fs
+ */
+@Slf4j
+@Component("liveTask")
+public class LiveTask {
+    @Autowired
+    private RedisTemplate redisTemplate;
+    @Autowired
+    private RedisCache redisCache;
+    @Autowired
+    private ILiveOrderService liveOrderService;
+
+    @Autowired
+    private ILiveCouponService liveCouponService;
+
+    @Autowired
+    private ILiveCouponIssueService liveCouponIssueService;
+    @Autowired
+    private IFsStoreProductScrmService fsStoreProductScrmService;
+
+    @Autowired
+    private ILiveAfterSalesService liveAfterSalesService;
+
+    @Autowired
+    private ILiveOrderItemService liveOrderItemService;
+
+    @Autowired
+    private ILiveOrderPaymentService liveOrderPaymentService;
+
+    @Autowired
+    private IFsUserService userService;
+
+    @Autowired
+    private ICompanyService companyService;
+
+    @Autowired
+    @Qualifier("erpOrderServiceImpl")
+    private IErpOrderService gyOrderService;
+
+    @Autowired
+    @Qualifier("wdtErpOrderServiceImpl")
+    private IErpOrderService wdtOrderService;
+
+    @Autowired
+    @Qualifier("hzOMSErpOrderServiceImpl")
+    private IErpOrderService hzOMSOrderService;
+
+    @Autowired
+    @Qualifier("dfOrderServiceImpl")
+    private IErpOrderService dfOrderService;
+
+    @Autowired
+    @Qualifier("JSTErpOrderServiceImpl")
+    private IErpOrderService jSTOrderService;
+
+    @Autowired
+    @Qualifier("k9OrderScrmServiceImpl")
+    private IErpOrderService k9OrderService;
+
+    @Autowired
+    private ConfigUtil configUtil;
+
+    @Autowired
+    IErpOrderService erpOrderService;
+
+    @Autowired
+    private LiveOrderMapper liveOrderMapper;
+
+    @Autowired
+    private LiveOrderItemMapper liveOrderItemMapper;
+
+    @Autowired
+    private LiveOrderPaymentMapper liveOrderPaymentMapper;
+
+    @Autowired
+    private IPayService ybPayService;
+
+    @Autowired
+    private ISysConfigService configService;
+
+    @Autowired
+    private IFsExpressService expressService;
+
+    @Autowired
+    private FsCourseRedPacketLogMapper fsCourseRedPacketLogMapper;
+
+    @Autowired
+    private JdbcTemplate jdbcTemplate;
+
+    public void PushErp() throws ParseException {
+//        List<Long> ids = liveOrderMapper.selectOrderIdByNoErp();
+//        for (Long id : ids) {
+//            liveOrderService.createOmsOrder(id);
+//        }
+    }
+
+    public void redPacketSubMoney() throws Exception {
+        List<RedPacketMoneyVO> redPacketMoneyVOS = fsCourseRedPacketLogMapper.selectFsCourseRedPacketLogByCompany();
+        for (RedPacketMoneyVO redPacketMoneyVO : redPacketMoneyVOS) {
+            companyService.subtractCompanyMoney(redPacketMoneyVO.getMoney(), redPacketMoneyVO.getCompanyId());
+        }
+    }
+
+    public void redPacketAddMoney() throws Exception {
+        List<RedPacketMoneyVO> redPacketMoneyVOS = fsCourseRedPacketLogMapper.selectFsCourseAddRedPacketLogByCompany();
+        for (RedPacketMoneyVO redPacketMoneyVO : redPacketMoneyVOS) {
+            companyService.addRedPacketCompanyMoney(redPacketMoneyVO.getMoney(), redPacketMoneyVO.getCompanyId());
+        }
+    }
+
+
+    //定时任务刷新微信订单结算状态
+    public void refreshOrderSettlementStatus(){
+        liveOrderService.refreshOrderSettlementStatus();
+    }
+
+
+
+    //每5分钟执行一次
+    public void deliveryOp() {
+        List<LiveOrder> list = liveOrderService.selectUpdateExpress();
+        if(list == null || list.isEmpty()) return;
+        if (list.size() > 100) {
+            list = list.subList(0, 100);
+        }
+        for (LiveOrder order : list) {
+            ErpOrderQueryRequert request = new ErpOrderQueryRequert();
+            request.setCode(order.getExtendOrderId());
+            IErpOrderService erpOrderService = getErpOrderService();
+            ErpOrderQueryResponse response = erpOrderService.getLiveOrder(request);
+            if (erpOrderService != dfOrderService) {
+                if (response.getOrders() != null && !response.getOrders().isEmpty()) {
+                    for (ErpOrderQuery orderQuery : response.getOrders()) {
+                        if (orderQuery.getDeliverys() != null && orderQuery.getDeliverys().size() > 0) {
+                            for (ErpDeliverys delivery : orderQuery.getDeliverys()) {
+                                if (delivery.getDelivery() && StringUtils.isNotEmpty(delivery.getMail_no())) {
+                                    //更新商订单状态 删除REDIS
+                                    liveOrderService.deliveryOrder(order.getOrderCode(), delivery.getMail_no(), delivery.getExpress_code(), delivery.getExpress_name());
+                                    redisCache.deleteObject(DELIVERY + ":" + order.getExtendOrderId());
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+    }
+
+    public void couponOp() {
+        // 直播优惠券过期处理,如果有对应方法则调用
+        // liveCouponService.updateFsCouponByExpire();
+    }
+
+    //退款自动处理 24小时未审核自动审核通过 每小时执行一次
+    public void refundOp() {
+        //获取所有退款申请
+        List<LiveAfterSales> list = liveAfterSalesService.selectLiveAfterSalesByDoAudit();
+        if (list != null) {
+            for (LiveAfterSales afterSales : list) {
+                //仅退款
+                if (afterSales.getRefundType().equals(0)) {
+                    LiveAfterSalesAudit1Param audit1Param = new LiveAfterSalesAudit1Param();
+                    audit1Param.setSalesId(afterSales.getId());
+                    audit1Param.setOperator("平台");
+                    liveAfterSalesService.audit1(audit1Param);
+                }
+            }
+        }
+    }
+
+    //每天执行一次
+    public void userMoneyOp() {
+        // 直播订单完成7天后给用户返现,如果有对应方法则调用
+        // List<LiveOrder> list = liveOrderService.selectLiveOrderListByFinish7Day();
+        // if (list != null) {
+        //     for (LiveOrder order : list) {
+        //         userService.addMoney(order);
+        //     }
+        // }
+    }
+
+    //每30秒执行一次
+    public void orderItemSyncOp() {
+//         同步订单项JSON,如果有对应方法则调用
+         List<LiveOrder> list = liveOrderService.selectLiveOrderItemJson();
+         for (LiveOrder storeOrder : list) {
+             LiveOrderItem parmOrderItem = new LiveOrderItem();
+             parmOrderItem.setOrderId(storeOrder.getOrderId());
+             List<LiveOrderItem> listOrderItem = liveOrderItemService.selectLiveOrderItemList(parmOrderItem);
+             if (listOrderItem.size() > 0) {
+                 String itemJson = JSONUtil.toJsonStr(listOrderItem);
+                 storeOrder.setItemJson(itemJson);
+                 liveOrderMapper.updateLiveOrderItemJson(storeOrder);
+             }
+         }
+    }
+
+    public void returnDeliveryId() {
+        IErpOrderService erpOrderService = getErpOrderService();
+        // 获取ERP订单号列表,如果有对应方法则调用
+        // List<String> list = liveOrderMapper.selectErpCode();
+        // for (String s : list) {
+        //     ErpOrderQueryRequert request = new ErpOrderQueryRequert();
+        //     request.setCode(s);
+        //     ErpOrderQueryResponse response = erpOrderService.getOrder(request);
+        //     if (response.getOrders() != null && response.getOrders().size() > 0) {
+        //         for (ErpOrderQuery orderQuery : response.getOrders()) {
+        //             if (orderQuery.getDeliverys() != null && orderQuery.getDeliverys().size() > 0) {
+        //                 for (ErpDeliverys delivery : orderQuery.getDeliverys()) {
+        //                     if (delivery.getDelivery() && StringUtils.isNotEmpty(delivery.getMail_no())) {
+        //                         LiveOrder order = new LiveOrder();
+        //                         order.setExtendOrderId(s);
+        //                         order.setDeliverySn(delivery.getMail_no());
+        //                         order.setStatus(2);
+        //                         liveOrderMapper.updateDelivery(order);
+        //                     }
+        //                 }
+        //             }
+        //         }
+        //     }
+        // }
+    }
+
+    public void changeStatus() {
+//         获取需要更新物流状态的订单ID列表,如果有对应方法则调用
+//         List<Long> list = liveOrderMapper.selectOrderId();
+//         for (Long orderId : list) {
+//             LiveOrder order = liveOrderMapper.selectLiveOrderByOrderId(String.valueOf(orderId));
+//             String lastFourNumber = "";
+//             if (order.getDeliverySn() != null && order.getDeliverySn().equals(ShipperCodeEnum.SF.getValue())) {
+//                 lastFourNumber = order.getUserPhone();
+//                 if (lastFourNumber != null && lastFourNumber.length() == 11) {
+//                     lastFourNumber = StrUtil.sub(lastFourNumber, lastFourNumber.length(), -4);
+//                 }
+//             }
+//             ExpressInfoDTO dto = expressService.getExpressInfo(order.getOrderCode(), order.getDeliverySn(), order.getDeliverySn(), lastFourNumber);
+//             LiveOrder map = new LiveOrder();
+//             map.setDeliveryStatus(Integer.parseInt(dto.getState()));
+//             map.setOrderId(orderId);
+//             map.setDeliveryType(dto.getStateEx());
+//             liveOrderMapper.updateLiveOrder(map);
+//         }
+    }
+
+    public void subCompanyMoney() {
+        // 获取需要扣减公司金额的支付ID列表,如果有对应方法则调用
+        // List<Long> list = liveOrderPaymentMapper.selectPaymentIds();
+        // for (Long paymentId : list) {
+        //     LiveOrderPayment payment = liveOrderPaymentService.selectLiveOrderPaymentByPaymentId(paymentId);
+        //     if (payment.getCompanyId() != null && payment.getCompanyId() > 0) {
+        //         companyService.subCompanyPaymentMoney(payment);
+        //     }
+        // }
+    }
+
+    public void updateOrderItem() throws ParseException {
+//        List<Long> ids = liveOrderService.selectOrderIdByNoErp();
+//        for (Long id : ids) {
+//            liveOrderService.createOmsOrder(id);
+//        }
+    }
+
+    //每天执行一次
+    public void syncExpress() {
+        List<Long> ids = liveOrderService.selectSyncExpressIds();
+        for (Long id : ids) {
+            liveOrderService.syncExpress(id);
+        }
+    }
+
+    public void returnPayStatus() {
+        // 获取需要查询支付状态的支付ID列表,如果有对应方法则调用
+        // List<String> ids = liveOrderPaymentMapper.selectPayStatusIds();
+        // for (String id : ids) {
+        //     OrderQueryDTO o = new OrderQueryDTO();
+        //     o.setUpOrderId(id);
+        //     OrderResult orderResult = ybPayService.getOrder(o);
+        //     if ("0".equals(orderResult.getState())) {
+        //         String[] order = orderResult.getLowOrderId().split("-");
+        //         if (orderResult.getStatus().equals("100")) {
+        //             switch (order[0]) {
+        //                 case "live":
+        //                     liveOrderService.payConfirm(1, null, order[1], o.getUpOrderId(), orderResult.getBankTrxId(), orderResult.getBankOrderId());
+        //                 case "live_remain":
+        //                     liveOrderService.payConfirm(1, null, order[1], o.getUpOrderId(), orderResult.getBankTrxId(), orderResult.getBankOrderId());
+        //                 case "payment":
+        //                     liveOrderPaymentService.payConfirm(order[1], o.getUpOrderId(), orderResult.getBankTrxId(), orderResult.getBankOrderId());
+        //             }
+        //         }
+        //     }
+        // }
+    }
+
+    public void AddTuiMoney() {
+        // 获取需要添加推荐金额的订单ID列表,如果有对应方法则调用
+        // List<Long> ids = liveOrderMapper.selectAddTuiMoney();
+        // for (Long id : ids) {
+        //     FsStoreOrderAddTuiMoneyParam param = new FsStoreOrderAddTuiMoneyParam();
+        //     param.setOrderId(id);
+        //     liveOrderService.addTuiMoney(param);
+        // }
+    }
+
+    public void selectPayMoneyLessOne() {
+        // 获取支付金额小于1的订单列表,如果有对应方法则调用
+        // List<LiveOrder> list = liveOrderMapper.selectPayMoneyLessOne();
+        // for (LiveOrder order : list) {
+        //     LiveAfterSalesParam param = new LiveAfterSalesParam();
+        //     param.setOrderCode(order.getOrderCode());
+        //     param.setServiceType(0);
+        //     param.setRefundAmount(order.getPayMoney());
+        //     param.setReasons("超时未处理,自动申请退款");
+        //     List<LiveAfterSalesProductParam> productParams = new ArrayList<>();
+        //     List<LiveOrderItem> items = liveOrderItemMapper.selectLiveOrderItemByOrderId(order.getOrderId());
+        //     for (LiveOrderItem item : items) {
+        //         LiveAfterSalesProductParam param1 = new LiveAfterSalesProductParam();
+        //         param1.setProductId(item.getProductId());
+        //         param1.setNum(item.getNum());
+        //         productParams.add(param1);
+        //     }
+        //     param.setProductList(productParams);
+        //     liveAfterSalesService.applyForAfterSales(order.getUserId(), param);
+        // }
+    }
+
+    public void deleteCustomer() {
+        // 删除客户逻辑
+    }
+
+    private IErpOrderService getErpOrderService() {
+        //判断是否开启erp
+        IErpOrderService erpOrderService = null;
+        FsSysConfig erpConfig = configUtil.getSysConfig();
+        Integer erpOpen = erpConfig.getErpOpen();
+        if (erpOpen != null && erpOpen == 1) {
+            //判断erp类型
+            Integer erpType = erpConfig.getErpType();
+            if (erpType != null) {
+                if (erpType == 1) {
+                    //管易
+                    erpOrderService = gyOrderService;
+                } else if (erpType == 2) {
+                    //旺店通
+                    erpOrderService = wdtOrderService;
+                } else if (erpType == 3) {
+                    //代服
+                    erpOrderService = hzOMSOrderService;
+                } else if (erpType == 4) {
+                    //瀚智
+                    erpOrderService = dfOrderService;
+                } else if (erpType == 5) {
+                    erpOrderService = jSTOrderService;
+                } else if (erpType == 6) {
+                    erpOrderService = k9OrderService;
+                }
+            }
+        }
+        return erpOrderService;
+    }
+
+    /**
+     * 提醒证件到期任务
+     */
+    public void remindCertValidation() {
+        log.info("提醒店铺证件到期任务执行... 当前时间: {}", LocalTime.now());
+
+        // 从配置表获取需要比较的表和字段
+        List<DateComparisonConfigDTO> tablesToCheck = jdbcTemplate.query(
+                "SELECT table_name, date_column,in_advance,user_column,phone_column,remind_words,platform,cert_type" +
+                        " FROM date_comparison_config", (rs, rowNum) -> {
+                    return DateComparisonConfigDTO.builder()
+                            .tableName(rs.getString("table_name"))//表名
+                            .certType(rs.getString("cert_type"))//证件类型
+                            .dateColumn(rs.getString("date_column"))//日期字段
+                            .userColumn(rs.getString("user_column"))//用户字段
+                            .remindWords(rs.getString("remindWords"))//提醒内容
+                            .phoneColumn(rs.getString("phone_column"))//提醒手机
+                            .inAdvance(rs.getInt("inAdvance"))//提前天数
+                            .platform(rs.getString("platform")).build();//平台
+                });
+
+        tablesToCheck.forEach(dto -> {
+            //获取证件失效日期字段小于当前时间加提前天数的用户和电话号码
+            String sql = String.format("SELECT %s , %s " +
+                            "FROM %s " +
+                            "WHERE %s >= DATE_SUB(CURDATE(), INTERVAL %d DAY)",
+                    dto.getUserColumn(),
+                    dto.getPhoneColumn(),
+                    dto.getTableName(),
+                    dto.getDateColumn(),
+                    dto.getInAdvance()
+            );
+            List<Map<String, Object>> users = jdbcTemplate.queryForList(sql);
+            users.forEach(user -> {
+                String userName = (String) user.get(dto.getUserColumn());
+                String phone = (String) user.get(dto.getPhoneColumn());
+                String remindWords = String.format("【%s平台提示】尊敬的%s用户,店铺%s证件即将到期,请及时处理!",
+                        dto.getPlatform(),
+                        userName,
+                        dto.getCertType());
+                // 使用phone发送remindWords短信
+                // TODO 发送通知
+            });
+        });
+    }
+
+    /**
+     * 禁用店铺
+     */
+    public void disable() {
+        log.info("禁用店铺任务执行... 当前时间: {}", LocalTime.now());
+        // 从配置表获取需要禁用的表和字段
+        List<DateComparisonConfigDTO> toDisable = jdbcTemplate.query(
+                "SELECT table_name, date_column,invalid_expression,status_column" +
+                        " FROM date_comparison_config " +
+                        " WHERE is_do_invalid = '1'", (rs, rowNum) -> DateComparisonConfigDTO.builder()
+                        .tableName(rs.getString("table_name"))//表名
+                        .dateColumn(rs.getString("date_column"))//日期字段
+                        .invalidExpression(rs.getString("invalid_expression"))//失效表达式
+                        .statusColumn(rs.getString("status_column"))//状态字段
+                        .build());
+
+        toDisable.forEach(dto -> {
+            //更新证件失效日期字段小于当前时间的数据
+            String sql = String.format("UPDATE %s " +
+                            "SET %s = %s " +
+                            "WHERE %s < CURDATE()",
+                    dto.getTableName(),
+                    dto.getStatusColumn(),
+                    dto.getInvalidExpression(),
+                    dto.getDateColumn());
+            jdbcTemplate.update(sql);
+        });
+    }
+
+    public void getOrderDeliveryStatus() {
+        IErpOrderService erpOrderService = getErpOrderService();
+        List<LiveOrder> orders = null;
+        if (erpOrderService != null && erpOrderService == dfOrderService) {
+            // 获取已发货订单列表,如果有对应方法则调用
+             orders = liveOrderMapper.selectShippedOrder();
+             if (orders != null && !orders.isEmpty()) {
+                 List<CompletableFuture<Void>> futures = new ArrayList<>();
+                 for (LiveOrder order : orders) {
+                     CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
+                         erpOrderService.getOrderLiveDeliveryStatus(order);
+                     });
+                     futures.add(future);
+                 }
+                 CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
+             }
+        }
+    }
+}

+ 7 - 1
fs-admin/src/main/java/com/fs/hisStore/task/MallStoreTask.java

@@ -231,6 +231,12 @@ public class MallStoreTask
     }
 
 
+    //定时任务刷新微信订单结算状态
+    public void refreshOrderSettlementStatus(){
+        fsStoreOrderService.refreshOrderSettlementStatus();
+    }
+
+
     public void storeProdUpdateCostPrice()
     {
         String json=configService.selectConfigByKey("store.config");
@@ -380,7 +386,7 @@ public class MallStoreTask
         for (Long orderId : list){
             FsStoreOrderScrm order = fsStoreOrderMapper.selectFsStoreOrderById(orderId);
             String lastFourNumber = "";
-            if (order.getDeliverySn().equals(ShipperCodeEnum.SF.getValue())) {
+            if (order.getDeliverySn().equals(ShipperCodeEnum.SF.getValue())  || order.getDeliverySn().equals(ShipperCodeEnum.ZTO.getValue())) {
                 lastFourNumber = order.getUserPhone();
                 if (lastFourNumber.length() == 11) {
                     lastFourNumber = StrUtil.sub(lastFourNumber, lastFourNumber.length(), -4);

+ 46 - 0
fs-admin/src/main/java/com/fs/live/aspectj/LiveControllerAspect.java

@@ -0,0 +1,46 @@
+package com.fs.live.aspectj;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.fs.live.domain.Live;
+import com.fs.live.service.ILiveService;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.annotation.Aspect;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Aspect
+@Component
+public class LiveControllerAspect {
+
+    private static final Logger logger = LoggerFactory.getLogger(LiveControllerAspect.class);
+
+    @Autowired
+    private ILiveService liveService;
+
+    @AfterReturning(pointcut = "execution(* com.fs.live.controller.LiveController.add(..)) || " +
+            "execution(* com.fs.live.controller.LiveController.finishLive(..)) || " +
+            "execution(* com.fs.live.controller.LiveController.handleDeleteSelected(..)) || " +
+            "execution(* com.fs.live.controller.LiveController.handleShelfOrUn(..)) || " +
+            "execution(* com.fs.live.controller.LiveController.edit(..)) || " +
+            "execution(* com.fs.live.controller.LiveController.copyLive(..)) || " +
+            "execution(* com.fs.live.controller.LiveController.startLive(..)) || " +
+            "execution(* com.fs.live.controller.LiveController.updateLiveIsAudit(..)) || " +
+            "execution(* com.fs.live.controller.LiveController.remove(..)) " ,
+            returning = "result")
+    public void afterLiveControllerMethodExecution(JoinPoint joinPoint,Object result) {
+        String methodName = joinPoint.getSignature().getName();
+        Object[] args = joinPoint.getArgs();
+        liveService.asyncToCache();
+        if (args[0] instanceof Live) {
+            Live live = (Live) args[0];
+            if (ObjectUtil.isNotEmpty(live) && ObjectUtil.isNotEmpty(live.getLiveId())){
+                liveService.asyncToCacheLiveDetail(live.getLiveId());
+            }
+        }
+        logger.info("后台直播间列表变更");
+
+    }
+}

+ 193 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveAfterSalesController.java

@@ -0,0 +1,193 @@
+package com.fs.live.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ParseUtils;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.framework.web.service.TokenService;
+import com.fs.his.domain.FsUser;
+import com.fs.his.service.IFsUserService;
+import com.fs.live.domain.LiveAfterSales;
+import com.fs.live.domain.LiveAfterSalesItem;
+import com.fs.live.domain.LiveAfterSalesLogs;
+import com.fs.live.domain.LiveOrder;
+import com.fs.live.param.LiveAfterSalesAudit1Param;
+import com.fs.live.param.LiveAfterSalesAudit2Param;
+import com.fs.live.param.LiveAfterSalesCancelParam;
+import com.fs.live.param.LiveAfterSalesRefundParam;
+import com.fs.live.service.ILiveAfterSalesItemService;
+import com.fs.live.service.ILiveAfterSalesLogsService;
+import com.fs.live.service.ILiveAfterSalesService;
+import com.fs.live.service.ILiveOrderService;
+import com.fs.live.vo.LiveAfterSalesVo;
+import com.github.pagehelper.PageHelper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.text.ParseException;
+import java.util.List;
+
+/**
+ * 售后记录Controller
+ *
+ * @author fs
+ * @date 2025-07-08
+ */
+@RestController
+@RequestMapping("/live/liveAfterSales")
+public class LiveAfterSalesController extends BaseController
+{
+    @Autowired
+    private ILiveAfterSalesService liveAfterSalesService;
+
+    @Autowired
+    private TokenService tokenService;
+    @Autowired
+    private ILiveAfterSalesItemService liveAfterSalesItemService;
+    @Autowired
+    private ILiveAfterSalesLogsService liveAfterSalesLogsService;
+    @Autowired
+    private IFsUserService userService;
+    @Autowired
+    private ILiveOrderService orderService;
+
+    /**
+     * 获取售后记录详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveAfteraSales:query')")
+    @GetMapping(value = "/{id}")
+    public R getInfo(@PathVariable("id") Long id)
+    {
+        LiveAfterSales liveAfterSales = liveAfterSalesService.selectLiveAfterSalesById(id);
+        if(liveAfterSales==null) return R.error("售后记录不存在");
+        List<LiveAfterSalesItem> list = liveAfterSalesItemService.selectLiveAfterSalesItemByAfterId(id);
+        List<LiveAfterSalesLogs> logList = liveAfterSalesLogsService.selectLiveAfterSalesLogsByAfterId(id);
+        FsUser user=userService.selectFsUserById(liveAfterSales.getUserId());
+        user.setPhone(ParseUtils.parsePhone(user.getPhone()));
+        LiveOrder liveOrder = orderService.selectLiveOrderByOrderId(String.valueOf(liveAfterSales.getOrderId()));
+        return R.ok().put("afterSales",liveAfterSales).put("items",list).put("logs",logList).put("user",user).put("order",liveOrder);
+
+    }
+
+    /**
+     * 查询售后记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveAfteraSales:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveAfterSalesVo liveAfterSales)
+    {
+        startPage();
+        List<LiveAfterSalesVo> list = liveAfterSalesService.selectLiveAfterSalesVoList(liveAfterSales);
+        for (LiveAfterSalesVo liveAfterSalesVo : list) {
+            liveAfterSalesVo.setUserPhone(ParseUtils.parsePhone(liveAfterSalesVo.getUserPhone()));
+        }
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出售后记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveAfteraSales:export')")
+    @Log(title = "售后记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveAfterSalesVo liveAfterSales)
+    {
+        PageHelper.clearPage();
+        PageHelper.startPage(1, 10000, "");
+        List<LiveAfterSalesVo> list = liveAfterSalesService.selectLiveAfterSalesVoList(liveAfterSales);
+        for (LiveAfterSalesVo liveAfterSalesVo : list) {
+            liveAfterSalesVo.setUserPhone(liveAfterSalesVo.getUserPhone() == null ? "" : liveAfterSalesVo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+            liveAfterSalesVo.setPhoneNumber(liveAfterSalesVo.getPhoneNumber() == null ? "" : liveAfterSalesVo.getPhoneNumber().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+        }
+        ExcelUtil<LiveAfterSalesVo> util = new ExcelUtil<LiveAfterSalesVo>(LiveAfterSalesVo.class);
+        return util.exportExcel(list, "销售直播退款订单数据");
+    }
+
+
+    /**
+     * 新增售后记录
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveAfteraSales:add')")
+    @Log(title = "售后记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LiveAfterSales liveAfterSales)
+    {
+        return toAjax(liveAfterSalesService.insertLiveAfterSales(liveAfterSales));
+    }
+
+    /**
+     * 修改售后记录
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveAfteraSales:edit')")
+    @Log(title = "售后记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody LiveAfterSales liveAfterSales)
+    {
+        return toAjax(liveAfterSalesService.updateLiveAfterSales(liveAfterSales));
+    }
+
+    /**
+     * 删除售后记录
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveAfteraSales:remove')")
+    @Log(title = "售后记录", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(liveAfterSalesService.deleteLiveAfterSalesByIds(ids));
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSales:audit1')")
+    @PostMapping("/audit1")
+    //平台审核
+    public R audit1(@RequestBody LiveAfterSalesAudit1Param param)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setOperator(loginUser.getUser().getNickName());
+        return liveAfterSalesService.audit1(param);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSales:audit2')")
+    @PostMapping("/audit2")
+    //仓库审核
+    public R audit2(@RequestBody LiveAfterSalesAudit2Param param)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setOperator(loginUser.getUser().getNickName());
+        return liveAfterSalesService.audit2(param);
+    }
+    //财务审核
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSales:refund')")
+    @PostMapping("/refund")
+    public R refund(@RequestBody LiveAfterSalesRefundParam param)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setOperator(loginUser.getUser().getNickName());
+        return liveAfterSalesService.refundMoney(param);
+    }
+    //平台撤销
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSales:cancel')")
+    @PostMapping("/cancel")
+    public R cancel(@RequestBody LiveAfterSalesCancelParam param) throws ParseException {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setOperator(loginUser.getUser().getNickName());
+        return liveAfterSalesService.cancel(param);
+    }
+
+    @PreAuthorize("@ss.hasPermi('store:storeAfterSales:refund')")
+    @PostMapping("/handleImmediatelyRefund")
+    public R handleImmediatelyRefund(@RequestBody LiveAfterSalesRefundParam param)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setOperator(loginUser.getUser().getNickName());
+        return liveAfterSalesService.handleImmediatelyRefund(param.getOrderId());
+    }
+
+}

+ 97 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveAfterSalesItemController.java

@@ -0,0 +1,97 @@
+package com.fs.live.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.live.domain.LiveAfterSalesItem;
+import com.fs.live.service.ILiveAfterSalesItemService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 售后子Controller
+ *
+ * @author fs
+ * @date 2025-07-08
+ */
+@RestController
+@RequestMapping("/live/liveAfterSalesItem")
+public class LiveAfterSalesItemController extends BaseController
+{
+    @Autowired
+    private ILiveAfterSalesItemService liveAfterSalesItemService;
+
+    /**
+     * 查询售后子列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveAfterSalesItem:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveAfterSalesItem liveAfterSalesItem)
+    {
+        startPage();
+        List<LiveAfterSalesItem> list = liveAfterSalesItemService.selectLiveAfterSalesItemList(liveAfterSalesItem);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出售后子列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveAfterSalesItem:export')")
+    @Log(title = "售后子", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveAfterSalesItem liveAfterSalesItem)
+    {
+        List<LiveAfterSalesItem> list = liveAfterSalesItemService.selectLiveAfterSalesItemList(liveAfterSalesItem);
+        ExcelUtil<LiveAfterSalesItem> util = new ExcelUtil<LiveAfterSalesItem>(LiveAfterSalesItem.class);
+        return util.exportExcel(list, "售后子数据");
+    }
+
+    /**
+     * 获取售后子详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveAfterSalesItem:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(liveAfterSalesItemService.selectLiveAfterSalesItemById(id));
+    }
+
+    /**
+     * 新增售后子
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveAfterSalesItem:add')")
+    @Log(title = "售后子", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LiveAfterSalesItem liveAfterSalesItem)
+    {
+        return toAjax(liveAfterSalesItemService.insertLiveAfterSalesItem(liveAfterSalesItem));
+    }
+
+    /**
+     * 修改售后子
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveAfterSalesItem:edit')")
+    @Log(title = "售后子", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody LiveAfterSalesItem liveAfterSalesItem)
+    {
+        return toAjax(liveAfterSalesItemService.updateLiveAfterSalesItem(liveAfterSalesItem));
+    }
+
+    /**
+     * 删除售后子
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveAfterSalesItem:remove')")
+    @Log(title = "售后子", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(liveAfterSalesItemService.deleteLiveAfterSalesItemByIds(ids));
+    }
+}

+ 97 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveAfterSalesLogsController.java

@@ -0,0 +1,97 @@
+package com.fs.live.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.live.domain.LiveAfterSalesLogs;
+import com.fs.live.service.ILiveAfterSalesLogsService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 售后订单操作Controller
+ *
+ * @author fs
+ * @date 2025-07-08
+ */
+@RestController
+@RequestMapping("/live/liveAfterSalesLogs")
+public class LiveAfterSalesLogsController extends BaseController
+{
+    @Autowired
+    private ILiveAfterSalesLogsService liveAfterSalesLogsService;
+
+    /**
+     * 查询售后订单操作列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveAfterSalesLogs:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveAfterSalesLogs liveAfterSalesLogs)
+    {
+        startPage();
+        List<LiveAfterSalesLogs> list = liveAfterSalesLogsService.selectLiveAfterSalesLogsList(liveAfterSalesLogs);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出售后订单操作列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveAfterSalesLogs:export')")
+    @Log(title = "售后订单操作", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveAfterSalesLogs liveAfterSalesLogs)
+    {
+        List<LiveAfterSalesLogs> list = liveAfterSalesLogsService.selectLiveAfterSalesLogsList(liveAfterSalesLogs);
+        ExcelUtil<LiveAfterSalesLogs> util = new ExcelUtil<LiveAfterSalesLogs>(LiveAfterSalesLogs.class);
+        return util.exportExcel(list, "售后订单操作数据");
+    }
+
+    /**
+     * 获取售后订单操作详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveAfterSalesLogs:query')")
+    @GetMapping(value = "/{logsId}")
+    public AjaxResult getInfo(@PathVariable("logsId") Long logsId)
+    {
+        return AjaxResult.success(liveAfterSalesLogsService.selectLiveAfterSalesLogsByLogsId(logsId));
+    }
+
+    /**
+     * 新增售后订单操作
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveAfterSalesLogs:add')")
+    @Log(title = "售后订单操作", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LiveAfterSalesLogs liveAfterSalesLogs)
+    {
+        return toAjax(liveAfterSalesLogsService.insertLiveAfterSalesLogs(liveAfterSalesLogs));
+    }
+
+    /**
+     * 修改售后订单操作
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveAfterSalesLogs:edit')")
+    @Log(title = "售后订单操作", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody LiveAfterSalesLogs liveAfterSalesLogs)
+    {
+        return toAjax(liveAfterSalesLogsService.updateLiveAfterSalesLogs(liveAfterSalesLogs));
+    }
+
+    /**
+     * 删除售后订单操作
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveAfterSalesLogs:remove')")
+    @Log(title = "售后订单操作", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{logsIds}")
+    public AjaxResult remove(@PathVariable Long[] logsIds)
+    {
+        return toAjax(liveAfterSalesLogsService.deleteLiveAfterSalesLogsByLogsIds(logsIds));
+    }
+}

+ 8 - 14
fs-admin/src/main/java/com/fs/live/controller/LiveAnchorController.java

@@ -1,28 +1,22 @@
 package com.fs.live.controller;
 
-import java.util.List;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.live.domain.LiveAnchor;
 import com.fs.live.service.ILiveAnchorService;
-import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.common.core.page.TableDataInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
 
 /**
  * 主播Controller
- * 
+ *
  * @author fs
  * @date 2025-01-17
  */

+ 227 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveAutoTaskController.java

@@ -0,0 +1,227 @@
+package com.fs.live.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.live.domain.Live;
+import com.fs.live.domain.LiveAutoTask;
+import com.fs.live.mapper.LiveMapper;
+import com.fs.live.param.LiveAutoTaskExportParam;
+import com.fs.live.param.LiveAutoTaskImportParam;
+import com.fs.live.service.ILiveAutoTaskService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 直播间自动化任务配置Controller
+ *
+ * @author fs
+ * @date 2025-08-29
+ */
+@RestController
+@RequestMapping("/live/task")
+public class LiveAutoTaskController extends BaseController
+{
+    @Autowired
+    private ILiveAutoTaskService liveAutoTaskService;
+    @Autowired
+    private LiveMapper liveMapper;
+
+    /**
+     * 查询直播间自动化任务配置列表
+     */
+//    @PreAuthorize("@ss.hasPermi('live:task:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveAutoTask liveAutoTask)
+    {
+        startPage();
+        List<LiveAutoTask> list = liveAutoTaskService.selectLiveAutoTaskList(liveAutoTask);
+        return getDataTable(list);
+    }
+    /**
+     * 查询直播间自动化任务配置列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:task:list')")
+    @GetMapping("/listBarrage")
+    public TableDataInfo listBarrage(LiveAutoTask liveAutoTask)
+    {
+        startPage();
+        List<LiveAutoTask> list = liveAutoTaskService.selectLiveAutoTaskBarrageList(liveAutoTask);
+        return getDataTable(list);
+    }
+
+//    @PreAuthorize("@ss.hasPermi('live:task:list')")
+    @GetMapping("/consoleList")
+    public TableDataInfo consoleList(LiveAutoTask liveAutoTask)
+    {
+        startPage();
+        // 大屏查询后面20条数据
+        List<LiveAutoTask> list = liveAutoTaskService.consoleList(liveAutoTask.getLiveId());
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出直播间自动化任务配置列表
+     */
+//    @PreAuthorize("@ss.hasPermi('shop:task:export')")
+    @Log(title = "直播间自动化任务配置", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveAutoTask liveAutoTask)
+    {
+        List<LiveAutoTask> list = liveAutoTaskService.selectLiveAutoTaskList(liveAutoTask);
+        ExcelUtil<LiveAutoTask> util = new ExcelUtil<LiveAutoTask>(LiveAutoTask.class);
+        return util.exportExcel(list, "直播间自动化任务配置数据");
+    }
+
+    /**
+     * 获取直播间自动化任务配置详细信息
+     */
+//    @PreAuthorize("@ss.hasPermi('live:task:list')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(liveAutoTaskService.selectLiveAutoTaskById(id));
+    }
+
+    /**
+     * 新增直播间自动化任务配置
+     */
+//    @PreAuthorize("@ss.hasPermi('shop:task:add')")
+    @Log(title = "直播间自动化任务配置", businessType = BusinessType.INSERT)
+    @PostMapping
+    public R add(@RequestBody LiveAutoTask liveAutoTask)
+    {
+        return liveAutoTaskService.insertLiveAutoTask(liveAutoTask);
+    }
+
+    /**
+     * 修改直播间自动化任务配置
+     */
+//    @PreAuthorize("@ss.hasPermi('shop:task:edit')")
+    @Log(title = "直播间自动化任务配置", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public R edit(@RequestBody LiveAutoTask liveAutoTask)
+    {
+        return liveAutoTaskService.updateLiveAutoTask(liveAutoTask);
+    }
+
+    /**
+     * 删除直播间自动化任务配置
+     */
+//    @PreAuthorize("@ss.hasPermi('shop:task:remove')")
+    @Log(title = "直播间自动化任务配置", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(liveAutoTaskService.deleteLiveAutoTaskByIds(ids));
+    }
+
+    /**
+     * 导出直播间自动化任务配置列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:task:export')")
+    @Log(title = "直播间自动化任务配置", businessType = BusinessType.EXPORT)
+    @GetMapping("/exportData")
+    public AjaxResult exportData(LiveAutoTask liveAutoTask)
+    {
+        List<LiveAutoTask> list = liveAutoTaskService.selectLiveAutoTaskBarrageList(liveAutoTask);
+        ExcelUtil<LiveAutoTaskExportParam> util = new ExcelUtil<LiveAutoTaskExportParam>(LiveAutoTaskExportParam.class);
+        ArrayList<LiveAutoTaskExportParam> barrageList = new ArrayList<>();
+        for (LiveAutoTask autoTask : list) {
+            LiveAutoTaskExportParam liveAutoTaskImportParam = new LiveAutoTaskExportParam();
+            liveAutoTaskImportParam.setTaskName(autoTask.getTaskName());
+            liveAutoTaskImportParam.setContent(autoTask.getContent());
+            liveAutoTaskImportParam.setRegisterDate(autoTask.getTriggerValue());
+            barrageList.add(liveAutoTaskImportParam);
+        }
+
+        return util.exportExcel(barrageList, "直播间弹幕脚本数据");
+    }
+
+    @GetMapping("/importTemplate")
+    public AjaxResult importTemplate()
+    {
+        ExcelUtil<LiveAutoTaskImportParam> util = new ExcelUtil<>(LiveAutoTaskImportParam.class);
+        return util.importTemplateExcel("导入模板");
+    }
+
+    @PreAuthorize("@ss.hasPermi('live:task:export')")
+    @PostMapping("/importData")
+    public AjaxResult importLineData(@RequestParam("liveId") String liveId, MultipartFile file) throws Exception
+    {
+        ExcelUtil<LiveAutoTaskImportParam> util = new ExcelUtil<LiveAutoTaskImportParam>(LiveAutoTaskImportParam.class);
+        List<LiveAutoTaskImportParam> list = util.importExcel(file.getInputStream());
+        if(list.size()>12000){
+            return new AjaxResult(500,"导入数据超出范围,最大12000条");
+        }
+        LiveAutoTask liveAutoTask;
+        Date nowDate = DateUtils.getNowDate();
+        Live live = liveMapper.selectLiveByLiveId(Long.parseLong(liveId));
+        for (LiveAutoTaskImportParam liveAutoTaskImportParam : list) {
+            if(StringUtils.isEmpty(liveAutoTaskImportParam.getTaskName()) || StringUtils.isEmpty(liveAutoTaskImportParam.getRegisterDate()) || StringUtils.isEmpty(liveAutoTaskImportParam.getContent())) continue;
+            liveAutoTask = new LiveAutoTask();
+            liveAutoTask.setLiveId(Long.parseLong(liveId));
+            liveAutoTask.setTaskName(liveAutoTaskImportParam.getTaskName());
+            liveAutoTask.setTaskType(3L);
+            liveAutoTask.setTriggerType(2L);
+            liveAutoTask.setTriggerValue(formatTime(liveAutoTaskImportParam.getRegisterDate()));
+            liveAutoTask.setContent(liveAutoTaskImportParam.getContent());
+            liveAutoTask.setAbsValue(getTriggerValue(liveAutoTask.getTriggerValue(),live.getStartTime()));
+            liveAutoTask.setCreateTime(nowDate);
+            liveAutoTask.setUpdateTime(nowDate);
+            liveAutoTask.setStatus(1L);
+            liveAutoTask.setFinishStatus(0L);
+            liveAutoTaskService.directInsertLiveAutoTask(liveAutoTask);
+        }
+        return AjaxResult.success();
+    }
+
+    public static Date formatTime(String duration) {
+        String[] parts = duration.split(":");
+        if (parts.length != 3) {
+            throw new IllegalArgumentException("时间格式不正确,应为 hh:mm:ss");
+        }
+        int hours = Integer.parseInt(parts[0]);
+        int minutes = Integer.parseInt(parts[1]);
+        int seconds = Integer.parseInt(parts[2]);
+
+        // 获取当前日期的Calendar实例
+        Calendar calendar = Calendar.getInstance();
+        // 设置时分秒
+        calendar.set(Calendar.HOUR_OF_DAY, hours); // 24小时制
+        calendar.set(Calendar.MINUTE, minutes);
+        calendar.set(Calendar.SECOND, seconds);
+        calendar.set(Calendar.MILLISECOND, 0); // 毫秒设为0
+
+        return calendar.getTime();
+    }
+
+    private Date getTriggerValue(Date triggerValue, LocalDateTime liveStartTime) {
+        LocalDateTime triggerDateTime = LocalDateTime.ofInstant(
+                triggerValue.toInstant(),
+                ZoneId.systemDefault()
+        );
+        LocalTime triggerTime = triggerDateTime.toLocalTime();
+        LocalDateTime combinedTime = liveStartTime
+                .plusHours(triggerTime.getHour())
+                .plusMinutes(triggerTime.getMinute())
+                .plusSeconds(triggerTime.getSecond());
+        return Date.from(combinedTime.atZone(ZoneId.systemDefault()).toInstant());
+    }
+}

+ 98 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveCartController.java

@@ -0,0 +1,98 @@
+package com.fs.live.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.live.domain.LiveCart;
+import com.fs.live.service.ILiveCartService;
+import com.fs.live.vo.LiveCartVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 购物车Controller
+ *
+ * @author fs
+ * @date 2025-07-08
+ */
+@RestController
+@RequestMapping("/live/liveCart")
+public class LiveCartController extends BaseController
+{
+    @Autowired
+    private ILiveCartService liveCartService;
+
+    /**
+     * 查询购物车列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveCart:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveCart liveCart)
+    {
+        startPage();
+        List<LiveCartVo> list = liveCartService.selectLiveCartListVo(liveCart);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出购物车列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveCart:export')")
+    @Log(title = "购物车", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveCart liveCart)
+    {
+        List<LiveCart> list = liveCartService.selectLiveCartList(liveCart);
+        ExcelUtil<LiveCart> util = new ExcelUtil<LiveCart>(LiveCart.class);
+        return util.exportExcel(list, "购物车数据");
+    }
+
+    /**
+     * 获取购物车详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveCart:query')")
+    @GetMapping(value = "/{cardId}")
+    public AjaxResult getInfo(@PathVariable("cardId") Long cardId)
+    {
+        return AjaxResult.success(liveCartService.selectLiveCartByCartId(cardId));
+    }
+
+    /**
+     * 新增购物车
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveCart:add')")
+    @Log(title = "购物车", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LiveCart liveCart)
+    {
+        return toAjax(liveCartService.insertLiveCart(liveCart));
+    }
+
+    /**
+     * 修改购物车
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveCart:edit')")
+    @Log(title = "购物车", businessType = BusinessType.UPDATE)
+    @PostMapping("/update")
+    public AjaxResult edit(@RequestBody LiveCart liveCart)
+    {
+        return toAjax(liveCartService.updateLiveCart(liveCart));
+    }
+
+    /**
+     * 删除购物车
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveCart:remove')")
+    @Log(title = "购物车", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{cardIds}")
+    public AjaxResult remove(@PathVariable Long[] cardIds)
+    {
+        return toAjax(liveCartService.deleteLiveCartByCartIds(cardIds));
+    }
+}

+ 98 - 29
fs-admin/src/main/java/com/fs/live/controller/LiveController.java

@@ -1,45 +1,44 @@
 package com.fs.live.controller;
 
-import java.util.List;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.task.LiveTask;
+import com.fs.hisStore.task.MallStoreTask;
 import com.fs.live.domain.Live;
 import com.fs.live.service.ILiveService;
-import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.common.core.page.TableDataInfo;
+import com.fs.live.vo.LiveListVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.text.ParseException;
+import java.util.List;
+import java.util.Map;
 
 /**
  * 直播Controller
- * 
+ *
  * @author fs
  * @date 2025-01-17
  */
 @RestController
 @RequestMapping("/live/live")
-public class LiveController extends BaseController
-{
+public class LiveController extends BaseController {
     @Autowired
     private ILiveService liveService;
 
+
     /**
      * 查询直播列表
      */
     @PreAuthorize("@ss.hasPermi('live:live:list')")
     @GetMapping("/list")
-    public TableDataInfo list(Live live)
-    {
+    public TableDataInfo list(Live live) {
         startPage();
         List<Live> list = liveService.selectLiveList(live);
         return getDataTable(list);
@@ -51,20 +50,19 @@ public class LiveController extends BaseController
     @PreAuthorize("@ss.hasPermi('live:live:export')")
     @Log(title = "直播", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
-    public AjaxResult export(Live live)
-    {
+    public AjaxResult export(Live live) {
         List<Live> list = liveService.selectLiveList(live);
         ExcelUtil<Live> util = new ExcelUtil<Live>(Live.class);
         return util.exportExcel(list, "直播数据");
     }
 
+
     /**
      * 获取直播详细信息
      */
     @PreAuthorize("@ss.hasPermi('live:live:query')")
     @GetMapping(value = "/{liveId}")
-    public AjaxResult getInfo(@PathVariable("liveId") Long liveId)
-    {
+    public AjaxResult getInfo(@PathVariable("liveId") Long liveId) {
         return AjaxResult.success(liveService.selectLiveByLiveId(liveId));
     }
 
@@ -74,8 +72,7 @@ public class LiveController extends BaseController
     @PreAuthorize("@ss.hasPermi('live:live:add')")
     @Log(title = "直播", businessType = BusinessType.INSERT)
     @PostMapping
-    public AjaxResult add(@RequestBody Live live)
-    {
+    public AjaxResult add(@RequestBody Live live) {
         return toAjax(liveService.insertLive(live));
     }
 
@@ -85,8 +82,7 @@ public class LiveController extends BaseController
     @PreAuthorize("@ss.hasPermi('live:live:edit')")
     @Log(title = "直播", businessType = BusinessType.UPDATE)
     @PutMapping
-    public AjaxResult edit(@RequestBody Live live)
-    {
+    public AjaxResult edit(@RequestBody Live live) {
         return toAjax(liveService.updateLive(live));
     }
 
@@ -95,9 +91,82 @@ public class LiveController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('live:live:remove')")
     @Log(title = "直播", businessType = BusinessType.DELETE)
-	@DeleteMapping("/{liveIds}")
-    public AjaxResult remove(@PathVariable Long[] liveIds)
-    {
+    @DeleteMapping("/{liveIds}")
+    public AjaxResult remove(@PathVariable Long[] liveIds) {
         return toAjax(liveService.deleteLiveByLiveIds(liveIds));
     }
+
+    @PreAuthorize("@ss.hasPermi('live:live:query')")
+    @GetMapping("/living/{liveId}")
+    public R getRoom(@PathVariable String liveId) {
+        return liveService.getLiveRoom(liveId);
+    }
+
+    @PreAuthorize("@ss.hasPermi('live:live:edit')")
+    @PostMapping("/updateLiveIsAudit")
+    public Integer updateLiveIsAudit(@RequestBody Live live) {
+        return liveService.updateLiveIsAudit(live);
+    }
+
+
+
+    /**
+     * 批量上下架视频
+     */
+    @PreAuthorize("@ss.hasPermi('live:live:edit')")
+    @PostMapping("/handleShelfOrUn")
+    public R handleShelfOrUn(@RequestBody LiveListVo listVo) {
+        return liveService.handleShelfOrUnAdmin(listVo);
+    }
+
+    /**
+     * 批量删除视频
+     */
+    @PreAuthorize("@ss.hasPermi('live:live:edit')")
+    @PostMapping("/handleDeleteSelected")
+    public R handleDeleteSelected(@RequestBody LiveListVo listVo) {
+        return liveService.handleDeleteSelectedAdmin(listVo);
+    }
+    /**
+     * 校验上传的身份证信息
+     */
+    @PostMapping("/verifyIdInfo")
+    public R verifyIdInfo(@RequestBody Map<String, String> payload) {
+        return liveService.verifyIdInfo(payload);
+    }
+
+    /**
+     * 结束直播
+     */
+    @PreAuthorize("@ss.hasPermi('live:live:edit')")
+    @GetMapping("/finishLive")
+    public R finishLive(Live live) {
+        return liveService.finishLive(live);
+    }
+//    @GetMapping("/test/test")
+//    public R test() {
+//         liveTask.updateExpress();
+//        return R.ok();
+//    }
+
+    /**
+     * 复制直播
+     */
+    @PreAuthorize("@ss.hasPermi('live:live:edit')")
+    @GetMapping("/copyLive")
+    public R copyLive(Live live) {
+
+        return liveService.copyLive(live);
+    }
+
+    /**
+     * 开启直播
+     */
+    @PreAuthorize("@ss.hasPermi('live:live:edit')")
+    @GetMapping("/startLive")
+    public R startLive(Live live) {
+        return liveService.startLive(live);
+    }
+
+
 }

+ 227 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveCouponController.java

@@ -0,0 +1,227 @@
+package com.fs.live.controller;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import com.fs.common.core.domain.R;
+import com.fs.live.domain.LiveCouponIssue;
+import com.fs.live.param.LiveCouponPublishParam;
+import com.fs.live.service.ILiveCouponIssueService;
+import com.fs.live.vo.LiveCouponListVo;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.live.domain.LiveCoupon;
+import com.fs.live.service.ILiveCouponService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 优惠券Controller
+ *
+ * @author fs
+ * @date 2025-09-30
+ */
+@RestController
+@RequestMapping("/live/coupon")
+public class LiveCouponController extends BaseController
+{
+    @Autowired
+    private ILiveCouponService liveCouponService;
+    @Autowired
+    private ILiveCouponIssueService liveCouponIssueService;
+
+
+    /**
+     * 查询优惠券列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveCoupon:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveCoupon liveCoupon)
+    {
+        startPage();
+        liveCoupon.setIsDel(0);
+        List<LiveCoupon> list = liveCouponService.selectLiveCouponList(liveCoupon);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出优惠券列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveCoupon:export')")
+    @Log(title = "优惠券", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveCoupon liveCoupon)
+    {
+        List<LiveCoupon> list = liveCouponService.selectLiveCouponList(liveCoupon);
+        ExcelUtil<LiveCoupon> util = new ExcelUtil<LiveCoupon>(LiveCoupon.class);
+        return util.exportExcel(list, "coupon");
+    }
+
+    /**
+     * 获取优惠券详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveCoupon:query')")
+    @GetMapping(value = "/{couponId}")
+    public AjaxResult getInfo(@PathVariable("couponId") Long couponId)
+    {
+        return AjaxResult.success(liveCouponService.selectLiveCouponById(couponId));
+    }
+
+    /**
+     * 新增优惠券
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveCoupon:add')")
+    @Log(title = "优惠券", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LiveCoupon liveCoupon)
+    {
+        return toAjax(liveCouponService.insertLiveCoupon(liveCoupon));
+    }
+
+    /**
+     * 修改优惠券
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveCoupon:edit')")
+    @Log(title = "优惠券", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody LiveCoupon liveCoupon)
+    {
+        return toAjax(liveCouponService.updateLiveCoupon(liveCoupon));
+    }
+
+    /**
+     * 删除优惠券
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveCoupon:remove')")
+    @Log(title = "优惠券", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{couponIds}")
+    public AjaxResult remove(@PathVariable Long[] couponIds)
+    {
+        return toAjax(liveCouponService.deleteLiveCouponByIds(couponIds));
+    }
+
+    @PreAuthorize("@ss.hasPermi('live:liveCoupon:publish')")
+    @PostMapping("/publish")
+    public AjaxResult publish(@RequestBody LiveCouponPublishParam publishParam)
+    {
+        LiveCoupon coupon=liveCouponService.selectLiveCouponById(publishParam.getCouponId());
+        LiveCouponIssue issue=new LiveCouponIssue();
+        issue.setCouponId(publishParam.getCouponId());
+        issue.setCouponName(coupon.getTitle());
+        issue.setCouponType(Math.toIntExact(coupon.getType()));
+        issue.setStartTime(publishParam.getStartTime());
+        issue.setLimitTime(publishParam.getLimitTime());
+        issue.setTotalCount(Long.valueOf(publishParam.getTotalCount()));
+        issue.setRemainCount(Long.valueOf(publishParam.getTotalCount()));
+        issue.setIsPermanent(0);
+        issue.setStatus(1);
+        issue.setCreateTime(new Date());
+        // 继承优惠券的领取上限字段
+        issue.setLimitReceiveCount(coupon.getLimitReceiveCount());
+        return toAjax( liveCouponIssueService.insertLiveCouponIssue(issue));
+    }
+
+    @PreAuthorize("@ss.hasPermi('live:liveCoupon:batchPublish')")
+    @PostMapping("/batchPublish")
+    public R batchPublish(@RequestBody LiveCouponPublishParam publishParam)
+    {
+
+        List<LiveCoupon> list=liveCouponService.selectLiveCouponByIds(publishParam.getIds());
+        for (LiveCoupon coupon :list ){
+            LiveCouponIssue issue=new LiveCouponIssue();
+            issue.setCouponId(coupon.getCouponId());
+            issue.setCouponName(coupon.getTitle());
+            issue.setCouponType(Math.toIntExact(coupon.getType()));
+            issue.setStartTime(publishParam.getStartTime());
+            issue.setLimitTime(publishParam.getLimitTime());
+            issue.setTotalCount(Long.valueOf(publishParam.getTotalCount()));
+            issue.setRemainCount(Long.valueOf(publishParam.getTotalCount()));
+            issue.setIsPermanent(0);
+            issue.setStatus(1);
+            issue.setCreateTime(new Date());
+            // 继承优惠券的领取上限字段
+            issue.setLimitReceiveCount(coupon.getLimitReceiveCount());
+            liveCouponIssueService.insertLiveCouponIssue(issue);
+        }
+        return R.ok();
+    }
+
+    @PreAuthorize("@ss.hasPermi('live:liveCoupon:query')")
+    @GetMapping(value = "/listLiveCoupon")
+    public TableDataInfo listLiveCoupon(@RequestParam("liveId") Long liveId)
+    {
+        startPage();
+        List<LiveCoupon> list = liveCouponService.selectLiveCouponByLiveId(liveId);
+        return getDataTable(list);
+    }
+    @PreAuthorize("@ss.hasPermi('live:liveCoupon:query')")
+    @GetMapping(value = "/listCoupon")
+    public TableDataInfo listCoupon(@RequestParam("liveId") Long liveId,@RequestParam("couponName") String couponName)
+    {
+        startPage();
+        List<LiveCoupon> list = liveCouponService.listCoupon(liveId,couponName);
+        return getDataTable(list);
+    }
+
+    /**
+     * 查询优惠券列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveCoupon:list')")
+    @GetMapping("/listOn")
+    public TableDataInfo listOn(@RequestParam("liveId") Long liveId)
+    {
+        startPage();
+        List<LiveCoupon> list = liveCouponService.listOn(liveId);
+        return getDataTable(list);
+    }
+
+
+    @PreAuthorize("@ss.hasPermi('live:liveCoupon:add')")
+    @Log(title = "直播优惠券", businessType = BusinessType.INSERT)
+    @PostMapping("/delLiveCoupon")
+    public AjaxResult delLiveCoupon(@RequestBody LiveCouponListVo vo)
+    {
+        return toAjax(liveCouponService.delLiveCoupon(vo));
+    }
+
+    /**
+     * 新增直播商品
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveCoupon:add')")
+    @Log(title = "直播优惠券", businessType = BusinessType.INSERT)
+    @PostMapping("/addLiveCoupon")
+    public AjaxResult addLiveCoupon(@RequestBody Map<String, Object> payload)
+    {
+
+        return toAjax(liveCouponService.insertLiveCouponEntity(payload));
+    }
+
+    @PreAuthorize("@ss.hasPermi('live:liveCoupon:edit')")
+    @PostMapping("/handleIsShowChange")
+    public R handleIsShowChange(@RequestBody Map<String, Object> payload) {
+        return liveCouponService.handleIsShowChange(payload);
+    }
+
+    /**
+     * 批量删除视频
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveCoupon:edit')")
+    @PostMapping("/handleDeleteSelected")
+    public R handleDeleteSelected(@RequestBody LiveCouponListVo listVo) {
+        return liveCouponService.handleDeleteSelectedAdmin(listVo);
+    }
+    /**
+     * 批量删除视频
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveCoupon:edit')")
+    @PostMapping("/updateLiveCouponBind")
+    public R updateLiveCouponBind(@RequestBody LiveCouponListVo listVo) {
+        return liveCouponService.updateLiveCouponBind(listVo);
+    }
+}

+ 103 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveCouponIssueController.java

@@ -0,0 +1,103 @@
+package com.fs.live.controller;
+
+import java.util.List;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.live.domain.LiveCouponIssue;
+import com.fs.live.service.ILiveCouponIssueService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 优惠券领取Controller
+ *
+ * @author fs
+ * @date 2025-09-30
+ */
+@RestController
+@RequestMapping("/live/coupon/issue")
+public class LiveCouponIssueController extends BaseController
+{
+    @Autowired
+    private ILiveCouponIssueService liveCouponIssueService;
+
+    /**
+     * 查询优惠券领取列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:issue:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveCouponIssue liveCouponIssue)
+    {
+        startPage();
+        List<LiveCouponIssue> list = liveCouponIssueService.selectLiveCouponIssueList(liveCouponIssue);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出优惠券领取列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:issue:export')")
+    @Log(title = "优惠券领取", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveCouponIssue liveCouponIssue)
+    {
+        List<LiveCouponIssue> list = liveCouponIssueService.selectLiveCouponIssueList(liveCouponIssue);
+        ExcelUtil<LiveCouponIssue> util = new ExcelUtil<LiveCouponIssue>(LiveCouponIssue.class);
+        return util.exportExcel(list, "issue");
+    }
+
+    /**
+     * 获取优惠券领取详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('live:issue:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(liveCouponIssueService.selectLiveCouponIssueById(id));
+    }
+
+    /**
+     * 新增优惠券领取
+     */
+    @PreAuthorize("@ss.hasPermi('live:issue:add')")
+    @Log(title = "优惠券领取", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LiveCouponIssue liveCouponIssue)
+    {
+        return toAjax(liveCouponIssueService.insertLiveCouponIssue(liveCouponIssue));
+    }
+
+    /**
+     * 修改优惠券领取
+     */
+    @PreAuthorize("@ss.hasPermi('live:issue:edit')")
+    @Log(title = "优惠券领取", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody LiveCouponIssue liveCouponIssue)
+    {
+        return toAjax(liveCouponIssueService.updateLiveCouponIssue(liveCouponIssue));
+    }
+
+    /**
+     * 删除优惠券领取
+     */
+    @PreAuthorize("@ss.hasPermi('live:issue:remove')")
+    @Log(title = "优惠券领取", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(liveCouponIssueService.deleteLiveCouponIssueByIds(ids));
+    }
+}

+ 103 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveCouponIssueUserController.java

@@ -0,0 +1,103 @@
+package com.fs.live.controller;
+
+import java.util.List;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.live.domain.LiveCouponIssueUser;
+import com.fs.live.service.ILiveCouponIssueUserService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 优惠券用户领取记录Controller
+ *
+ * @author fs
+ * @date 2025-09-30
+ */
+@RestController
+@RequestMapping("/live/coupon/issue/user")
+public class LiveCouponIssueUserController extends BaseController
+{
+    @Autowired
+    private ILiveCouponIssueUserService liveCouponIssueUserService;
+
+    /**
+     * 查询优惠券用户领取记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:issue:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveCouponIssueUser liveCouponIssueUser)
+    {
+        startPage();
+        List<LiveCouponIssueUser> list = liveCouponIssueUserService.selectLiveCouponIssueUserList(liveCouponIssueUser);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出优惠券用户领取记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:issue:export')")
+    @Log(title = "优惠券用户领取记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveCouponIssueUser liveCouponIssueUser)
+    {
+        List<LiveCouponIssueUser> list = liveCouponIssueUserService.selectLiveCouponIssueUserList(liveCouponIssueUser);
+        ExcelUtil<LiveCouponIssueUser> util = new ExcelUtil<LiveCouponIssueUser>(LiveCouponIssueUser.class);
+        return util.exportExcel(list, "user");
+    }
+
+    /**
+     * 获取优惠券用户领取记录详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('live:issue:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(liveCouponIssueUserService.selectLiveCouponIssueUserById(id));
+    }
+
+    /**
+     * 新增优惠券用户领取记录
+     */
+    @PreAuthorize("@ss.hasPermi('live:issue:add')")
+    @Log(title = "优惠券用户领取记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LiveCouponIssueUser liveCouponIssueUser)
+    {
+        return toAjax(liveCouponIssueUserService.insertLiveCouponIssueUser(liveCouponIssueUser));
+    }
+
+    /**
+     * 修改优惠券用户领取记录
+     */
+    @PreAuthorize("@ss.hasPermi('live:issue:edit')")
+    @Log(title = "优惠券用户领取记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody LiveCouponIssueUser liveCouponIssueUser)
+    {
+        return toAjax(liveCouponIssueUserService.updateLiveCouponIssueUser(liveCouponIssueUser));
+    }
+
+    /**
+     * 删除优惠券用户领取记录
+     */
+    @PreAuthorize("@ss.hasPermi('live:issue:remove')")
+    @Log(title = "优惠券用户领取记录", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(liveCouponIssueUserService.deleteLiveCouponIssueUserByIds(ids));
+    }
+}

+ 105 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveCouponUserController.java

@@ -0,0 +1,105 @@
+package com.fs.live.controller;
+
+import java.util.List;
+
+import com.fs.common.utils.ParseUtils;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.live.domain.LiveCouponUser;
+import com.fs.live.service.ILiveCouponUserService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 优惠券发放记录Controller
+ *
+ * @author fs
+ * @date 2025-09-30
+ */
+@RestController
+@RequestMapping("/live/coupon/user")
+public class LiveCouponUserController extends BaseController
+{
+    @Autowired
+    private ILiveCouponUserService liveCouponUserService;
+
+    /**
+     * 查询优惠券发放记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:issue:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveCouponUser liveCouponUser)
+    {
+        startPage();
+        List<LiveCouponUser> list = liveCouponUserService.selectLiveCouponUserList(liveCouponUser);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出优惠券发放记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:issue:export')")
+    @Log(title = "优惠券发放记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveCouponUser liveCouponUser)
+    {
+        List<LiveCouponUser> list = liveCouponUserService.selectLiveCouponUserList(liveCouponUser);
+        ExcelUtil<LiveCouponUser> util = new ExcelUtil<LiveCouponUser>(LiveCouponUser.class);
+        return util.exportExcel(list, "user");
+    }
+
+    /**
+     * 获取优惠券发放记录详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('live:issue:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(liveCouponUserService.selectLiveCouponUserById(id));
+    }
+
+    /**
+     * 新增优惠券发放记录
+     */
+    @PreAuthorize("@ss.hasPermi('live:issue:add')")
+    @Log(title = "优惠券发放记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LiveCouponUser liveCouponUser)
+    {
+        return toAjax(liveCouponUserService.insertLiveCouponUser(liveCouponUser));
+    }
+
+    /**
+     * 修改优惠券发放记录
+     */
+    @PreAuthorize("@ss.hasPermi('live:issue:edit')")
+    @Log(title = "优惠券发放记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody LiveCouponUser liveCouponUser)
+    {
+        return toAjax(liveCouponUserService.updateLiveCouponUser(liveCouponUser));
+    }
+
+    /**
+     * 删除优惠券发放记录
+     */
+    @PreAuthorize("@ss.hasPermi('live:issue:remove')")
+    @Log(title = "优惠券发放记录", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(liveCouponUserService.deleteLiveCouponUserByIds(ids));
+    }
+}

+ 113 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveDataController.java

@@ -0,0 +1,113 @@
+package com.fs.live.controller;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.utils.SecurityUtils;
+import com.fs.live.domain.LiveData;
+import com.fs.live.param.LiveDataParam;
+import com.fs.live.service.ILiveDataService;
+import com.fs.live.vo.LiveUserFirstVo;
+import com.github.pagehelper.PageHelper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.List;
+import java.util.Map;
+
+
+@RestController
+@RequestMapping("/liveData/liveData")
+public class LiveDataController extends BaseController {
+
+    @Autowired
+    private ILiveDataService liveDataService;
+
+    /**
+     * 直播数据页面卡片数据
+     */
+    @GetMapping("/dashboardData")
+    public R dashboardData(@RequestParam Long liveId, HttpServletRequest request) {
+        return liveDataService.dashboardData(liveId);
+    }
+
+    /**
+     * 直播数据页面 分页查询邀请榜单
+     */
+    @GetMapping("/dashboardInviteList")
+    public TableDataInfo inviteList(@RequestParam Long liveId, HttpServletRequest request) {
+        startPage();
+        List<LiveUserFirstVo> list = liveDataService.inviteList(liveId);
+        return getDataTable(list);
+    }
+
+    /**
+     * 查询新直播数据列表
+     */
+    @PreAuthorize("@ss.hasPermi('liveData:liveData:list')")
+    @PostMapping("/listLiveData")
+    public R listLiveData(@RequestBody LiveDataParam param, HttpServletRequest request)
+    {
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        return liveDataService.listLiveData(param);
+    }
+
+    /**
+     * 查询直播数据列表
+     * */
+    @PreAuthorize("@ss.hasPermi('liveData:liveData:query')")
+    @GetMapping("/list")
+    public List<LiveData> list(LiveData liveData) {
+        return liveDataService.selectLiveDataList(liveData);
+    }
+
+    /**
+     * 查询直播数据详情
+     * */
+    @PreAuthorize("@ss.hasPermi('liveData:liveData:query')")
+    @GetMapping("/get/{liveId}")
+    public R getLiveData(@PathVariable Long liveId) {
+        return R.ok().put("liveData", liveDataService.selectLiveDataByLiveId(liveId));
+    }
+
+    /**
+     * 点赞
+     * */
+    @PreAuthorize("@ss.hasPermi('liveData:liveData:edit')")
+    @GetMapping("/like/{liveId}")
+    public R like(@PathVariable Long liveId) {
+        return R.ok(liveDataService.updateLikeByLiveId(liveId, SecurityUtils.getLoginUser().getUser().getUserId()));
+    }
+
+    /**
+     * 收藏
+     * */
+    @PreAuthorize("@ss.hasPermi('liveData:liveData:edit')")
+    @GetMapping("/collect/{liveId}")
+    public R collect(@PathVariable Long liveId) {
+        return R.ok(liveDataService.collect(liveId, SecurityUtils.getLoginUser().getUser().getUserId()));
+    }
+
+    /**
+     * 关注
+     * */
+    @PreAuthorize("@ss.hasPermi('liveData:liveData:edit')")
+    @GetMapping("/follow/{liveId}")
+    public R follow(@PathVariable Long liveId) {
+        return R.ok(liveDataService.follow(liveId, SecurityUtils.getLoginUser().getUser().getUserId()));
+    }
+
+    /**
+     * 获取直播内数据
+     * */
+    @PreAuthorize("@ss.hasPermi('liveData:liveData:query')")
+    @GetMapping("/getLiveViewData")
+    public R getLiveViewData(Long liveId) {
+        Map<String,Object> liveViewData =liveDataService.getLiveViewData(liveId);
+        return R.ok(liveViewData);
+    }
+
+
+}

+ 97 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveEventConfController.java

@@ -0,0 +1,97 @@
+package com.fs.live.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.live.domain.LiveEventConf;
+import com.fs.live.service.ILiveEventConfService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 直播触发事件配置Controller
+ *
+ * @author fs
+ * @date 2025-07-17
+ */
+@RestController
+@RequestMapping("/live/liveEventConf")
+public class LiveEventConfController extends BaseController
+{
+    @Autowired
+    private ILiveEventConfService liveEventConfService;
+
+    /**
+     * 查询直播触发事件配置列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveEventConf:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveEventConf liveEventConf)
+    {
+        startPage();
+        List<LiveEventConf> list = liveEventConfService.selectLiveEventConfList(liveEventConf);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出直播触发事件配置列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveEventConf:export')")
+    @Log(title = "直播触发事件配置", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveEventConf liveEventConf)
+    {
+        List<LiveEventConf> list = liveEventConfService.selectLiveEventConfList(liveEventConf);
+        ExcelUtil<LiveEventConf> util = new ExcelUtil<LiveEventConf>(LiveEventConf.class);
+        return util.exportExcel(list, "直播触发事件配置数据");
+    }
+
+    /**
+     * 获取直播触发事件配置详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveEventConf:query')")
+    @GetMapping(value = "/{eventId}")
+    public AjaxResult getInfo(@PathVariable("eventId") Long eventId)
+    {
+        return AjaxResult.success(liveEventConfService.selectLiveEventConfByEventId(eventId));
+    }
+
+    /**
+     * 新增直播触发事件配置
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveEventConf:add')")
+    @Log(title = "直播触发事件配置", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LiveEventConf liveEventConf)
+    {
+        return toAjax(liveEventConfService.insertLiveEventConf(liveEventConf));
+    }
+
+    /**
+     * 修改直播触发事件配置
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveEventConf:edit')")
+    @Log(title = "直播触发事件配置", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody LiveEventConf liveEventConf)
+    {
+        return toAjax(liveEventConfService.updateLiveEventConf(liveEventConf));
+    }
+
+    /**
+     * 删除直播触发事件配置
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveEventConf:remove')")
+    @Log(title = "直播触发事件配置", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{eventIds}")
+    public AjaxResult remove(@PathVariable Long[] eventIds)
+    {
+        return toAjax(liveEventConfService.deleteLiveEventConfByEventIds(eventIds));
+    }
+}

+ 97 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveGiftController.java

@@ -0,0 +1,97 @@
+package com.fs.live.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.live.domain.LiveGift;
+import com.fs.live.service.ILiveGiftService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 直播间礼物配置Controller
+ *
+ * @author fs
+ * @date 2025-07-08
+ */
+@RestController
+@RequestMapping("/live/gift")
+public class LiveGiftController extends BaseController
+{
+    @Autowired
+    private ILiveGiftService liveGiftService;
+
+    /**
+     * 查询直播间礼物配置列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:gift:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveGift liveGift)
+    {
+        startPage();
+        List<LiveGift> list = liveGiftService.selectLiveGiftList(liveGift);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出直播间礼物配置列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:gift:export')")
+    @Log(title = "直播间礼物配置", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveGift liveGift)
+    {
+        List<LiveGift> list = liveGiftService.selectLiveGiftList(liveGift);
+        ExcelUtil<LiveGift> util = new ExcelUtil<LiveGift>(LiveGift.class);
+        return util.exportExcel(list, "直播间礼物配置数据");
+    }
+
+    /**
+     * 获取直播间礼物配置详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('live:gift:query')")
+    @GetMapping(value = "/{giftId}")
+    public AjaxResult getInfo(@PathVariable("giftId") Long giftId)
+    {
+        return AjaxResult.success(liveGiftService.selectLiveGiftByGiftId(giftId));
+    }
+
+    /**
+     * 新增直播间礼物配置
+     */
+    @PreAuthorize("@ss.hasPermi('live:gift:add')")
+    @Log(title = "直播间礼物配置", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LiveGift liveGift)
+    {
+        return toAjax(liveGiftService.insertLiveGift(liveGift));
+    }
+
+    /**
+     * 修改直播间礼物配置
+     */
+    @PreAuthorize("@ss.hasPermi('live:gift:edit')")
+    @Log(title = "直播间礼物配置", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody LiveGift liveGift)
+    {
+        return toAjax(liveGiftService.updateLiveGift(liveGift));
+    }
+
+    /**
+     * 删除直播间礼物配置
+     */
+    @PreAuthorize("@ss.hasPermi('live:gift:remove')")
+    @Log(title = "直播间礼物配置", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{giftIds}")
+    public AjaxResult remove(@PathVariable Long[] giftIds)
+    {
+        return toAjax(liveGiftService.deleteLiveGiftByGiftIds(giftIds));
+    }
+}

+ 107 - 29
fs-admin/src/main/java/com/fs/live/controller/LiveGoodsController.java

@@ -1,30 +1,33 @@
 package com.fs.live.controller;
 
-import java.util.List;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.entity.SysUser;
+import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.SecurityUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.service.IFsStoreProductScrmService;
+import com.fs.hisStore.vo.FsStoreProductListVO;
 import com.fs.live.domain.LiveGoods;
 import com.fs.live.service.ILiveGoodsService;
-import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.common.core.page.TableDataInfo;
+import com.fs.live.vo.LiveGoodsListVo;
+import com.fs.live.vo.LiveGoodsVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
 
 /**
  * 直播商品Controller
- * 
+ *
  * @author fs
- * @date 2025-01-17
+ * @date 2025-07-08
  */
 @RestController
 @RequestMapping("/live/liveGoods")
@@ -33,26 +36,37 @@ public class LiveGoodsController extends BaseController
     @Autowired
     private ILiveGoodsService liveGoodsService;
 
+    @Autowired
+    private IFsStoreProductScrmService fsStoreProductService;
+
+
     /**
      * 查询直播商品列表
      */
-    @PreAuthorize("@ss.hasPermi('live:liveGoods:list')")
+//    @PreAuthorize("@ss.hasPermi('live:liveGoods:list')")
     @GetMapping("/list")
-    public TableDataInfo list(LiveGoods liveGoods)
+    public TableDataInfo list(LiveGoods liveGoods, @RequestParam(value = "liveId", required = true) Long liveId)
     {
+        // 设置企业ID和企业用户ID
+        setCompanyId(liveGoods);
+        liveGoods.setLiveId(liveId);
+
         startPage();
-        List<LiveGoods> list = liveGoodsService.selectLiveGoodsList(liveGoods);
+        List<LiveGoodsVo> list = liveGoodsService.selectProductListByLiveId(liveGoods);
         return getDataTable(list);
     }
 
     /**
      * 导出直播商品列表
      */
-    @PreAuthorize("@ss.hasPermi('live:liveGoods:export')")
+//    @PreAuthorize("@ss.hasPermi('live:liveGoods:export')")
     @Log(title = "直播商品", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
     public AjaxResult export(LiveGoods liveGoods)
     {
+        // 设置企业ID和企业用户ID
+        setCompanyId(liveGoods);
+
         List<LiveGoods> list = liveGoodsService.selectLiveGoodsList(liveGoods);
         ExcelUtil<LiveGoods> util = new ExcelUtil<LiveGoods>(LiveGoods.class);
         return util.exportExcel(list, "直播商品数据");
@@ -61,43 +75,107 @@ public class LiveGoodsController extends BaseController
     /**
      * 获取直播商品详细信息
      */
-    @PreAuthorize("@ss.hasPermi('live:liveGoods:query')")
+//    @PreAuthorize("@ss.hasPermi('live:liveGoods:query')")
     @GetMapping(value = "/{goodsId}")
     public AjaxResult getInfo(@PathVariable("goodsId") Long goodsId)
     {
-        return AjaxResult.success(liveGoodsService.selectLiveGoodsByGoodsId(goodsId));
+        //CompanyUser user = SecurityUtils.getLoginUser().getUser();
+        return AjaxResult.success();
     }
 
     /**
      * 新增直播商品
      */
-    @PreAuthorize("@ss.hasPermi('live:liveGoods:add')")
+//    @PreAuthorize("@ss.hasPermi('live:liveGoods:add')")
     @Log(title = "直播商品", businessType = BusinessType.INSERT)
     @PostMapping
-    public AjaxResult add(@RequestBody LiveGoods liveGoods)
+    public AjaxResult add(@RequestBody Map<String, Object> payload)
     {
-        return toAjax(liveGoodsService.insertLiveGoods(liveGoods));
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        //CompanyUser companyUser = companyUserService.selectCompanyUserById(loginUser.getUser().getUserId());
+        SysUser user = loginUser.getUser();
+        return toAjax(liveGoodsService.insertLiveGoodsAdmin(payload, user));
     }
 
     /**
      * 修改直播商品
      */
-    @PreAuthorize("@ss.hasPermi('live:liveGoods:edit')")
+//    @PreAuthorize("@ss.hasPermi('live:liveGoods:edit')")
     @Log(title = "直播商品", businessType = BusinessType.UPDATE)
     @PutMapping
-    public AjaxResult edit(@RequestBody LiveGoods liveGoods)
+    public R edit(@RequestBody LiveGoods liveGoods)
     {
-        return toAjax(liveGoodsService.updateLiveGoods(liveGoods));
+        return liveGoodsService.updateLiveGoods(liveGoods);
     }
 
     /**
      * 删除直播商品
      */
-    @PreAuthorize("@ss.hasPermi('live:liveGoods:remove')")
+//    @PreAuthorize("@ss.hasPermi('live:liveGoods:remove')")
     @Log(title = "直播商品", businessType = BusinessType.DELETE)
-	@DeleteMapping("/{goodsIds}")
+    @DeleteMapping("/{goodsIds}")
     public AjaxResult remove(@PathVariable Long[] goodsIds)
     {
         return toAjax(liveGoodsService.deleteLiveGoodsByGoodsIds(goodsIds));
     }
+
+    /**
+     * 设置企业ID 企业用户ID
+     * @param liveGoods 直播商品
+     */
+    private void setCompanyId(LiveGoods liveGoods) {
+        // 设置企业ID 企业用户ID
+        //LoginUser loginUser = SecurityUtils.getLoginUser();
+        //CompanyUser companyUser = companyUserService.selectCompanyUserById(loginUser.getUser().getUserId());
+        //liveGoods.setCompanyId(companyUser.getCompanyId());
+        //liveGoods.setCompanyUserId(companyUser.getUserId());
+    }
+
+    /**
+     * 查询商品列表
+     */
+    @PreAuthorize("@ss.hasPermi('store:storeProduct:list')")
+    @GetMapping("/liveList")
+    public TableDataInfo liveList(LiveGoods liveGoods)
+    {
+        startPage();
+        List<FsStoreProductListVO> list = fsStoreProductService.liveList(liveGoods);
+        return getDataTable(list);
+    }
+
+    /**
+     * 获取直播店铺
+     * */
+//    @PreAuthorize("@ss.hasPermi('live:liveGoods:query')")
+    @GetMapping("/liveStore/{liveId}")
+    public R liveGoodsStore(@PathVariable Long liveId,@RequestParam String key)
+    {
+        return liveGoodsService.getStoreByLiveId(liveId, key);
+    }
+
+    /**
+     * 批量上下架视频
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveGoods:edit')")
+    @PostMapping("/handleShelfOrUn")
+    public R handleShelfOrUn(@RequestBody LiveGoodsListVo listVo) {
+        return liveGoodsService.handleShelfOrUnAdmin(listVo);
+    }
+
+    /**
+     * 批量删除视频
+     */
+    @PostMapping("/handleDeleteSelected")
+    public R handleDeleteSelected(@RequestBody LiveGoodsListVo listVo) {
+        return liveGoodsService.handleDeleteSelectedAdmin(listVo);
+    }
+
+    /**
+     * 更新展示状态
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveGoods:edit')")
+    @PostMapping("/handleIsShowChange")
+    public R handleIsShowChange(@RequestBody LiveGoodsListVo listVo) {
+        return liveGoodsService.handleIsShowChange(listVo);
+    }
 }

+ 0 - 103
fs-admin/src/main/java/com/fs/live/controller/LiveGoodsOrderController.java

@@ -1,103 +0,0 @@
-package com.fs.live.controller;
-
-import java.util.List;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.fs.common.annotation.Log;
-import com.fs.common.core.controller.BaseController;
-import com.fs.common.core.domain.AjaxResult;
-import com.fs.common.enums.BusinessType;
-import com.fs.live.domain.LiveGoodsOrder;
-import com.fs.live.service.ILiveGoodsOrderService;
-import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.common.core.page.TableDataInfo;
-
-/**
- * 订单Controller
- * 
- * @author fs
- * @date 2025-01-17
- */
-@RestController
-@RequestMapping("/live/liveOrder")
-public class LiveGoodsOrderController extends BaseController
-{
-    @Autowired
-    private ILiveGoodsOrderService liveGoodsOrderService;
-
-    /**
-     * 查询订单列表
-     */
-    @PreAuthorize("@ss.hasPermi('live:liveOrder:list')")
-    @GetMapping("/list")
-    public TableDataInfo list(LiveGoodsOrder liveGoodsOrder)
-    {
-        startPage();
-        List<LiveGoodsOrder> list = liveGoodsOrderService.selectLiveGoodsOrderList(liveGoodsOrder);
-        return getDataTable(list);
-    }
-
-    /**
-     * 导出订单列表
-     */
-    @PreAuthorize("@ss.hasPermi('live:liveOrder:export')")
-    @Log(title = "订单", businessType = BusinessType.EXPORT)
-    @GetMapping("/export")
-    public AjaxResult export(LiveGoodsOrder liveGoodsOrder)
-    {
-        List<LiveGoodsOrder> list = liveGoodsOrderService.selectLiveGoodsOrderList(liveGoodsOrder);
-        ExcelUtil<LiveGoodsOrder> util = new ExcelUtil<LiveGoodsOrder>(LiveGoodsOrder.class);
-        return util.exportExcel(list, "订单数据");
-    }
-
-    /**
-     * 获取订单详细信息
-     */
-    @PreAuthorize("@ss.hasPermi('live:liveOrder:query')")
-    @GetMapping(value = "/{orderId}")
-    public AjaxResult getInfo(@PathVariable("orderId") Long orderId)
-    {
-        return AjaxResult.success(liveGoodsOrderService.selectLiveGoodsOrderByOrderId(orderId));
-    }
-
-    /**
-     * 新增订单
-     */
-    @PreAuthorize("@ss.hasPermi('live:liveOrder:add')")
-    @Log(title = "订单", businessType = BusinessType.INSERT)
-    @PostMapping
-    public AjaxResult add(@RequestBody LiveGoodsOrder liveGoodsOrder)
-    {
-        return toAjax(liveGoodsOrderService.insertLiveGoodsOrder(liveGoodsOrder));
-    }
-
-    /**
-     * 修改订单
-     */
-    @PreAuthorize("@ss.hasPermi('live:liveOrder:edit')")
-    @Log(title = "订单", businessType = BusinessType.UPDATE)
-    @PutMapping
-    public AjaxResult edit(@RequestBody LiveGoodsOrder liveGoodsOrder)
-    {
-        return toAjax(liveGoodsOrderService.updateLiveGoodsOrder(liveGoodsOrder));
-    }
-
-    /**
-     * 删除订单
-     */
-    @PreAuthorize("@ss.hasPermi('live:liveOrder:remove')")
-    @Log(title = "订单", businessType = BusinessType.DELETE)
-	@DeleteMapping("/{orderIds}")
-    public AjaxResult remove(@PathVariable Long[] orderIds)
-    {
-        return toAjax(liveGoodsOrderService.deleteLiveGoodsOrderByOrderIds(orderIds));
-    }
-}

+ 0 - 103
fs-admin/src/main/java/com/fs/live/controller/LiveGoodsOrderItemsController.java

@@ -1,103 +0,0 @@
-package com.fs.live.controller;
-
-import java.util.List;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.fs.common.annotation.Log;
-import com.fs.common.core.controller.BaseController;
-import com.fs.common.core.domain.AjaxResult;
-import com.fs.common.enums.BusinessType;
-import com.fs.live.domain.LiveGoodsOrderItems;
-import com.fs.live.service.ILiveGoodsOrderItemsService;
-import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.common.core.page.TableDataInfo;
-
-/**
- * 订单商品Controller
- * 
- * @author fs
- * @date 2025-01-17
- */
-@RestController
-@RequestMapping("/live/liveOrderitems")
-public class LiveGoodsOrderItemsController extends BaseController
-{
-    @Autowired
-    private ILiveGoodsOrderItemsService liveGoodsOrderItemsService;
-
-    /**
-     * 查询订单商品列表
-     */
-    @PreAuthorize("@ss.hasPermi('live:liveOrderitems:list')")
-    @GetMapping("/list")
-    public TableDataInfo list(LiveGoodsOrderItems liveGoodsOrderItems)
-    {
-        startPage();
-        List<LiveGoodsOrderItems> list = liveGoodsOrderItemsService.selectLiveGoodsOrderItemsList(liveGoodsOrderItems);
-        return getDataTable(list);
-    }
-
-    /**
-     * 导出订单商品列表
-     */
-    @PreAuthorize("@ss.hasPermi('live:liveOrderitems:export')")
-    @Log(title = "订单商品", businessType = BusinessType.EXPORT)
-    @GetMapping("/export")
-    public AjaxResult export(LiveGoodsOrderItems liveGoodsOrderItems)
-    {
-        List<LiveGoodsOrderItems> list = liveGoodsOrderItemsService.selectLiveGoodsOrderItemsList(liveGoodsOrderItems);
-        ExcelUtil<LiveGoodsOrderItems> util = new ExcelUtil<LiveGoodsOrderItems>(LiveGoodsOrderItems.class);
-        return util.exportExcel(list, "订单商品数据");
-    }
-
-    /**
-     * 获取订单商品详细信息
-     */
-    @PreAuthorize("@ss.hasPermi('live:liveOrderitems:query')")
-    @GetMapping(value = "/{id}")
-    public AjaxResult getInfo(@PathVariable("id") Long id)
-    {
-        return AjaxResult.success(liveGoodsOrderItemsService.selectLiveGoodsOrderItemsById(id));
-    }
-
-    /**
-     * 新增订单商品
-     */
-    @PreAuthorize("@ss.hasPermi('live:liveOrderitems:add')")
-    @Log(title = "订单商品", businessType = BusinessType.INSERT)
-    @PostMapping
-    public AjaxResult add(@RequestBody LiveGoodsOrderItems liveGoodsOrderItems)
-    {
-        return toAjax(liveGoodsOrderItemsService.insertLiveGoodsOrderItems(liveGoodsOrderItems));
-    }
-
-    /**
-     * 修改订单商品
-     */
-    @PreAuthorize("@ss.hasPermi('live:liveOrderitems:edit')")
-    @Log(title = "订单商品", businessType = BusinessType.UPDATE)
-    @PutMapping
-    public AjaxResult edit(@RequestBody LiveGoodsOrderItems liveGoodsOrderItems)
-    {
-        return toAjax(liveGoodsOrderItemsService.updateLiveGoodsOrderItems(liveGoodsOrderItems));
-    }
-
-    /**
-     * 删除订单商品
-     */
-    @PreAuthorize("@ss.hasPermi('live:liveOrderitems:remove')")
-    @Log(title = "订单商品", businessType = BusinessType.DELETE)
-	@DeleteMapping("/{ids}")
-    public AjaxResult remove(@PathVariable Long[] ids)
-    {
-        return toAjax(liveGoodsOrderItemsService.deleteLiveGoodsOrderItemsByIds(ids));
-    }
-}

+ 419 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveHealthOrderController.java

@@ -0,0 +1,419 @@
+package com.fs.live.controller;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.CloudHostUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.his.domain.FsStoreOrderDf;
+import com.fs.his.vo.FsStoreOrderListAndStatisticsVo;
+import com.fs.hisStore.dto.StoreOrderProductDTO;
+import com.fs.hisStore.param.FsStoreOrderParam;
+import com.fs.hisStore.vo.FsStoreOrderErpExportVO;
+import com.fs.hisStore.vo.FsStoreOrderExportVO;
+import com.fs.hisStore.vo.FsStoreOrderItemExportVO;
+import com.fs.live.domain.LiveOrderDf;
+import com.fs.live.dto.LiveOrderDeliveryNoteDTO;
+import com.fs.live.param.LiveOrderParam;
+import com.fs.live.service.ILiveOrderDfService;
+import com.fs.live.service.ILiveOrderItemService;
+import com.fs.live.service.ILiveOrderService;
+import com.fs.live.vo.*;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.math.BigDecimal;
+import java.util.*;
+
+/**`
+ * 订单Controller
+ *
+ * @author fs
+ * @date 2025-07-08
+ */
+@RestController
+@RequestMapping("/live/liveOrder")
+public class LiveHealthOrderController extends BaseController {
+
+    @Autowired
+    private ILiveOrderService liveOrderService;
+    @Autowired
+    private ILiveOrderItemService orderItemService;
+
+    @Autowired
+    private ILiveOrderDfService liveOrderDfService;
+
+    @PreAuthorize("@ss.hasPermi('store:healthStoreOrder:exportItems:details')")
+    @Log(title = "商城订单明细导出", businessType = BusinessType.EXPORT)
+    @GetMapping("/healthExportItemsDetails")
+    public AjaxResult healthExportItemsDetails(LiveOrderParam param) {
+        if ("".equals(param.getBeginTime()) && "".equals(param.getEndTime())){
+            param.setBeginTime(null);
+            param.setEndTime(null);
+        }
+        if (liveOrderService.isEntityNull(param)){
+            return AjaxResult.error("请筛选数据导出");
+        }
+        if(!StringUtils.isEmpty(param.getCreateTimeRange())){
+            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+        }
+        if(!StringUtils.isEmpty(param.getPayTimeRange())){
+            param.setPayTimeList(param.getPayTimeRange().split("--"));
+        }
+        if(!StringUtils.isEmpty(param.getDeliverySendTimeRange())){
+            param.setDeliverySendTimeList(param.getDeliverySendTimeRange().split("--"));
+        }
+        if(!StringUtils.isEmpty(param.getDeliveryImportTimeRange())){
+            param.setDeliveryImportTimeList(param.getDeliveryImportTimeRange().split("--"));
+        }
+        param.setIsHealth("1");
+        List<LiveOrderItemExportVO> list = orderItemService.selectLiveOrderItemListExportVO(param);
+        //对手机号脱敏
+        if (list != null) {
+            for (LiveOrderItemExportVO vo : list) {
+                if (!StringUtils.isEmpty(vo.getJsonInfo())) {
+                    try {
+                        StoreOrderProductDTO orderProductDTO = JSONObject.parseObject(vo.getJsonInfo(), StoreOrderProductDTO.class);
+                        BeanUtil.copyProperties(orderProductDTO, vo);
+                    } catch (Exception e) {
+                    }
+                }
+            }
+        }
+        ExcelUtil<LiveOrderItemExportVO> util = new ExcelUtil<LiveOrderItemExportVO>(LiveOrderItemExportVO.class);
+        return util.exportExcel(list, "订单明细数据");
+    }
+
+
+    /**
+     * 导出健康商城列表(明文)
+     */
+    @PreAuthorize("@ss.hasPermi('store:healthStoreOrder:export:details')")
+    @Log(title = "健康商城订单", businessType = BusinessType.EXPORT)
+    @PostMapping("/healthExportDetails")
+    public AjaxResult healthExportDetails(@RequestBody LiveOrderParam param) {
+        if ("".equals(param.getBeginTime()) && "".equals(param.getEndTime())){
+            param.setBeginTime(null);
+            param.setEndTime(null);
+        }
+        if (liveOrderService.isEntityNull(param)){
+            return AjaxResult.error("请筛选数据导出");
+        }
+        if(!StringUtils.isEmpty(param.getCreateTimeRange())){
+            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+        }
+        if(!StringUtils.isEmpty(param.getPayTimeRange())){
+            param.setPayTimeList(param.getPayTimeRange().split("--"));
+        }
+        if(!StringUtils.isEmpty(param.getDeliverySendTimeRange())){
+            param.setDeliverySendTimeList(param.getDeliverySendTimeRange().split("--"));
+        }
+        if(!StringUtils.isEmpty(param.getDeliveryImportTimeRange())){
+            param.setDeliveryImportTimeList(param.getDeliveryImportTimeRange().split("--"));
+        }
+        param.setIsHealth("1");
+        List<LiveOrderErpExportVO> list = liveOrderService.selectLiveOrderListVOByExport(param);
+        String filter = param.getFilter();
+        // 1. 处理filter参数:将逗号分隔的字符串拆分为ArrayList<String>
+        ArrayList<String> filterList = new ArrayList<>();
+        if (StringUtils.isNotBlank(filter)) {
+            // 按逗号拆分,同时去除可能的空格(如filter传"orderId, orderCode"时兼容)
+            String[] filterArr = filter.split("\\s*,\\s*");
+            filterList.addAll(Arrays.asList(filterArr));
+        }
+        // 动态导出:根据选中的字段生成Excel
+        ExcelUtil<LiveOrderErpExportVO> util = new ExcelUtil<LiveOrderErpExportVO>(LiveOrderErpExportVO.class);
+        AjaxResult result;
+        // 如果有选中的字段,只导出这些字段
+        if (filter != null && !filter.isEmpty()) {
+            return util.exportExcelSelectedColumns(list, "订单数据", filterList);
+        } else {
+            // 导出所有字段
+            return util.exportExcel(list, "订单数据");
+        }
+    }
+
+    /**
+     * 导出健康商城列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:healthLiveOrder:export')")
+    @Log(title = "健康商城订单", businessType = BusinessType.EXPORT)
+    @PostMapping("/healthExport")
+    public AjaxResult export1(@RequestBody LiveOrderParam param) {
+        if ("".equals(param.getBeginTime()) && "".equals(param.getEndTime())){
+            param.setBeginTime(null);
+            param.setEndTime(null);
+        }
+        if (liveOrderService.isEntityNull(param)){
+            return AjaxResult.error("请筛选数据导出");
+        }
+        if(!StringUtils.isEmpty(param.getCreateTimeRange())){
+            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+        }
+        if(!StringUtils.isEmpty(param.getPayTimeRange())){
+            param.setPayTimeList(param.getPayTimeRange().split("--"));
+        }
+        if(!StringUtils.isEmpty(param.getDeliverySendTimeRange())){
+            param.setDeliverySendTimeList(param.getDeliverySendTimeRange().split("--"));
+        }
+        if(!StringUtils.isEmpty(param.getDeliveryImportTimeRange())){
+            param.setDeliveryImportTimeList(param.getDeliveryImportTimeRange().split("--"));
+        }
+        param.setIsHealth("1");
+        List<LiveOrderErpExportVO> list = liveOrderService.selectLiveOrderListVOByExport(param);
+        //对手机号脱敏
+        if (list != null) {
+            for (LiveOrderErpExportVO vo : list) {
+                if (vo.getPhone() != null) {
+                    vo.setPhone(vo.getPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                }
+                if (vo.getUserPhone() != null) {
+                    vo.setUserPhone(vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                }
+
+            }
+        }
+        String filter = param.getFilter();
+        // 1. 处理filter参数:将逗号分隔的字符串拆分为ArrayList<String>
+        ArrayList<String> filterList = new ArrayList<>();
+        if (StringUtils.isNotBlank(filter)) {
+            // 按逗号拆分,同时去除可能的空格(如filter传"orderId, orderCode"时兼容)
+            String[] filterArr = filter.split("\\s*,\\s*");
+            filterList.addAll(Arrays.asList(filterArr));
+        }
+        // 动态导出:根据选中的字段生成Excel
+        ExcelUtil<LiveOrderErpExportVO> util = new ExcelUtil<LiveOrderErpExportVO>(LiveOrderErpExportVO.class);
+        AjaxResult result;
+        // 如果有选中的字段,只导出这些字段
+        if (filter != null && !filter.isEmpty()) {
+            return util.exportExcelSelectedColumns(list, "订单数据", filterList);
+        } else {
+            // 导出所有字段
+            return util.exportExcel(list, "订单数据");
+        }
+    }
+
+    /**
+     * 查询健康商城订单列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:healthLiveOrder:list')")
+    @PostMapping("/healthList")
+    public TableDataInfo healthStoreList(@RequestBody LiveOrderParam param) {
+        startPage();
+        if(!StringUtils.isEmpty(param.getCreateTimeRange())){
+            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+        }
+        if(!StringUtils.isEmpty(param.getPayTimeRange())){
+            param.setPayTimeList(param.getPayTimeRange().split("--"));
+        }
+        if(!StringUtils.isEmpty(param.getDeliveryImportTimeRange())){
+            param.setDeliveryImportTimeList(param.getDeliveryImportTimeRange().split("--"));
+        }
+        if(!StringUtils.isEmpty(param.getDeliverySendTimeRange())){
+            param.setDeliverySendTimeList(param.getDeliverySendTimeRange().split("--"));
+        }
+        param.setIsHealth("1");
+        List<LiveOrderVO> list = liveOrderService.selectLiveOrderListVO(param);
+        //金牛需求 区别其他项目 status = 6 (金牛代服管家) ,其他项目请避免使用订单状态status = 6
+        TableDataInfo dataTable = getDataTable(list);
+        if (CloudHostUtils.hasCloudHostName("康年堂")){
+            dataTable.setMsg("knt");
+        }
+        if (list != null) {
+            for (LiveOrderVO vo : list) {
+                if(vo.getPhone()!=null){
+                    vo.setPhone(vo.getPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                    vo.setUserPhone(vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                }
+                if (CloudHostUtils.hasCloudHostName("康年堂")){
+                    //查询顺丰代服账号
+                    LiveOrderDf df = liveOrderDfService.selectLiveOrderDfByOrderId(vo.getId());
+                    if (df != null){
+                        vo.setErpAccount(df.getLoginAccount());
+                    }
+                }
+
+            }
+        }
+        LiveOrderListAndStatisticsVo vo = new LiveOrderListAndStatisticsVo();
+        BeanUtils.copyProperties(dataTable, vo);
+        if (dataTable.getTotal()>0){
+            Map<String, BigDecimal> statistics= liveOrderService.selectLiveOrderStatistics(param);
+            if (statistics != null && statistics.size() >= 3){
+                vo.setPayPriceTotal(statistics.get("pay_price").toString());
+                vo.setPayMoneyTotal(statistics.get("pay_money").toString());
+                vo.setPayRemainTotal(statistics.get("pay_remain").toString());
+            }else {
+                vo.setPayPriceTotal("0");
+                vo.setPayMoneyTotal("0");
+                vo.setPayRemainTotal("0");
+            }
+            //商品数量合计
+            String productStatistics= liveOrderService.selectLiveOrderProductStatistics(param);
+            if (StringUtils.isNotBlank(productStatistics)){
+                vo.setProductInfo(productStatistics);
+            } else {
+                vo.setProductInfo("");
+            }
+
+        }
+        return vo;
+    }
+
+    @PreAuthorize("@ss.hasPermi('live:healthLiveOrder:exportItems')")
+    @Log(title = "直播订单明细导出", businessType = BusinessType.EXPORT)
+    @GetMapping("/healthExportItems")
+    public AjaxResult exportItems1(LiveOrderParam param) {
+        if ("".equals(param.getBeginTime()) && "".equals(param.getEndTime())){
+            param.setBeginTime(null);
+            param.setEndTime(null);
+        }
+        if (liveOrderService.isEntityNull(param)){
+            return AjaxResult.error("请筛选数据导出");
+        }
+        if(!StringUtils.isEmpty(param.getCreateTimeRange())){
+            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+        }
+        if(!StringUtils.isEmpty(param.getPayTimeRange())){
+            param.setPayTimeList(param.getPayTimeRange().split("--"));
+        }
+        if(!StringUtils.isEmpty(param.getDeliverySendTimeRange())){
+            param.setDeliverySendTimeList(param.getDeliverySendTimeRange().split("--"));
+        }
+        if(!StringUtils.isEmpty(param.getDeliveryImportTimeRange())){
+            param.setDeliveryImportTimeList(param.getDeliveryImportTimeRange().split("--"));
+        }
+        param.setIsHealth("1");
+        List<LiveOrderItemExportVO> list = orderItemService.selectLiveOrderItemListExportVO(param);
+        //对手机号脱敏
+        if (list != null) {
+            for (LiveOrderItemExportVO vo : list) {
+                if (vo.getUserPhone() != null) {
+                    String phone = vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{1})", "$1****$2");
+                    vo.setUserPhone(phone);
+                }
+                if (!StringUtils.isEmpty(vo.getJsonInfo())) {
+                    try {
+                        StoreOrderProductDTO orderProductDTO = JSONObject.parseObject(vo.getJsonInfo(), StoreOrderProductDTO.class);
+                        BeanUtil.copyProperties(orderProductDTO, vo);
+                    } catch (Exception e) {
+                    }
+                }
+            }
+        }
+        ExcelUtil<LiveOrderItemExportVO> util = new ExcelUtil<LiveOrderItemExportVO>(LiveOrderItemExportVO.class);
+        return util.exportExcel(list, "订单明细数据");
+    }
+
+
+
+    // 允许的文件扩展名
+    private static final String[] ALLOWED_EXCEL_EXTENSIONS = {".xlsx", ".xls"};
+
+    // 最大文件大小(5MB)
+    private static final long MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB
+
+    /**
+     * 下载订单发货导入模板
+     */
+    @GetMapping("/importDeliveryNoteExpressTemplate")
+    public AjaxResult importDeliveryNoteExpressTemplate() {
+        ExcelUtil<LiveOrderDeliveryNoteDTO> util = new ExcelUtil<>(LiveOrderDeliveryNoteDTO.class);
+        return util.importTemplateExcel("订单发货导入模板");
+    }
+
+    /**
+     * 订单发货批量导入
+     */
+    @Log(title = "发货同步导入", businessType = BusinessType.IMPORT)
+    @PostMapping("/importDeliveryNoteExpress")
+    public R importDeliveryNoteExpress(@RequestParam("file") MultipartFile file, @RequestParam("miniAppId") String miniAppId) {
+        // 1. 检查文件是否为空
+        if (file.isEmpty()) {
+            return R.error("上传的文件不能为空");
+        }
+        // 2. 检查文件大小
+        if (file.getSize() > MAX_FILE_SIZE) {
+            return R.error("文件大小不能超过5MB");
+        }
+        // 3. 检查文件扩展名
+        String fileName = file.getOriginalFilename();
+        if (fileName == null || !isValidExcelFile(fileName)) {
+            return R.error("请上传Excel文件(.xlsx或.xls格式)");
+        }
+
+        ExcelUtil<LiveOrderDeliveryNoteDTO> util = new ExcelUtil<>(LiveOrderDeliveryNoteDTO.class);
+        try {
+            List<LiveOrderDeliveryNoteDTO> dtoList = util.importExcel(file.getInputStream());
+            if (!dtoList.isEmpty()) {
+                if (dtoList.size() > 200) {
+                    return R.error("操作失败,导入数据不能大于200条!");
+                }
+                return liveOrderService.importDeliveryNoteExpress(dtoList,miniAppId);
+            } else {
+                return R.error("操作失败,导入数据不能小于1条!");
+            }
+        } catch (Exception e) {
+            logger.error("导入发货单失败", e);
+            return R.error("导入失败:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 发货单导出接口
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:healthExportShippingOrder')")
+    @Log(title = "发货单导出", businessType = BusinessType.EXPORT)
+    @GetMapping("/healthExportShippingOrder")
+    public AjaxResult healthExportShippingOrder(LiveOrderParam param) {
+        if ("".equals(param.getBeginTime()) && "".equals(param.getEndTime())) {
+            param.setBeginTime(null);
+            param.setEndTime(null);
+        }
+        if (liveOrderService.isEntityNull(param)) {
+            param = new LiveOrderParam();
+        }
+        if (!StringUtils.isEmpty(param.getCreateTimeRange())) {
+            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+        }
+        if (!StringUtils.isEmpty(param.getPayTimeRange())) {
+            param.setPayTimeList(param.getPayTimeRange().split("--"));
+        }
+        if (!StringUtils.isEmpty(param.getDeliverySendTimeRange())) {
+            param.setDeliverySendTimeList(param.getDeliverySendTimeRange().split("--"));
+        }
+        if (!StringUtils.isEmpty(param.getDeliveryImportTimeRange())) {
+            param.setDeliveryImportTimeList(param.getDeliveryImportTimeRange().split("--"));
+        }
+        List<LiveOrderDeliveryNoteExportVO> deliveryNoteExportVOList = liveOrderService.getDeliveryNote(param);
+        ExcelUtil<LiveOrderDeliveryNoteExportVO> util = new ExcelUtil<>(LiveOrderDeliveryNoteExportVO.class);
+        //通过商品ID获取关键字
+        String firstKeyword = deliveryNoteExportVOList.stream()
+                .map(LiveOrderDeliveryNoteExportVO::getKeyword)
+                .findFirst()
+                .orElse("无订单");
+        String fileName = "077AC" + firstKeyword + new java.text.SimpleDateFormat("yyyyMMdd").format(new Date());
+        return util.exportExcel(deliveryNoteExportVOList, fileName);
+    }
+
+    /**
+     * 检查文件是否为有效的Excel文件
+     */
+    private boolean isValidExcelFile(String fileName) {
+        for (String ext : ALLOWED_EXCEL_EXTENSIONS) {
+            if (fileName.toLowerCase().endsWith(ext)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}

+ 143 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveLotteryConfController.java

@@ -0,0 +1,143 @@
+package com.fs.live.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.SecurityUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.live.domain.LiveLotteryConf;
+import com.fs.live.param.LiveLotteryProductSaveParam;
+import com.fs.live.service.ILiveLotteryConfService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 直播抽奖配置Controller
+ *
+ * @author fs
+ * @date 2025-07-17
+ */
+@RestController
+@RequestMapping("/live/liveLotteryConf")
+public class LiveLotteryConfController extends BaseController
+{
+    @Autowired
+    private ILiveLotteryConfService liveLotteryConfService;
+
+    /**
+     * 查询直播抽奖配置列表
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveLotteryConf:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveLotteryConf liveLotteryConf)
+    {
+        startPage();
+        List<LiveLotteryConf> list = liveLotteryConfService.selectLiveLotteryConfList(liveLotteryConf);
+        return getDataTable(list);
+    }
+
+    @GetMapping("/listOn")
+    public TableDataInfo listOn(LiveLotteryConf liveLotteryConf)
+    {
+        startPage();
+        List<LiveLotteryConf> list = liveLotteryConfService.selectLiveLotteryConfListOn(liveLotteryConf);
+        return getDataTable(list);
+    }
+    /**
+     * 导出直播抽奖配置列表
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveLotteryConf:export')")
+    @Log(title = "直播抽奖配置", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveLotteryConf liveLotteryConf)
+    {
+        List<LiveLotteryConf> list = liveLotteryConfService.selectLiveLotteryConfList(liveLotteryConf);
+        ExcelUtil<LiveLotteryConf> util = new ExcelUtil<LiveLotteryConf>(LiveLotteryConf.class);
+        return util.exportExcel(list, "直播抽奖配置数据");
+    }
+
+    /**
+     * 获取直播抽奖配置详细信息
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveLotteryConf:query')")
+    @GetMapping(value = "/{lotteryId}")
+    public AjaxResult getInfo(@PathVariable("lotteryId") Long lotteryId)
+    {
+        return AjaxResult.success(liveLotteryConfService.selectLiveLotteryConfByLotteryId(lotteryId));
+    }
+
+    /**
+     * 新增直播抽奖配置
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveLotteryConf:add')")
+    @Log(title = "直播抽奖配置", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LiveLotteryConf liveLotteryConf)
+    {
+        return toAjax(liveLotteryConfService.insertLiveLotteryConf(liveLotteryConf));
+    }
+
+    /**
+     * 修改直播抽奖配置
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveLotteryConf:edit')")
+    @Log(title = "直播抽奖配置", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public R edit(@RequestBody LiveLotteryConf liveLotteryConf)
+    {
+        return liveLotteryConfService.updateLiveLotteryConf(liveLotteryConf);
+    }
+
+    /**
+     * 删除直播抽奖配置
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveLotteryConf:remove')")
+//    @Log(title = "直播抽奖配置", businessType = BusinessType.DELETE)
+//	@DeleteMapping("/{lotteryIds}")
+//    public AjaxResult remove(@PathVariable Long[] lotteryIds)
+//    {
+//        return toAjax(liveLotteryConfService.deleteLiveLotteryConfByLotteryIds(lotteryIds));
+//    }
+
+//    @PreAuthorize("@ss.hasPermi('live:liveLotteryConf:query')")
+    @GetMapping("/live/{liveId}")
+    public List<LiveLotteryConf> getByLiveId(@PathVariable Long liveId) {
+        return liveLotteryConfService.getByLiveId(liveId);
+    }
+
+//    @PreAuthorize("@ss.hasPermi('live:liveLotteryConf:remove')")
+    @DeleteMapping("/{id}")
+    public void delete(@PathVariable Long id) {
+        liveLotteryConfService.delete(id);
+    }
+
+    /**
+     * 发起抽奖
+     * */
+//    @PreAuthorize("@ss.hasPermi('live:liveLotteryConf:edit')")
+    @GetMapping("/start/{lotteryId}")
+    public String  start(@PathVariable Long lotteryId) {
+       return liveLotteryConfService.startLottery(lotteryId, SecurityUtils.getLoginUser().getUser().getUserId());
+    }
+
+    /** 查询抽奖配置的所有商品信息*/
+//    @PreAuthorize("@ss.hasPermi('live:liveLotteryConf:query')")
+    @GetMapping("/getGoods/{lotteryId}")
+    public R getGoods(@PathVariable Long lotteryId) {
+        return R.ok().put("data",liveLotteryConfService.getGoods(lotteryId));
+    }
+
+    /** 抽奖商品配置保存*/
+//    @PreAuthorize("@ss.hasPermi('live:liveLotteryConf:edit')")
+    @PostMapping("/product")
+    public void saveGoods(@RequestBody LiveLotteryProductSaveParam liveLotteryProducts) {
+        //liveLotteryProducts.setCreateBy(getUsername());
+        liveLotteryConfService.saveProducts(liveLotteryProducts);
+    }
+
+}

+ 97 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveLotteryRecordController.java

@@ -0,0 +1,97 @@
+package com.fs.live.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.live.domain.LiveLotteryRecord;
+import com.fs.live.service.ILiveLotteryRecordService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 直播抽奖记录Controller
+ *
+ * @author fs
+ * @date 2025-07-17
+ */
+@RestController
+@RequestMapping("/live/liveLotteryRecord")
+public class LiveLotteryRecordController extends BaseController
+{
+    @Autowired
+    private ILiveLotteryRecordService liveLotteryRecordService;
+
+    /**
+     * 查询直播抽奖记录列表
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveLotteryRecord:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveLotteryRecord liveLotteryRecord)
+    {
+        startPage();
+        List<LiveLotteryRecord> list = liveLotteryRecordService.selectLiveLotteryRecordList(liveLotteryRecord);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出直播抽奖记录列表
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveLotteryRecord:export')")
+    @Log(title = "直播抽奖记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveLotteryRecord liveLotteryRecord)
+    {
+        List<LiveLotteryRecord> list = liveLotteryRecordService.selectLiveLotteryRecordList(liveLotteryRecord);
+        ExcelUtil<LiveLotteryRecord> util = new ExcelUtil<LiveLotteryRecord>(LiveLotteryRecord.class);
+        return util.exportExcel(list, "直播抽奖记录数据");
+    }
+
+    /**
+     * 获取直播抽奖记录详细信息
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveLotteryRecord:query')")
+    @GetMapping(value = "/{lotteryId}")
+    public AjaxResult getInfo(@PathVariable("lotteryId") Long lotteryId)
+    {
+        return AjaxResult.success(liveLotteryRecordService.selectLiveLotteryRecordByLotteryId(lotteryId));
+    }
+
+    /**
+     * 新增直播抽奖记录
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveLotteryRecord:add')")
+    @Log(title = "直播抽奖记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LiveLotteryRecord liveLotteryRecord)
+    {
+        return toAjax(liveLotteryRecordService.insertLiveLotteryRecord(liveLotteryRecord));
+    }
+
+    /**
+     * 修改直播抽奖记录
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveLotteryRecord:edit')")
+    @Log(title = "直播抽奖记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody LiveLotteryRecord liveLotteryRecord)
+    {
+        return toAjax(liveLotteryRecordService.updateLiveLotteryRecord(liveLotteryRecord));
+    }
+
+    /**
+     * 删除直播抽奖记录
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveLotteryRecord:remove')")
+    @Log(title = "直播抽奖记录", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{lotteryIds}")
+    public AjaxResult remove(@PathVariable Long[] lotteryIds)
+    {
+        return toAjax(liveLotteryRecordService.deleteLiveLotteryRecordByLotteryIds(lotteryIds));
+    }
+}

+ 97 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveLotteryRegistrationController.java

@@ -0,0 +1,97 @@
+package com.fs.live.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.live.domain.LiveLotteryRegistration;
+import com.fs.live.service.ILiveLotteryRegistrationService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 直播抽奖登记Controller
+ *
+ * @author fs
+ * @date 2025-07-17
+ */
+@RestController
+@RequestMapping("/live/liveLotteryRegistration")
+public class LiveLotteryRegistrationController extends BaseController
+{
+    @Autowired
+    private ILiveLotteryRegistrationService liveLotteryRegistrationService;
+
+    /**
+     * 查询直播抽奖登记列表
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveLotteryRegistration:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveLotteryRegistration liveLotteryRegistration)
+    {
+        startPage();
+        List<LiveLotteryRegistration> list = liveLotteryRegistrationService.selectLiveLotteryRegistrationList(liveLotteryRegistration);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出直播抽奖登记列表
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveLotteryRegistration:export')")
+    @Log(title = "直播抽奖登记", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveLotteryRegistration liveLotteryRegistration)
+    {
+        List<LiveLotteryRegistration> list = liveLotteryRegistrationService.selectLiveLotteryRegistrationList(liveLotteryRegistration);
+        ExcelUtil<LiveLotteryRegistration> util = new ExcelUtil<LiveLotteryRegistration>(LiveLotteryRegistration.class);
+        return util.exportExcel(list, "直播抽奖登记数据");
+    }
+
+    /**
+     * 获取直播抽奖登记详细信息
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveLotteryRegistration:query')")
+    @GetMapping(value = "/{registrationId}")
+    public AjaxResult getInfo(@PathVariable("registrationId") Long registrationId)
+    {
+        return AjaxResult.success(liveLotteryRegistrationService.selectLiveLotteryRegistrationByRegistrationId(registrationId));
+    }
+
+    /**
+     * 新增直播抽奖登记
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveLotteryRegistration:add')")
+    @Log(title = "直播抽奖登记", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LiveLotteryRegistration liveLotteryRegistration)
+    {
+        return toAjax(liveLotteryRegistrationService.insertLiveLotteryRegistration(liveLotteryRegistration));
+    }
+
+    /**
+     * 修改直播抽奖登记
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveLotteryRegistration:edit')")
+    @Log(title = "直播抽奖登记", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody LiveLotteryRegistration liveLotteryRegistration)
+    {
+        return toAjax(liveLotteryRegistrationService.updateLiveLotteryRegistration(liveLotteryRegistration));
+    }
+
+    /**
+     * 删除直播抽奖登记
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveLotteryRegistration:remove')")
+    @Log(title = "直播抽奖登记", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{registrationIds}")
+    public AjaxResult remove(@PathVariable Long[] registrationIds)
+    {
+        return toAjax(liveLotteryRegistrationService.deleteLiveLotteryRegistrationByRegistrationIds(registrationIds));
+    }
+}

+ 22 - 20
fs-admin/src/main/java/com/fs/live/controller/LiveMsgController.java

@@ -1,28 +1,22 @@
 package com.fs.live.controller;
 
-import java.util.List;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.live.domain.LiveMsg;
 import com.fs.live.service.ILiveMsgService;
-import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.common.core.page.TableDataInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
 
 /**
  * 直播讨论Controller
- * 
+ *
  * @author fs
  * @date 2025-01-17
  */
@@ -36,7 +30,7 @@ public class LiveMsgController extends BaseController
     /**
      * 查询直播讨论列表
      */
-    @PreAuthorize("@ss.hasPermi('live:liveMsg:list')")
+//    @PreAuthorize("@ss.hasPermi('live:liveMsg:list')")
     @GetMapping("/list")
     public TableDataInfo list(LiveMsg liveMsg)
     {
@@ -45,10 +39,18 @@ public class LiveMsgController extends BaseController
         return getDataTable(list);
     }
 
+    @GetMapping("/singleList")
+    public TableDataInfo singleList(LiveMsg liveMsg)
+    {
+        startPage();
+        List<LiveMsg> list = liveMsgService.selectLiveMsgSingleList(liveMsg);
+        return getDataTable(list);
+    }
+
     /**
      * 导出直播讨论列表
      */
-    @PreAuthorize("@ss.hasPermi('live:liveMsg:export')")
+//    @PreAuthorize("@ss.hasPermi('live:liveMsg:export')")
     @Log(title = "直播讨论", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
     public AjaxResult export(LiveMsg liveMsg)
@@ -61,7 +63,7 @@ public class LiveMsgController extends BaseController
     /**
      * 获取直播讨论详细信息
      */
-    @PreAuthorize("@ss.hasPermi('live:liveMsg:query')")
+//    @PreAuthorize("@ss.hasPermi('live:liveMsg:query')")
     @GetMapping(value = "/{msgId}")
     public AjaxResult getInfo(@PathVariable("msgId") Long msgId)
     {
@@ -71,7 +73,7 @@ public class LiveMsgController extends BaseController
     /**
      * 新增直播讨论
      */
-    @PreAuthorize("@ss.hasPermi('live:liveMsg:add')")
+//    @PreAuthorize("@ss.hasPermi('live:liveMsg:add')")
     @Log(title = "直播讨论", businessType = BusinessType.INSERT)
     @PostMapping
     public AjaxResult add(@RequestBody LiveMsg liveMsg)
@@ -82,7 +84,7 @@ public class LiveMsgController extends BaseController
     /**
      * 修改直播讨论
      */
-    @PreAuthorize("@ss.hasPermi('live:liveMsg:edit')")
+//    @PreAuthorize("@ss.hasPermi('live:liveMsg:edit')")
     @Log(title = "直播讨论", businessType = BusinessType.UPDATE)
     @PutMapping
     public AjaxResult edit(@RequestBody LiveMsg liveMsg)
@@ -93,7 +95,7 @@ public class LiveMsgController extends BaseController
     /**
      * 删除直播讨论
      */
-    @PreAuthorize("@ss.hasPermi('live:liveMsg:remove')")
+//    @PreAuthorize("@ss.hasPermi('live:liveMsg:remove')")
     @Log(title = "直播讨论", businessType = BusinessType.DELETE)
 	@DeleteMapping("/{msgIds}")
     public AjaxResult remove(@PathVariable Long[] msgIds)

+ 731 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveOrderController.java

@@ -0,0 +1,731 @@
+package com.fs.live.controller;
+
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSON;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ParseUtils;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.param.CompanyStoreOrderMoneyLogsListParam;
+import com.fs.company.service.ICompanyMoneyLogsService;
+import com.fs.company.vo.CompanyStoreOrderMoneyLogsVO;
+import com.fs.crm.domain.CrmCustomer;
+import com.fs.crm.service.ICrmCustomerService;
+import com.fs.erp.domain.ErpDeliverys;
+import com.fs.erp.domain.ErpOrderQuery;
+import com.fs.erp.dto.ErpOrderQueryRequert;
+import com.fs.erp.dto.ErpOrderQueryResponse;
+import com.fs.erp.service.IErpOrderService;
+import com.fs.framework.web.service.TokenService;
+import com.fs.his.domain.FsDfAccount;
+import com.fs.his.domain.FsStoreOrderDf;
+import com.fs.his.domain.FsUser;
+import com.fs.his.enums.FsStoreOrderLogEnum;
+import com.fs.his.service.IFsDfAccountService;
+import com.fs.his.service.IFsExpressService;
+import com.fs.his.service.IFsUserService;
+import com.fs.hisStore.dto.StoreOrderExpressExportDTO;
+import com.fs.hisStore.param.*;
+import com.fs.hisStore.service.IFsExpressScrmService;
+import com.fs.hisStore.task.ExpressTask;
+import com.fs.hisStore.task.LiveTask;
+import com.fs.hisStore.vo.FsStoreOrderVO;
+import com.fs.live.domain.*;
+import com.fs.live.dto.LiveOrderCustomerExportDTO;
+import com.fs.live.dto.LiveOrderDeliveryNoteDTO;
+import com.fs.live.dto.LiveOrderExpressExportDTO;
+import com.fs.live.param.LiveOrderParam;
+import com.fs.live.vo.LiveOrderDeliveryNoteExportVO;
+import com.fs.live.enums.LiveOrderCancleReason;
+import com.fs.live.param.LiveOrderScrmSetErpPhoneParam;
+import com.fs.live.service.*;
+import com.fs.live.vo.*;
+import com.fs.qw.utils.RSAUtils;
+import com.fs.store.domain.FsStoreDelivers;
+import com.fs.system.domain.SysConfig;
+import com.fs.system.mapper.SysConfigMapper;
+import io.swagger.annotations.ApiOperation;
+import org.apache.http.util.Asserts;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+import java.math.BigDecimal;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+
+/**`
+ * 订单Controller
+ *
+ * @author fs
+ * @date 2025-07-08
+ */
+@RestController
+@RequestMapping("/live/liveOrder")
+public class LiveOrderController extends BaseController
+{
+    @Autowired
+    private ILiveOrderService liveOrderService;
+    @Autowired
+    private ICrmCustomerService crmCustomerService;
+    @Autowired
+    private IFsUserService userService;
+    @Autowired
+    private ILiveOrderItemService orderItemService;
+    @Autowired
+    private ILiveOrderLogsService orderLogsService;
+    @Autowired
+    private ILiveOrderPaymentService orderPaymentService;
+    @Autowired
+    private TokenService tokenService;
+    @Autowired
+    private IFsExpressScrmService expressService;
+//    @Autowired
+//    private FsWarehousesMapper fsWarehousesMapper;
+    @Autowired
+    IErpOrderService erpOrderService;
+
+
+
+    @Autowired
+    private IFsDfAccountService fsDfAccountService;
+
+    @Autowired
+    SysConfigMapper sysConfigMapper;
+
+    @Autowired
+    private ILiveOrderDfService liveOrderDfService;
+
+    @Autowired
+    private LiveTask liveTask;
+
+
+
+
+    @GetMapping("/importTemplate")
+    public AjaxResult importTemplate() {
+        ExcelUtil<LiveOrderExpressExportDTO> util = new ExcelUtil<LiveOrderExpressExportDTO>(LiveOrderExpressExportDTO.class);
+        return util.importTemplateExcel("物流回单数据");
+    }
+
+    /**
+     * 查询订单列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveOrder liveOrder)
+    {
+        startPage();
+        List<LiveOrder> list = liveOrderService.selectLiveOrderList(liveOrder);
+        for (LiveOrder vo : list){
+            vo.setUserPhone(ParseUtils.parsePhone(vo.getUserPhone()));
+        }
+        return getDataTable(list);
+    }
+
+
+    /**
+     * 导出订单列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:export')")
+    @Log(title = "订单", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveOrder liveOrder)
+    {
+        List<LiveOrder> list = liveOrderService.selectLiveOrderList(liveOrder);
+        ExcelUtil<LiveOrder> util = new ExcelUtil<LiveOrder>(LiveOrder.class);
+        return util.exportExcel(list, "订单数据");
+    }
+
+    /**
+     * 查询订单列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:list')")
+    @GetMapping("/listZm")
+    public TableDataInfo listZm(LiveOrder liveOrder)
+    {
+        startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        List<LiveOrderVoZm> list = liveOrderService.selectLiveOrderListZm(liveOrder);
+        for (LiveOrderVoZm vo : list){
+            vo.setUserPhone(ParseUtils.parsePhone(vo.getUserPhone()));
+            vo.setCompanyUserPhone(ParseUtils.parsePhone(vo.getCompanyUserPhone()));
+            vo.setUserBindPhone(ParseUtils.parsePhone(vo.getUserBindPhone()));
+            vo.setUserAddress(ParseUtils.parseAddress(vo.getUserAddress()));
+
+            // 财务独特字段
+            if (loginUser.getPermissions().contains("live:liveOrder:finance") || loginUser.getPermissions().contains("*:*:*")) {
+                vo.setCostPrice(vo.getCostPrice());
+                vo.setFPrice(vo.getCostPrice().multiply(BigDecimal.valueOf(Long.parseLong(vo.getTotalNum()))));
+            } else {
+                vo.setCostPrice(BigDecimal.ZERO);
+                vo.setFPrice(BigDecimal.ZERO);
+                vo.setPayDelivery(BigDecimal.ZERO);
+                vo.setBarCode("");
+                vo.setCateName("");
+            }
+            vo.setCost(vo.getCostPrice());
+
+        }
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出订单列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:export')")
+    @Log(title = "订单", businessType = BusinessType.EXPORT)
+    @GetMapping("/exportZm")
+    public AjaxResult exportZm(LiveOrder liveOrder)
+    {
+        List<LiveOrderVoZm> list = liveOrderService.selectLiveOrderListZm(liveOrder);
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        for (LiveOrderVoZm vo : list){
+            vo.setUserPhone(ParseUtils.parsePhone(vo.getUserPhone()));
+            vo.setCompanyUserPhone(ParseUtils.parsePhone(vo.getCompanyUserPhone()));
+            vo.setUserBindPhone(ParseUtils.parsePhone(vo.getUserBindPhone()));
+            vo.setUserAddress(ParseUtils.parseAddress(vo.getUserAddress()));
+            // 财务独特字段
+            if (loginUser.getPermissions().contains("live:liveOrder:finance") || loginUser.getPermissions().contains("*:*:*")) {
+                vo.setCostPrice(vo.getCostPrice());
+                vo.setFPrice(vo.getCostPrice().multiply(BigDecimal.valueOf(Long.parseLong(vo.getTotalNum()))));
+            } else {
+                vo.setCostPrice(BigDecimal.ZERO);
+                vo.setFPrice(BigDecimal.ZERO);
+            }
+            vo.setCost(vo.getCostPrice());
+        }
+        ExcelUtil<LiveOrderVoZm> util = new ExcelUtil<LiveOrderVoZm>(LiveOrderVoZm.class);
+        return util.exportExcel(list, "订单数据");
+    }
+
+
+    /**
+     * 获取订单详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:query')")
+    @GetMapping(value = "/info/{orderId}")
+    public AjaxResult getInfo(@PathVariable("orderId") String orderId)
+    {
+        return AjaxResult.success(liveOrderService.selectLiveOrderByOrderId(orderId));
+    }
+
+
+    /**
+     * 新增订单
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:add')")
+    @Log(title = "订单", businessType = BusinessType.INSERT)
+    @PostMapping("/create")
+    public R add(@RequestBody LiveOrder liveOrder)
+    {
+        return R.ok().put("data", liveOrderService.insertLiveOrder(liveOrder));
+    }
+
+    /**
+     * 修改订单
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:edit')")
+    @Log(title = "订单", businessType = BusinessType.UPDATE)
+    @PutMapping("/update")
+    public AjaxResult edit(@RequestBody LiveOrder liveOrder)
+    {
+        return toAjax(liveOrderService.updateLiveOrder(liveOrder));
+    }
+
+    /**
+     * 支付订单
+     * */
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:pay')")
+    @PostMapping(value = "/pay")
+    public void pay(LiveOrder liveOrder)
+    {
+       liveOrderService.handlePay(liveOrder);
+    }
+
+    /**
+     * 取消订单确认
+     * */
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:edit')")
+    @GetMapping(value = "/cancelConfirm/{orderId}")
+    public R cancelConfirm(@PathVariable String orderId)
+    {
+        LiveOrder byId = liveOrderService.getById(orderId);
+        List<Map<String, String>> allCodeDescMap = LiveOrderCancleReason.getAllCodeDescMap();
+        return R.ok().put("reason",allCodeDescMap).put("data",byId);
+    }
+
+    /**
+     * 按照时间粒度返回订单
+     * */
+    @GetMapping(value = "/getLiveOrderTimeGranularity")
+    public R getLiveOrderTimeGranularity(LiveOrderTimeVo liveOrder){
+        return liveOrderService.getLiveOrderTimeGranularity(liveOrder);
+    }
+
+
+    @Log(title = "同步物流", businessType = BusinessType.UPDATE)
+    @GetMapping(value = "/syncExpress/{id}")
+    public R syncExpress(@PathVariable("id") Long id) {
+        return liveOrderService.syncExpress(id);
+    }
+
+
+    /**
+     * 查询订单商品列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:query')")
+    @GetMapping("/ltemlist/{orderId}")
+    public TableDataInfo ltemlist(@PathVariable("orderId") String orderId)
+    {
+        List<LiveGoodsVo> list = liveOrderService.selectLiveOrderItemList(orderId);
+        return getDataTable(list);
+    }
+
+
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:refundOrderMoney')")
+    @Log(title = "退款", businessType = BusinessType.UPDATE)
+//    @PreAuthorize("@ss.hasPermi('live:liveOrder:refundOrderMoney')")
+    @PostMapping("/refundOrderMoney")
+    public synchronized R refundOrderMoney(@Validated @RequestBody FsStoreOrderRefundParam param, HttpServletRequest request) {
+        return liveOrderService.refundOrderMoney(param.getOrderId());
+    }
+
+    /**
+     * 获取订单详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:query')")
+    @GetMapping(value = "/{id}")
+    public R getInfo(@PathVariable("id") Long id)
+    {
+        LiveOrder order=liveOrderService.selectLiveOrderByOrderId(String.valueOf(id));
+        order.setUserPhone(ParseUtils.parsePhone(order.getUserPhone()));
+        order.setUserAddress(ParseUtils.parseAddress(order.getUserAddress()));
+        FsUser user=userService.selectFsUserById(Long.valueOf(order.getUserId()));
+        user.setPhone(ParseUtils.parsePhone(user.getPhone()));
+        List<LiveOrderItem> items=orderItemService.selectCheckedByOrderId(id);
+//        FsStoreOrderStatus statusMap=new FsStoreOrderStatus();
+
+        List<LiveOrderLogs> logs=orderLogsService.selectLiveOrderLogsByOrderId(id);
+        List<LiveOrderPayment> payments=orderPaymentService.selectLiveOrderPaymentByOrderId(id);
+
+        CrmCustomer customer=null;
+        if(order.getCustomerId()!=null&&order.getCustomerId()>0){
+            customer=crmCustomerService.selectCrmCustomerById(order.getCustomerId());
+        }
+        return R.ok().put("order", order).put("items", items).put("logs",logs).put("user",user).put("customer",customer).put("payments",payments) ;
+    }
+
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:query')")
+    @GetMapping(value = "/payments/{id}")
+    public R getOrderPayments(@PathVariable("id") Long id){
+        List<LiveOrderPayment> payments=orderPaymentService.selectLiveOrderPaymentByOrderId(id);
+        return R.ok().put("payments",payments);
+    }
+//    @Autowired
+//    private FsStoreDeliversMapper fsStoreDeliversMapper;
+    @GetMapping(value = "/express/{id}")
+    public R getExpress(@PathVariable("id") Long id){
+//        List<FsStoreDelivers> data = fsStoreDeliversMapper.findByOrderIdWithType(id, 1);
+        return R.ok().put("data","123");
+    }
+
+    @Autowired
+    private ICompanyMoneyLogsService moneyLogsService;
+
+    @GetMapping(value = "/tuiMoneyLogs")
+    public R tuiMoneyLogs(@RequestParam("orderId") String orderId){
+        LiveOrder liveOrder = liveOrderService.selectLiveOrderByOrderId(orderId);
+        List<CompanyStoreOrderMoneyLogsVO> tuiMoneyLogs=new ArrayList<>();
+        if(liveOrder.getCompanyId()!=null){
+            CompanyStoreOrderMoneyLogsListParam moneyLogsMap=new CompanyStoreOrderMoneyLogsListParam();
+            moneyLogsMap.setCompanyId(liveOrder.getCompanyId());
+            moneyLogsMap.setBusinessId(liveOrder.getOrderId().toString());
+//            moneyLogsMap.setType(1);
+            tuiMoneyLogs=moneyLogsService.selectCompanyStoreOrderMoneyLogsList(moneyLogsMap);
+        }
+        return R.ok().put("data",tuiMoneyLogs);
+    }
+
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:query')")
+    @GetMapping(value = "/logs/{id}")
+    public R getOrderLogs(@PathVariable("id") Long id){
+        List<LiveOrderLogs> logs=orderLogsService.selectLiveOrderLogsByOrderId(id);
+        return R.ok().put("logs",logs);
+    }
+
+    @GetMapping(value = "/queryAddress/{id}")
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:queryAddress')")
+    public R getAddress(@PathVariable("id") Long id)
+    {
+        LiveOrder order = liveOrderService.selectLiveOrderByOrderId(String.valueOf(id));
+        String address = order.getUserAddress();
+        return R.ok().put("address",address);
+    }
+    @GetMapping(value = "/queryPhone/{id}")
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:queryPhone')")
+    @Log(title = "查看电话", businessType = BusinessType.GRANT)
+    public R getPhone(@PathVariable("id") Long id)
+    {
+        LiveOrder order = liveOrderService.selectLiveOrderByOrderId(String.valueOf(id));
+        String userPhone = order.getUserPhone();
+        return R.ok().put("userPhone",userPhone);
+    }
+
+    /**
+     * 根据orderId查询
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:query')")
+    @GetMapping("/getByOrderId/{orderId}")
+    public R getByOrderId(@PathVariable Long orderId) {
+        LiveOrder liveOrder = liveOrderService.selectLiveOrderByOrderId(String.valueOf(orderId));
+        return R.ok().put("data",liveOrder);
+    }
+
+    @ApiOperation("物流查询")
+    @PostMapping("/getExpressByDeliverId")
+    public R getExpressByDeliverId(@Validated @RequestBody FsStoreOrderExpressParam param, HttpServletRequest request){
+        return expressService.getLiveExpressByDeliverId(param);
+    }
+
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:auditPayRemain')")
+    @PostMapping("/auditPayRemain")
+    public R auditPayRemain(@Validated @RequestBody FsStoreOrderAuditPayRemainParam param, HttpServletRequest request) {
+        return liveOrderService.auditPayRemain(param.getOrderId());
+    }
+
+    @Log(title = "分佣", businessType = BusinessType.UPDATE)
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:addTuiMoney')")
+    @PostMapping("/addTuiMoney")
+    public R addTuiMoney(@Validated @RequestBody FsStoreOrderAddTuiMoneyParam param, HttpServletRequest request) {
+        return liveOrderService.addTuiMoney(param);
+    }
+
+    @Log(title = "同步物流", businessType = BusinessType.UPDATE)
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:syncExpress')")
+    @PostMapping("/syncExpress")
+    public R syncExpress(@Validated @RequestBody FsStoreOrderExpressEditParam param, HttpServletRequest request) {
+        return liveOrderService.syncExpress(param.getOrderId());
+    }
+
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:updateExpress')")
+    @PostMapping("/updateExpress")
+    public R updateExpress(@Validated @RequestBody FsStoreOrderExpressEditParam param, HttpServletRequest request) {
+        return liveOrderService.updateExpress(param.getOrderId());
+    }
+
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:getEroOrder')")
+    @GetMapping("/getEroOrder")
+    public R getEroOrder(@RequestParam("extendOrderId") String extendOrderId) {
+        ErpOrderQueryRequert request = new ErpOrderQueryRequert();
+        request.setCode(extendOrderId);
+        if(StringUtils.isEmpty(extendOrderId)) return R.error("物流订单ID为空!");
+
+        LiveOrder order = liveOrderService.selectLiveOrderByExtendId(extendOrderId);
+
+        // 根据仓库code找erp
+//        if(com.fs.common.utils.StringUtils.isNotBlank(order.getStoreHouseCode())){
+//            String erp = fsWarehousesMapper.selectErpByCode(order.getStoreHouseCode());
+//            ErpContextHolder.setErpType(erp);
+//        }
+
+//        ErpOrderQueryResponse response = erpOrderService.getOrderLive(request);
+        return R.ok().put("data","123");
+    }
+
+    @Log(title = "冻结、解冻佣金", businessType = BusinessType.UPDATE)
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:editTuiMoney')")
+    @PostMapping("/editTuiMoney")
+    public R editTuiMoney(@Validated @RequestBody FsStoreOrderEditTuiMoneyParam param, HttpServletRequest request) {
+        return liveOrderService.editTuiMoney(param.getOrderId());
+    }
+
+    @Log(title = "确认订单", businessType = BusinessType.UPDATE)
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:finishOrder')")
+    @PostMapping("/finishOrder")
+    public R finishOrder(@Validated @RequestBody FsStoreOrderFinishParam param, HttpServletRequest request) {
+        return liveOrderService.finishOrder(param.getOrderId());
+    }
+
+    /**
+     * 修改物流
+     * @param deliveryDTO
+     * @return AjaxResult
+     */
+    @Log(title = "修改物流", businessType = BusinessType.UPDATE)
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:editDeliveryId')")
+    @PutMapping("/editDeliveryId")
+    public AjaxResult editDeliveryId(@RequestBody FsStoreDelivers deliveryDTO) {
+        liveOrderService.editLiveOrderDeliveryId(deliveryDTO);
+        return AjaxResult.success();
+    }
+
+
+    @Log(title = "手动推管易", businessType = BusinessType.INSERT)
+    @ApiOperation("创建ERP订单")
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:createErpOrder')")
+    @GetMapping("/createErpOrder")
+    public R createErpOrder(@RequestParam("orderCode") String orderCode) throws Exception
+    {
+        logger.info("手动推管易 订单号: {}",orderCode);
+        LiveOrder order=liveOrderService.selectOrderIdByOrderCode(orderCode);
+        if (orderPaymentService.selectByBussinessId(order.getOrderId()) != null) {
+            liveOrderService.createOmsOrder(order.getOrderId());
+            return R.ok();
+        }
+        return R.error("订单未支付!");
+
+    }
+
+    @Log(title = "同步管易物流单号", businessType = BusinessType.UPDATE)
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:updateErpOrder')")
+    @PostMapping("/updateErpOrder")
+    public R updateErpOrder(@Validated @RequestBody FsStoreOrderExpressEditParam param) {
+//        LiveOrder order = liveOrderService.selectLiveOrderByOrderId(String.valueOf(param.getOrderId()));
+//        ErpOrderQueryRequert request = new ErpOrderQueryRequert();
+//        request.setCode(order.getExtendOrderId());
+//
+//        // 根据仓库code找erp
+//        if(com.fs.common.utils.StringUtils.isNotBlank(order.getStoreHouseCode())){
+//            String erp = fsWarehousesMapper.selectErpByCode(order.getStoreHouseCode());
+//            ErpContextHolder.setErpType(erp);
+//        }
+//
+//        ErpOrderQueryResponse response = erpOrderService.getOrderLive(request);
+//        if(response.getOrders()!=null&&response.getOrders().size()>0){
+//            for(ErpOrderQuery orderQuery : response.getOrders()){
+//                if(orderQuery.getDeliverys()!=null&&orderQuery.getDeliverys().size()>0){
+//                    for(ErpDeliverys delivery:orderQuery.getDeliverys()){
+//                        if(delivery.getDelivery()&& StringUtils.isNotEmpty(delivery.getMail_no())){
+//                            //更新商订单状态
+//                            liveOrderService.updateDeliveryOrder(param.getOrderId(), delivery.getMail_no(),delivery.getExpress_code(),delivery.getExpress_name());
+//                            return R.ok();
+//                        }
+//                    }
+//
+//                }
+//            }
+//        }
+        return R.error("未查询到快递信息");
+    }
+
+    /**
+     * 删除订单
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:remove')")
+    @Log(title = "订单", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids) {
+        return toAjax(liveOrderService.deleteLiveOrderByIds(ids));
+    }
+
+    /**
+     * 获取erp账户
+     */
+    @GetMapping("/getErpAccount")
+    public R getErpAccount()
+    {
+        List<FsDfAccount> erpAccounts = fsDfAccountService.selectFsDfAccountList(null);
+        List<String> list = erpAccounts.stream().map(FsDfAccount::getLoginAccount).collect(Collectors.toList());
+        return R.ok().put("data", list);
+    }
+
+    /**
+     * 查询erp默认手机号
+     * @return
+     */
+    @GetMapping(value = "/queryErpPhone")
+    public AjaxResult queryErpPhone()
+    {
+        SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("erp.phone");
+        List<String> list = new ArrayList<>();
+        if(sysConfig!=null){
+            String configValue = sysConfig.getConfigValue();
+            if(StringUtils.isNotEmpty(configValue)){
+                list = JSON.parseArray(configValue, String.class);
+            }
+        }
+        return AjaxResult.success(list);
+    }
+
+    /**
+     * 设置erp默认手机号
+     * @param phoneList
+     * @return
+     */
+    @PostMapping(value = "/saveErpPhone")
+    public AjaxResult saveErpPhone(@RequestBody List<String> phoneList)
+    {
+        //去重
+        phoneList = phoneList.stream().distinct().collect(Collectors.toList());
+        SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("erp.phone");
+        sysConfig.setConfigValue(JSON.toJSONString(phoneList));
+        return AjaxResult.success(sysConfigMapper.updateConfig(sysConfig));
+    }
+
+    /**
+     * 批量设置erp手机号
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveOrder:createErpOrder')")
+    @Log(title = "订单", businessType = BusinessType.UPDATE)
+    @PostMapping("/editErpPhone")
+    public AjaxResult editErpPhone(@RequestBody LiveOrderScrmSetErpPhoneParam param)
+    {
+        param.setOpeName(getLoginUser().getUser().getNickName());
+        List<String> erpPhone = param.getErpPhone();
+        if (erpPhone == null || erpPhone.isEmpty()) {
+            return AjaxResult.error("请选择手机号");
+        }
+        return toAjax(liveOrderService.batchUpdateErpByOrderIds(param));
+    }
+
+    @Log(title = "手动推管易", businessType = BusinessType.INSERT)
+    @ApiOperation("批量创建ERP订单")
+    @PreAuthorize("@ss.hasPermi('his:storeOrder:createErpOrder')")
+    @PostMapping(value = "/batchCreateErpOrder")
+    public R batchCreateErpOrder(@RequestBody LiveOrderScrmSetErpPhoneParam param)
+    {
+        String nickName = getLoginUser().getUser().getNickName();
+        String loginAccount = param.getLoginAccount();
+        if (StringUtils.isBlank(loginAccount)){
+            return R.error("未选择推送erp账户");
+        }
+        LiveOrderDf df = getDFInfo(loginAccount);
+        if (df.getLoginAccount() == null){
+            return R.error("未查询到所选erp账户");
+        }
+        List<Long> orderIds = param.getOrderIds();
+        if (orderIds  == null || orderIds.isEmpty()) {
+            if(!StringUtils.isEmpty(param.getCreateTimeRange())){
+                param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+            }
+            if(!StringUtils.isEmpty(param.getPayTimeRange())){
+                param.setPayTimeList(param.getPayTimeRange().split("--"));
+            }
+            if(!StringUtils.isEmpty(param.getDeliveryImportTimeRange())){
+                param.setDeliveryImportTimeList(param.getDeliveryImportTimeRange().split("--"));
+            }
+            if(!StringUtils.isEmpty(param.getDeliverySendTimeRange())){
+                param.setDeliverySendTimeList(param.getDeliverySendTimeRange().split("--"));
+            }
+            param.setNotHealth(1);
+            List<LiveOrderVO> list = liveOrderService.selectLiveOrderListVO(param);
+            orderIds = list.stream().map(LiveOrderVO::getId).collect(Collectors.toList());
+        }
+        if (orderIds.isEmpty()){
+            return R.ok();
+        }
+        orderIds.forEach(orderId->{
+            try {
+                df.setOrderId(orderId);
+                LiveOrderDf temp = liveOrderDfService.selectLiveOrderDfByOrderId(df.getOrderId());
+                if (temp == null){
+                    df.setParcelQuantity(param.getParcelQuantity()); //设置包裹数量
+                    liveOrderDfService.insertLiveOrderDf(df);
+                    orderLogsService.create(orderId, FsStoreOrderLogEnum.SET_PUSH_ACCOUNT.getValue(),
+                            nickName + " " +FsStoreOrderLogEnum.SET_PUSH_ACCOUNT.getDesc() + ":" + df.getLoginAccount());
+                }
+                if (orderPaymentService.selectByBussinessId(orderId) != null) {
+                    liveOrderService.createOmsOrder(orderId);
+                    orderLogsService.create(orderId, FsStoreOrderLogEnum.PUSH_ORDER_ERP.getValue(),
+                            nickName + " " +FsStoreOrderLogEnum.PUSH_ORDER_ERP.getDesc() + ":" + df.getLoginAccount());
+                }
+            } catch (ParseException e) {
+                throw new RuntimeException(e);
+            }
+
+        });
+        return R.ok();
+    }
+
+    @ApiOperation("批量设置订单账户")
+    @PreAuthorize("@ss.hasPermi('his:storeOrder:createErpOrder')")
+    @PostMapping(value = "/batchSetErpOrder")
+    public R batchSetErpOrder(@RequestBody LiveOrderScrmSetErpPhoneParam param)
+    {
+        String nickName = getLoginUser().getUser().getNickName();
+        String loginAccount = param.getLoginAccount();
+        if (StringUtils.isBlank(loginAccount)){
+            return R.error("未选择erp账户");
+        }
+        LiveOrderDf df = getDFInfo(loginAccount);
+        if (df.getLoginAccount() == null){
+            return R.error("未查询到所选erp账户");
+        }
+        List<Long> orderIds = param.getOrderIds();
+        if (orderIds  == null || orderIds.isEmpty()) {
+            if(!StringUtils.isEmpty(param.getCreateTimeRange())){
+                param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+            }
+            if(!StringUtils.isEmpty(param.getPayTimeRange())){
+                param.setPayTimeList(param.getPayTimeRange().split("--"));
+            }
+            if(!StringUtils.isEmpty(param.getDeliveryImportTimeRange())){
+                param.setDeliveryImportTimeList(param.getDeliveryImportTimeRange().split("--"));
+            }
+            if(!StringUtils.isEmpty(param.getDeliverySendTimeRange())){
+                param.setDeliverySendTimeList(param.getDeliverySendTimeRange().split("--"));
+            }
+            param.setNotHealth(1);
+            List<LiveOrderVO> list = liveOrderService.selectLiveOrderListVO(param);
+            orderIds = list.stream().map(LiveOrderVO::getId).collect(Collectors.toList());
+        }
+        if (orderIds.isEmpty()){
+            return R.ok();
+        }
+        orderIds.forEach(orderId->{
+            df.setOrderId(orderId);
+            LiveOrderDf temp = liveOrderDfService.selectLiveOrderDfByOrderId(df.getOrderId());
+            df.setParcelQuantity(param.getParcelQuantity());
+            if (temp != null){
+                df.setUpdateTime(new Date());
+                liveOrderDfService.updateLiveOrderDf(df);
+            } else {
+                liveOrderDfService.insertLiveOrderDf(df);
+            }
+            orderLogsService.create(orderId, FsStoreOrderLogEnum.SET_PUSH_ACCOUNT.getValue(),
+                    nickName + " " +FsStoreOrderLogEnum.SET_PUSH_ACCOUNT.getDesc() + ":" + df.getLoginAccount());
+        });
+        return R.ok();
+    }
+
+    private LiveOrderDf getDFInfo(String loginAccount) {
+        //查询订单账户 判断是否存在该订单账户
+        List<FsDfAccount> erpAccounts = fsDfAccountService.selectFsDfAccountList(null);
+        LiveOrderDf df = new LiveOrderDf();
+        for (FsDfAccount erpAccount : erpAccounts) {
+            if (loginAccount.equals(erpAccount.getLoginAccount())){
+                //添加df记录
+                df.setAppKey(erpAccount.getDfAppKey());
+                df.setAppSecret(erpAccount.getDfAppsecret());
+                df.setLoginAccount(loginAccount);
+                df.setMonthlyCard(erpAccount.getMonthlyCard());
+                df.setExpressProductCode(erpAccount.getExpressProductCode());
+                df.setStatus(0);
+                break;
+            }
+        }
+        return df;
+    }
+
+
+
+}

+ 97 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveOrderItemController.java

@@ -0,0 +1,97 @@
+package com.fs.live.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.live.domain.LiveOrderItem;
+import com.fs.live.service.ILiveOrderItemService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 订单详情Controller
+ *
+ * @author fs
+ * @date 2025-07-08
+ */
+@RestController
+@RequestMapping("/live/liveOrderItem")
+public class LiveOrderItemController extends BaseController
+{
+    @Autowired
+    private ILiveOrderItemService liveOrderItemService;
+
+    /**
+     * 查询订单详情列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveOrderItem:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveOrderItem liveOrderItem)
+    {
+        startPage();
+        List<LiveOrderItem> list = liveOrderItemService.selectLiveOrderItemList(liveOrderItem);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出订单详情列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveOrderItem:export')")
+    @Log(title = "订单详情", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveOrderItem liveOrderItem)
+    {
+        List<LiveOrderItem> list = liveOrderItemService.selectLiveOrderItemList(liveOrderItem);
+        ExcelUtil<LiveOrderItem> util = new ExcelUtil<LiveOrderItem>(LiveOrderItem.class);
+        return util.exportExcel(list, "订单详情数据");
+    }
+
+    /**
+     * 获取订单详情详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveOrderItem:query')")
+    @GetMapping(value = "/{itemId}")
+    public AjaxResult getInfo(@PathVariable("itemId") String itemId)
+    {
+        return AjaxResult.success(liveOrderItemService.selectLiveOrderItemByItemId(itemId));
+    }
+
+    /**
+     * 新增订单详情
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveOrderItem:add')")
+    @Log(title = "订单详情", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LiveOrderItem liveOrderItem)
+    {
+        return toAjax(liveOrderItemService.insertLiveOrderItem(liveOrderItem));
+    }
+
+    /**
+     * 修改订单详情
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveOrderItem:edit')")
+    @Log(title = "订单详情", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody LiveOrderItem liveOrderItem)
+    {
+        return toAjax(liveOrderItemService.updateLiveOrderItem(liveOrderItem));
+    }
+
+    /**
+     * 删除订单详情
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveOrderItem:remove')")
+    @Log(title = "订单详情", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{itemIds}")
+    public AjaxResult remove(@PathVariable String[] itemIds)
+    {
+        return toAjax(liveOrderItemService.deleteLiveOrderItemByItemIds(itemIds));
+    }
+}

+ 97 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveOrderLogsController.java

@@ -0,0 +1,97 @@
+package com.fs.live.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.live.domain.LiveOrderLogs;
+import com.fs.live.service.ILiveOrderLogsService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 订单操作记录Controller
+ *
+ * @author fs
+ * @date 2025-07-08
+ */
+@RestController
+@RequestMapping("/live/liveOrderLogs")
+public class LiveOrderLogsController extends BaseController
+{
+    @Autowired
+    private ILiveOrderLogsService liveOrderLogsService;
+
+    /**
+     * 查询订单操作记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveOrderLogs:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveOrderLogs liveOrderLogs)
+    {
+        startPage();
+        List<LiveOrderLogs> list = liveOrderLogsService.selectLiveOrderLogsList(liveOrderLogs);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出订单操作记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveOrderLogs:export')")
+    @Log(title = "订单操作记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveOrderLogs liveOrderLogs)
+    {
+        List<LiveOrderLogs> list = liveOrderLogsService.selectLiveOrderLogsList(liveOrderLogs);
+        ExcelUtil<LiveOrderLogs> util = new ExcelUtil<LiveOrderLogs>(LiveOrderLogs.class);
+        return util.exportExcel(list, "订单操作记录数据");
+    }
+
+    /**
+     * 获取订单操作记录详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveOrderLogs:query')")
+    @GetMapping(value = "/{logsId}")
+    public AjaxResult getInfo(@PathVariable("logsId") String logsId)
+    {
+        return AjaxResult.success(liveOrderLogsService.selectLiveOrderLogsByLogsId(logsId));
+    }
+
+    /**
+     * 新增订单操作记录
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveOrderLogs:add')")
+    @Log(title = "订单操作记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LiveOrderLogs liveOrderLogs)
+    {
+        return toAjax(liveOrderLogsService.insertLiveOrderLogs(liveOrderLogs));
+    }
+
+    /**
+     * 修改订单操作记录
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveOrderLogs:edit')")
+    @Log(title = "订单操作记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody LiveOrderLogs liveOrderLogs)
+    {
+        return toAjax(liveOrderLogsService.updateLiveOrderLogs(liveOrderLogs));
+    }
+
+    /**
+     * 删除订单操作记录
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveOrderLogs:remove')")
+    @Log(title = "订单操作记录", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{logsIds}")
+    public AjaxResult remove(@PathVariable String[] logsIds)
+    {
+        return toAjax(liveOrderLogsService.deleteLiveOrderLogsByLogsIds(logsIds));
+    }
+}

+ 118 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveOrderPaymentController.java

@@ -0,0 +1,118 @@
+package com.fs.live.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ParseUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.live.domain.LiveOrderPayment;
+import com.fs.live.service.ILiveOrderPaymentService;
+import com.fs.live.vo.LiveOrderPaymentVo;
+import com.github.pagehelper.PageHelper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 支付明细Controller
+ *
+ * @author fs
+ * @date 2025-08-07
+ */
+@RestController
+@RequestMapping("/live/order/payment")
+public class LiveOrderPaymentController extends BaseController
+{
+    @Autowired
+    private ILiveOrderPaymentService liveOrderPaymentService;
+
+    /**
+     * 查询支付明细列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:order:payment:query')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveOrderPayment liveOrderPayment)
+    {
+        startPage();
+        List<LiveOrderPayment> list = liveOrderPaymentService.selectLiveOrderPaymentList(liveOrderPayment);
+        return getDataTable(list);
+    }
+    /**
+     * 查询支付明细列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:order:payment:query')")
+    @GetMapping
+    public TableDataInfo listNew(LiveOrderPaymentVo liveOrderPayment)
+    {
+        startPage();
+        List<LiveOrderPaymentVo> list = liveOrderPaymentService.selectLiveOrderPaymentVoList(liveOrderPayment);
+        for (LiveOrderPaymentVo vo : list){
+            vo.setUserPhone(ParseUtils.parsePhone(vo.getUserPhone()));
+        }
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出支付明细列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:order:payment:export')")
+    @Log(title = "支付明细", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveOrderPaymentVo liveOrderPayment)
+    {
+        PageHelper.startPage(1, 10000, "");
+        List<LiveOrderPaymentVo> list = liveOrderPaymentService.selectLiveOrderPaymentVoList(liveOrderPayment);
+        for (LiveOrderPaymentVo vo : list){
+            vo.setUserPhone(vo.getUserPhone() == null ? "" : vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+        }
+        ExcelUtil<LiveOrderPaymentVo> util = new ExcelUtil<LiveOrderPaymentVo>(LiveOrderPaymentVo.class);
+        return util.exportExcel(list, "直播订单支付记录");
+    }
+
+    /**
+     * 获取支付明细详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('live:order:payment:query')")
+    @GetMapping(value = "/{paymentId}")
+    public AjaxResult getInfo(@PathVariable("paymentId") Long paymentId)
+    {
+        return AjaxResult.success(liveOrderPaymentService.selectLiveOrderPaymentByPaymentIdNew(paymentId));
+    }
+
+    /**
+     * 新增支付明细
+     */
+    @PreAuthorize("@ss.hasPermi('live:order:payment:edit')")
+    @Log(title = "支付明细", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LiveOrderPayment liveOrderPayment)
+    {
+        return toAjax(liveOrderPaymentService.insertLiveOrderPayment(liveOrderPayment));
+    }
+
+    /**
+     * 修改支付明细
+     */
+    @PreAuthorize("@ss.hasPermi('live:order:payment:edit')")
+    @Log(title = "支付明细", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody LiveOrderPayment liveOrderPayment)
+    {
+        return toAjax(liveOrderPaymentService.updateLiveOrderPayment(liveOrderPayment));
+    }
+
+    /**
+     * 删除支付明细
+     */
+    @PreAuthorize("@ss.hasPermi('live:order:payment:remove')")
+    @Log(title = "支付明细", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{paymentIds}")
+    public AjaxResult remove(@PathVariable Long[] paymentIds)
+    {
+        return toAjax(liveOrderPaymentService.deleteLiveOrderPaymentByPaymentIds(paymentIds));
+    }
+}

+ 0 - 103
fs-admin/src/main/java/com/fs/live/controller/LiveQuestionController.java

@@ -1,103 +0,0 @@
-package com.fs.live.controller;
-
-import java.util.List;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.fs.common.annotation.Log;
-import com.fs.common.core.controller.BaseController;
-import com.fs.common.core.domain.AjaxResult;
-import com.fs.common.enums.BusinessType;
-import com.fs.live.domain.LiveQuestion;
-import com.fs.live.service.ILiveQuestionService;
-import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.common.core.page.TableDataInfo;
-
-/**
- * 问答Controller
- * 
- * @author fs
- * @date 2025-01-17
- */
-@RestController
-@RequestMapping("/live/liveQuestion")
-public class LiveQuestionController extends BaseController
-{
-    @Autowired
-    private ILiveQuestionService liveQuestionService;
-
-    /**
-     * 查询问答列表
-     */
-    @PreAuthorize("@ss.hasPermi('live:liveQuestion:list')")
-    @GetMapping("/list")
-    public TableDataInfo list(LiveQuestion liveQuestion)
-    {
-        startPage();
-        List<LiveQuestion> list = liveQuestionService.selectLiveQuestionList(liveQuestion);
-        return getDataTable(list);
-    }
-
-    /**
-     * 导出问答列表
-     */
-    @PreAuthorize("@ss.hasPermi('live:liveQuestion:export')")
-    @Log(title = "问答", businessType = BusinessType.EXPORT)
-    @GetMapping("/export")
-    public AjaxResult export(LiveQuestion liveQuestion)
-    {
-        List<LiveQuestion> list = liveQuestionService.selectLiveQuestionList(liveQuestion);
-        ExcelUtil<LiveQuestion> util = new ExcelUtil<LiveQuestion>(LiveQuestion.class);
-        return util.exportExcel(list, "问答数据");
-    }
-
-    /**
-     * 获取问答详细信息
-     */
-    @PreAuthorize("@ss.hasPermi('live:liveQuestion:query')")
-    @GetMapping(value = "/{questionId}")
-    public AjaxResult getInfo(@PathVariable("questionId") Long questionId)
-    {
-        return AjaxResult.success(liveQuestionService.selectLiveQuestionByQuestionId(questionId));
-    }
-
-    /**
-     * 新增问答
-     */
-    @PreAuthorize("@ss.hasPermi('live:liveQuestion:add')")
-    @Log(title = "问答", businessType = BusinessType.INSERT)
-    @PostMapping
-    public AjaxResult add(@RequestBody LiveQuestion liveQuestion)
-    {
-        return toAjax(liveQuestionService.insertLiveQuestion(liveQuestion));
-    }
-
-    /**
-     * 修改问答
-     */
-    @PreAuthorize("@ss.hasPermi('live:liveQuestion:edit')")
-    @Log(title = "问答", businessType = BusinessType.UPDATE)
-    @PutMapping
-    public AjaxResult edit(@RequestBody LiveQuestion liveQuestion)
-    {
-        return toAjax(liveQuestionService.updateLiveQuestion(liveQuestion));
-    }
-
-    /**
-     * 删除问答
-     */
-    @PreAuthorize("@ss.hasPermi('live:liveQuestion:remove')")
-    @Log(title = "问答", businessType = BusinessType.DELETE)
-	@DeleteMapping("/{questionIds}")
-    public AjaxResult remove(@PathVariable Long[] questionIds)
-    {
-        return toAjax(liveQuestionService.deleteLiveQuestionByQuestionIds(questionIds));
-    }
-}

+ 125 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveRedConfController.java

@@ -0,0 +1,125 @@
+package com.fs.live.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.SecurityUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.live.domain.LiveRedConf;
+import com.fs.live.service.ILiveRedConfService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 直播红包记录配置Controller
+ *
+ * @author fs
+ * @date 2025-07-17
+ */
+@RestController
+@RequestMapping("/live/liveRedConf")
+public class LiveRedConfController extends BaseController
+{
+    @Autowired
+    private ILiveRedConfService liveRedConfService;
+
+    /**
+     * 查询直播红包记录配置列表
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveRedConf:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveRedConf liveRedConf)
+    {
+        startPage();
+        List<LiveRedConf> list = liveRedConfService.selectLiveRedConfList(liveRedConf);
+        return getDataTable(list);
+    }
+
+    @GetMapping("/listOn")
+    public TableDataInfo listOn(LiveRedConf liveRedConf)
+    {
+        startPage();
+        List<LiveRedConf> list = liveRedConfService.selectLiveRedConfListOn(liveRedConf);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出直播红包记录配置列表
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveRedConf:export')")
+    @Log(title = "直播红包记录配置", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveRedConf liveRedConf)
+    {
+        List<LiveRedConf> list = liveRedConfService.selectLiveRedConfList(liveRedConf);
+        ExcelUtil<LiveRedConf> util = new ExcelUtil<LiveRedConf>(LiveRedConf.class);
+        return util.exportExcel(list, "直播红包记录配置数据");
+    }
+
+    /**
+     * 获取直播红包记录配置详细信息
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveRedConf:query')")
+    @GetMapping(value = "/{redId}")
+    public AjaxResult getInfo(@PathVariable("redId") Long redId)
+    {
+        return AjaxResult.success(liveRedConfService.selectLiveRedConfByRedId(redId));
+    }
+
+    /**
+     * 新增直播红包记录配置
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveRedConf:add')")
+    @Log(title = "直播红包记录配置", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LiveRedConf liveRedConf)
+    {
+        return toAjax(liveRedConfService.insertLiveRedConf(liveRedConf));
+    }
+
+    /**
+     * 修改直播红包记录配置
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveRedConf:edit')")
+    @Log(title = "直播红包记录配置", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public R edit(@RequestBody LiveRedConf liveRedConf)
+    {
+        liveRedConfService.updateLiveRedConf(liveRedConf);
+        return R.ok(liveRedConf.getRedStatus().toString());
+    }
+
+    /**
+     * 删除直播红包记录配置
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveRedConf:remove')")
+    @Log(title = "直播红包记录配置", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{redIds}")
+    public AjaxResult remove(@PathVariable Long[] redIds)
+    {
+        return toAjax(liveRedConfService.deleteLiveRedConfByRedIds(redIds));
+    }
+
+//    @PreAuthorize("@ss.hasPermi('live:liveRedConf:query')")
+    @GetMapping("/live/{liveId}")
+    public List<LiveRedConf> getByLiveId(@PathVariable Long liveId) {
+        return liveRedConfService.getByLiveId(liveId);
+    }
+
+    /**
+     * 点击发放红包
+     * */
+//    @PreAuthorize("@ss.hasPermi('live:liveRedConf:edit')")
+    @PostMapping("/start/{redId}")
+    public String start(@PathVariable String redId) {
+        return liveRedConfService.start(redId, SecurityUtils.getLoginUser().getUser().getUserId());
+    }
+
+
+
+}

+ 4 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveRedController.java

@@ -0,0 +1,4 @@
+package com.fs.live.controller;
+
+public class LiveRedController {
+}

+ 125 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveRewardRecordController.java

@@ -0,0 +1,125 @@
+package com.fs.live.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.live.domain.LiveRewardRecord;
+import com.fs.live.service.ILiveRewardRecordService;
+import com.fs.live.vo.LiveRewardRecordStatisticsVo;
+import com.fs.live.vo.LiveRewardRecordVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 用户直播间奖励记录Controller
+ *
+ * @author fs
+ * @date 2025-08-27
+ */
+@RestController
+@RequestMapping("/live/record")
+public class LiveRewardRecordController extends BaseController
+{
+    @Autowired
+    private ILiveRewardRecordService liveRewardRecordService;
+
+    /**
+     * 查询用户直播间奖励记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:record:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveRewardRecord liveRewardRecord)
+    {
+        startPage();
+        List<LiveRewardRecord> list = liveRewardRecordService.selectLiveRewardRecordList(liveRewardRecord);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出用户直播间奖励记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:record:export')")
+    @Log(title = "用户直播间奖励记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveRewardRecord liveRewardRecord)
+    {
+        List<LiveRewardRecord> list = liveRewardRecordService.selectLiveRewardRecordList(liveRewardRecord);
+        ExcelUtil<LiveRewardRecord> util = new ExcelUtil<LiveRewardRecord>(LiveRewardRecord.class);
+        return util.exportExcel(list, "用户直播间奖励记录数据");
+    }
+
+    /**
+     * 获取用户直播间奖励记录详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('live:record:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(liveRewardRecordService.selectLiveRewardRecordById(id));
+    }
+
+    /**
+     * 新增用户直播间奖励记录
+     */
+    @PreAuthorize("@ss.hasPermi('live:record:add')")
+    @Log(title = "用户直播间奖励记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LiveRewardRecord liveRewardRecord)
+    {
+        return toAjax(liveRewardRecordService.insertLiveRewardRecord(liveRewardRecord));
+    }
+
+    /**
+     * 修改用户直播间奖励记录
+     */
+    @PreAuthorize("@ss.hasPermi('live:record:edit')")
+    @Log(title = "用户直播间奖励记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody LiveRewardRecord liveRewardRecord)
+    {
+        return toAjax(liveRewardRecordService.updateLiveRewardRecord(liveRewardRecord));
+    }
+
+    /**
+     * 删除用户直播间奖励记录
+     */
+    @PreAuthorize("@ss.hasPermi('live:record:remove')")
+    @Log(title = "用户直播间奖励记录", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(liveRewardRecordService.deleteLiveRewardRecordByIds(ids));
+    }
+
+    /**
+     * 删除用户直播间奖励记录
+     */
+    @PreAuthorize("@ss.hasPermi('live:record:query')")
+    @PostMapping("/statistics")
+    public R statistics(@RequestBody LiveRewardRecordVo param)
+    {
+        return liveRewardRecordService.statistics(param);
+        // 可惜了 我华丽的实现
+        //        return liveRewardRecordService.count(step,companyId);
+    }
+
+    @PreAuthorize("@ss.hasPermi('live:record:export')")
+    @PostMapping("/export")
+    public AjaxResult export(@RequestBody LiveRewardRecordVo param)
+    {
+        List<LiveRewardRecordStatisticsVo> list = liveRewardRecordService.selectRewardSummary(param);
+
+        ExcelUtil<LiveRewardRecordStatisticsVo> util = new ExcelUtil<LiveRewardRecordStatisticsVo>(LiveRewardRecordStatisticsVo.class);
+        return util.exportExcel(list, "liveIntegralLogs");
+
+//        return liveRewardRecordService.export(param);
+//        return R.ok();
+    }
+}

+ 98 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveSensitiveWordsController.java

@@ -0,0 +1,98 @@
+package com.fs.live.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.live.domain.LiveSensitiveWords;
+import com.fs.live.service.ILiveSensitiveWordsService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 直播间敏感词过滤Controller
+ *
+ * @author fs
+ * @date 2025-07-08
+ */
+@RestController
+@RequestMapping("/live/words")
+public class LiveSensitiveWordsController extends BaseController
+{
+    @Autowired
+    private ILiveSensitiveWordsService liveSensitiveWordsService;
+
+    /**
+     * 查询直播间敏感词过滤列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:words:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveSensitiveWords liveSensitiveWords)
+    {
+        startPage();
+        List<LiveSensitiveWords> list = liveSensitiveWordsService.selectLiveSensitiveWordsList(liveSensitiveWords);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出直播间敏感词过滤列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:words:export')")
+    @Log(title = "直播间敏感词过滤", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveSensitiveWords liveSensitiveWords)
+    {
+        List<LiveSensitiveWords> list = liveSensitiveWordsService.selectLiveSensitiveWordsList(liveSensitiveWords);
+        ExcelUtil<LiveSensitiveWords> util = new ExcelUtil<LiveSensitiveWords>(LiveSensitiveWords.class);
+        return util.exportExcel(list, "直播间敏感词过滤数据");
+    }
+
+    /**
+     * 获取直播间敏感词过滤详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('live:words:query')")
+    @GetMapping(value = "/{wordId}")
+    public AjaxResult getInfo(@PathVariable("wordId") Long wordId)
+    {
+        return AjaxResult.success(liveSensitiveWordsService.selectLiveSensitiveWordsByWordId(wordId));
+    }
+
+    /**
+     * 新增直播间敏感词过滤
+     */
+    @PreAuthorize("@ss.hasPermi('live:words:add')")
+    @Log(title = "直播间敏感词过滤", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LiveSensitiveWords liveSensitiveWords)
+    {
+
+        return toAjax(liveSensitiveWordsService.insertLiveSensitiveWords(liveSensitiveWords));
+    }
+
+    /**
+     * 修改直播间敏感词过滤
+     */
+    @PreAuthorize("@ss.hasPermi('live:words:edit')")
+    @Log(title = "直播间敏感词过滤", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody LiveSensitiveWords liveSensitiveWords)
+    {
+        return toAjax(liveSensitiveWordsService.updateLiveSensitiveWords(liveSensitiveWords));
+    }
+
+    /**
+     * 删除直播间敏感词过滤
+     */
+    @PreAuthorize("@ss.hasPermi('live:words:remove')")
+    @Log(title = "直播间敏感词过滤", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{wordIds}")
+    public AjaxResult remove(@PathVariable Long[] wordIds)
+    {
+        return toAjax(liveSensitiveWordsService.deleteLiveSensitiveWordsByWordIds(wordIds));
+    }
+}

+ 122 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveTrafficLogController.java

@@ -0,0 +1,122 @@
+package com.fs.live.controller;
+
+import java.text.SimpleDateFormat;
+import java.util.List;
+
+import com.fs.live.param.LiveTrafficLogParam;
+import com.fs.live.vo.LiveTrafficLogListVO;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.live.domain.LiveTrafficLog;
+import com.fs.live.service.ILiveTrafficLogService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 直播流量记录Controller
+ *
+ * @author fs
+ * @date 2025-10-13
+ */
+@RestController
+@RequestMapping("/live/trafficLog")
+public class LiveTrafficLogController extends BaseController
+{
+    @Autowired
+    private ILiveTrafficLogService liveTrafficLogService;
+
+    /**
+     * 查询直播流量记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:trafficLog:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveTrafficLogParam param)
+    {
+        startPage();
+        if (param.getTime() != null) {
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
+            String formattedDate = sdf.format(param.getTime());
+            String[] parts = formattedDate.split("-");
+            param.setYear(Integer.parseInt(parts[0]));
+            param.setMonth(Integer.parseInt(parts[1]));
+        }
+        List<LiveTrafficLogListVO> list = liveTrafficLogService.selectTrafficByCompany(param);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出直播流量记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:trafficLog:export')")
+    @Log(title = "直播流量记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveTrafficLogParam param)
+    {
+        if (param.getTime() != null) {
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
+            String formattedDate = sdf.format(param.getTime());
+            String[] parts = formattedDate.split("-");
+            param.setYear(Integer.parseInt(parts[0]));
+            param.setMonth(Integer.parseInt(parts[1]));
+        }
+
+        List<LiveTrafficLogListVO> list = liveTrafficLogService.selectTrafficByCompany(param);
+        ExcelUtil<LiveTrafficLogListVO> util = new ExcelUtil<LiveTrafficLogListVO>(LiveTrafficLogListVO.class);
+        return util.exportExcel(list, "直播流量记录数据");
+    }
+
+    /**
+     * 获取直播流量记录详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('live:trafficLog:query')")
+    @GetMapping(value = "/{logId}")
+    public AjaxResult getInfo(@PathVariable("logId") Long logId)
+    {
+        return AjaxResult.success(liveTrafficLogService.selectLiveTrafficLogById(logId));
+    }
+
+    /**
+     * 新增直播流量记录
+     */
+    @PreAuthorize("@ss.hasPermi('live:trafficLog:add')")
+    @Log(title = "直播流量记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LiveTrafficLog liveTrafficLog)
+    {
+        return toAjax(liveTrafficLogService.insertLiveTrafficLog(liveTrafficLog));
+    }
+
+    /**
+     * 修改直播流量记录
+     */
+    @PreAuthorize("@ss.hasPermi('live:trafficLog:edit')")
+    @Log(title = "直播流量记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody LiveTrafficLog liveTrafficLog)
+    {
+        return toAjax(liveTrafficLogService.updateLiveTrafficLog(liveTrafficLog));
+    }
+
+    /**
+     * 删除直播流量记录
+     */
+    @PreAuthorize("@ss.hasPermi('live:trafficLog:remove')")
+    @Log(title = "直播流量记录", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{logIds}")
+    public AjaxResult remove(@PathVariable Long[] logIds)
+    {
+        return toAjax(liveTrafficLogService.deleteLiveTrafficLogByIds(logIds));
+    }
+}

+ 97 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveUserFavoriteController.java

@@ -0,0 +1,97 @@
+package com.fs.live.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.live.domain.LiveUserFavorite;
+import com.fs.live.service.ILiveUserFavoriteService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 用户直播收藏Controller
+ *
+ * @author fs
+ * @date 2025-07-11
+ */
+@RestController
+@RequestMapping("/live/liveUserFavorite")
+public class LiveUserFavoriteController extends BaseController
+{
+    @Autowired
+    private ILiveUserFavoriteService liveUserFavoriteService;
+
+    /**
+     * 查询用户直播收藏列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveUserFavorite:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveUserFavorite liveUserFavorite)
+    {
+        startPage();
+        List<LiveUserFavorite> list = liveUserFavoriteService.selectLiveUserFavoriteList(liveUserFavorite);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出用户直播收藏列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveUserFavorite:export')")
+    @Log(title = "用户直播收藏", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveUserFavorite liveUserFavorite)
+    {
+        List<LiveUserFavorite> list = liveUserFavoriteService.selectLiveUserFavoriteList(liveUserFavorite);
+        ExcelUtil<LiveUserFavorite> util = new ExcelUtil<LiveUserFavorite>(LiveUserFavorite.class);
+        return util.exportExcel(list, "用户直播收藏数据");
+    }
+
+    /**
+     * 获取用户直播收藏详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveUserFavorite:query')")
+    @GetMapping(value = "/{favoriteId}")
+    public AjaxResult getInfo(@PathVariable("favoriteId") Long favoriteId)
+    {
+        return AjaxResult.success(liveUserFavoriteService.selectLiveUserFavoriteByFavoriteId(favoriteId));
+    }
+
+    /**
+     * 新增用户直播收藏
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveUserFavorite:add')")
+    @Log(title = "用户直播收藏", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LiveUserFavorite liveUserFavorite)
+    {
+        return toAjax(liveUserFavoriteService.insertLiveUserFavorite(liveUserFavorite));
+    }
+
+    /**
+     * 修改用户直播收藏
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveUserFavorite:edit')")
+    @Log(title = "用户直播收藏", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody LiveUserFavorite liveUserFavorite)
+    {
+        return toAjax(liveUserFavoriteService.updateLiveUserFavorite(liveUserFavorite));
+    }
+
+    /**
+     * 删除用户直播收藏
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveUserFavorite:remove')")
+    @Log(title = "用户直播收藏", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{favoriteIds}")
+    public AjaxResult remove(@PathVariable Long[] favoriteIds)
+    {
+        return toAjax(liveUserFavoriteService.deleteLiveUserFavoriteByFavoriteIds(favoriteIds));
+    }
+}

+ 97 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveUserFollowController.java

@@ -0,0 +1,97 @@
+package com.fs.live.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.live.domain.LiveUserFollow;
+import com.fs.live.service.ILiveUserFollowService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 用户直播关注Controller
+ *
+ * @author fs
+ * @date 2025-07-11
+ */
+@RestController
+@RequestMapping("/live/liveUserFollow")
+public class LiveUserFollowController extends BaseController
+{
+    @Autowired
+    private ILiveUserFollowService liveUserFollowService;
+
+    /**
+     * 查询用户直播关注列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveUserFollow:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveUserFollow liveUserFollow)
+    {
+        startPage();
+        List<LiveUserFollow> list = liveUserFollowService.selectLiveUserFollowList(liveUserFollow);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出用户直播关注列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveUserFollow:export')")
+    @Log(title = "用户直播关注", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveUserFollow liveUserFollow)
+    {
+        List<LiveUserFollow> list = liveUserFollowService.selectLiveUserFollowList(liveUserFollow);
+        ExcelUtil<LiveUserFollow> util = new ExcelUtil<LiveUserFollow>(LiveUserFollow.class);
+        return util.exportExcel(list, "用户直播关注数据");
+    }
+
+    /**
+     * 获取用户直播关注详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveUserFollow:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(liveUserFollowService.selectLiveUserFollowById(id));
+    }
+
+    /**
+     * 新增用户直播关注
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveUserFollow:add')")
+    @Log(title = "用户直播关注", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LiveUserFollow liveUserFollow)
+    {
+        return toAjax(liveUserFollowService.insertLiveUserFollow(liveUserFollow));
+    }
+
+    /**
+     * 修改用户直播关注
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveUserFollow:edit')")
+    @Log(title = "用户直播关注", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody LiveUserFollow liveUserFollow)
+    {
+        return toAjax(liveUserFollowService.updateLiveUserFollow(liveUserFollow));
+    }
+
+    /**
+     * 删除用户直播关注
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveUserFollow:remove')")
+    @Log(title = "用户直播关注", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(liveUserFollowService.deleteLiveUserFollowByIds(ids));
+    }
+}

+ 97 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveUserLikeController.java

@@ -0,0 +1,97 @@
+package com.fs.live.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.live.domain.LiveUserLike;
+import com.fs.live.service.ILiveUserLikeService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 用户直播赞Controller
+ *
+ * @author fs
+ * @date 2025-07-11
+ */
+@RestController
+@RequestMapping("/live/liveUserLike")
+public class LiveUserLikeController extends BaseController
+{
+    @Autowired
+    private ILiveUserLikeService liveUserLikeService;
+
+    /**
+     * 查询用户直播赞列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveUserLike:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveUserLike liveUserLike)
+    {
+        startPage();
+        List<LiveUserLike> list = liveUserLikeService.selectLiveUserLikeList(liveUserLike);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出用户直播赞列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveUserLike:export')")
+    @Log(title = "用户直播赞", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveUserLike liveUserLike)
+    {
+        List<LiveUserLike> list = liveUserLikeService.selectLiveUserLikeList(liveUserLike);
+        ExcelUtil<LiveUserLike> util = new ExcelUtil<LiveUserLike>(LiveUserLike.class);
+        return util.exportExcel(list, "用户直播赞数据");
+    }
+
+    /**
+     * 获取用户直播赞详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveUserLike:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(liveUserLikeService.selectLiveUserLikeById(id));
+    }
+
+    /**
+     * 新增用户直播赞
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveUserLike:add')")
+    @Log(title = "用户直播赞", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LiveUserLike liveUserLike)
+    {
+        return toAjax(liveUserLikeService.insertLiveUserLike(liveUserLike));
+    }
+
+    /**
+     * 修改用户直播赞
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveUserLike:edit')")
+    @Log(title = "用户直播赞", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody LiveUserLike liveUserLike)
+    {
+        return toAjax(liveUserLikeService.updateLiveUserLike(liveUserLike));
+    }
+
+    /**
+     * 删除用户直播赞
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveUserLike:remove')")
+    @Log(title = "用户直播赞", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(liveUserLikeService.deleteLiveUserLikeByIds(ids));
+    }
+}

+ 108 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveUserLotteryRecordController.java

@@ -0,0 +1,108 @@
+package com.fs.live.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.live.domain.LiveUserLotteryRecord;
+import com.fs.live.service.ILiveUserLotteryRecordService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 直播用户中奖记录Controller
+ *
+ * @author fs
+ * @date 2025-07-17
+ */
+@RestController
+@RequestMapping("/live/liveUserLotteryRecord")
+public class LiveUserLotteryRecordController extends BaseController
+{
+    @Autowired
+    private ILiveUserLotteryRecordService liveUserLotteryRecordService;
+
+    /**
+     * 查询直播用户中奖记录列表
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveUserLotteryRecord:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveUserLotteryRecord liveUserLotteryRecord)
+    {
+        startPage();
+        List<LiveUserLotteryRecord> list = liveUserLotteryRecordService.selectLiveUserLotteryRecordList(liveUserLotteryRecord);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出直播用户中奖记录列表
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveUserLotteryRecord:export')")
+    @Log(title = "直播用户中奖记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveUserLotteryRecord liveUserLotteryRecord)
+    {
+        List<LiveUserLotteryRecord> list = liveUserLotteryRecordService.selectLiveUserLotteryRecordList(liveUserLotteryRecord);
+        ExcelUtil<LiveUserLotteryRecord> util = new ExcelUtil<LiveUserLotteryRecord>(LiveUserLotteryRecord.class);
+        return util.exportExcel(list, "直播用户中奖记录数据");
+    }
+
+    /**
+     * 获取直播用户中奖记录详细信息
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveUserLotteryRecord:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(liveUserLotteryRecordService.selectLiveUserLotteryRecordById(id));
+    }
+
+    /**
+     * 新增直播用户中奖记录
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveUserLotteryRecord:add')")
+    @Log(title = "直播用户中奖记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LiveUserLotteryRecord liveUserLotteryRecord)
+    {
+        return toAjax(liveUserLotteryRecordService.insertLiveUserLotteryRecord(liveUserLotteryRecord));
+    }
+
+    /**
+     * 修改直播用户中奖记录
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveUserLotteryRecord:edit')")
+    @Log(title = "直播用户中奖记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody LiveUserLotteryRecord liveUserLotteryRecord)
+    {
+        return toAjax(liveUserLotteryRecordService.updateLiveUserLotteryRecord(liveUserLotteryRecord));
+    }
+
+    /**
+     * 删除直播用户中奖记录
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveUserLotteryRecord:remove')")
+    @Log(title = "直播用户中奖记录", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(liveUserLotteryRecordService.deleteLiveUserLotteryRecordByIds(ids));
+    }
+
+    /**
+     * 查询直播用户中奖记录列表
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveUserLotteryRecord:list')")
+    @PostMapping("/info")
+    public R info(@RequestBody LiveUserLotteryRecord liveUserLotteryRecord)
+    {
+        return liveUserLotteryRecordService.selectRecordByLiveIdAndLotteryId(liveUserLotteryRecord);
+    }
+}

+ 97 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveUserRedRecordController.java

@@ -0,0 +1,97 @@
+package com.fs.live.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.live.domain.LiveUserRedRecord;
+import com.fs.live.service.ILiveUserRedRecordService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 直播用户红包记录Controller
+ *
+ * @author fs
+ * @date 2025-07-17
+ */
+@RestController
+@RequestMapping("/live/liveUserRedRecord")
+public class LiveUserRedRecordController extends BaseController
+{
+    @Autowired
+    private ILiveUserRedRecordService liveUserRedRecordService;
+
+    /**
+     * 查询直播用户红包记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveUserRedRecord:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveUserRedRecord liveUserRedRecord)
+    {
+        startPage();
+        List<LiveUserRedRecord> list = liveUserRedRecordService.selectLiveUserRedRecordList(liveUserRedRecord);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出直播用户红包记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveUserRedRecord:export')")
+    @Log(title = "直播用户红包记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveUserRedRecord liveUserRedRecord)
+    {
+        List<LiveUserRedRecord> list = liveUserRedRecordService.selectLiveUserRedRecordList(liveUserRedRecord);
+        ExcelUtil<LiveUserRedRecord> util = new ExcelUtil<LiveUserRedRecord>(LiveUserRedRecord.class);
+        return util.exportExcel(list, "直播用户红包记录数据");
+    }
+
+    /**
+     * 获取直播用户红包记录详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveUserRedRecord:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(liveUserRedRecordService.selectLiveUserRedRecordById(id));
+    }
+
+    /**
+     * 新增直播用户红包记录
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveUserRedRecord:add')")
+    @Log(title = "直播用户红包记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LiveUserRedRecord liveUserRedRecord)
+    {
+        return toAjax(liveUserRedRecordService.insertLiveUserRedRecord(liveUserRedRecord));
+    }
+
+    /**
+     * 修改直播用户红包记录
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveUserRedRecord:edit')")
+    @Log(title = "直播用户红包记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody LiveUserRedRecord liveUserRedRecord)
+    {
+        return toAjax(liveUserRedRecordService.updateLiveUserRedRecord(liveUserRedRecord));
+    }
+
+    /**
+     * 删除直播用户红包记录
+     */
+    @PreAuthorize("@ss.hasPermi('live:liveUserRedRecord:remove')")
+    @Log(title = "直播用户红包记录", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(liveUserRedRecordService.deleteLiveUserRedRecordByIds(ids));
+    }
+}

+ 33 - 20
fs-admin/src/main/java/com/fs/live/controller/LiveVideoController.java

@@ -1,28 +1,22 @@
 package com.fs.live.controller;
 
-import java.util.List;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.live.domain.LiveVideo;
 import com.fs.live.service.ILiveVideoService;
-import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.common.core.page.TableDataInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
 
 /**
  * 直播视频Controller
- * 
+ *
  * @author fs
  * @date 2025-01-17
  */
@@ -36,7 +30,7 @@ public class LiveVideoController extends BaseController
     /**
      * 查询直播视频列表
      */
-    @PreAuthorize("@ss.hasPermi('live:liveVideo:list')")
+//    @PreAuthorize("@ss.hasPermi('live:liveVideo:list')")
     @GetMapping("/list")
     public TableDataInfo list(LiveVideo liveVideo)
     {
@@ -48,7 +42,7 @@ public class LiveVideoController extends BaseController
     /**
      * 导出直播视频列表
      */
-    @PreAuthorize("@ss.hasPermi('live:liveVideo:export')")
+//    @PreAuthorize("@ss.hasPermi('live:liveVideo:export')")
     @Log(title = "直播视频", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
     public AjaxResult export(LiveVideo liveVideo)
@@ -61,17 +55,36 @@ public class LiveVideoController extends BaseController
     /**
      * 获取直播视频详细信息
      */
-    @PreAuthorize("@ss.hasPermi('live:liveVideo:query')")
+//    @PreAuthorize("@ss.hasPermi('live:liveVideo:query')")
     @GetMapping(value = "/{videoId}")
     public AjaxResult getInfo(@PathVariable("videoId") Long videoId)
     {
         return AjaxResult.success(liveVideoService.selectLiveVideoByVideoId(videoId));
     }
 
+    /**
+     * 获取直播视频详细信息
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveVideo:query')")
+    @GetMapping(value = "/liveVideoByLiveId/{liveId}")
+    public AjaxResult getLiveVideoByLiveId(@PathVariable("liveId") Long liveId)
+    {
+        return AjaxResult.success(liveVideoService.selectLiveVideoByLiveId(liveId));
+    }
+
+    /**
+     * 获取直播视频详细信息
+     */
+    @GetMapping(value = "/preview/{liveId}")
+    public AjaxResult getLiveVideoByLiveIdAndType(@PathVariable("liveId") Long liveId)
+    {
+        return AjaxResult.success(liveVideoService.selectLiveVideoByLiveIdAndType(liveId,3));
+    }
+
     /**
      * 新增直播视频
      */
-    @PreAuthorize("@ss.hasPermi('live:liveVideo:add')")
+//    @PreAuthorize("@ss.hasPermi('live:liveVideo:add')")
     @Log(title = "直播视频", businessType = BusinessType.INSERT)
     @PostMapping
     public AjaxResult add(@RequestBody LiveVideo liveVideo)
@@ -82,7 +95,7 @@ public class LiveVideoController extends BaseController
     /**
      * 修改直播视频
      */
-    @PreAuthorize("@ss.hasPermi('live:liveVideo:edit')")
+//    @PreAuthorize("@ss.hasPermi('live:liveVideo:edit')")
     @Log(title = "直播视频", businessType = BusinessType.UPDATE)
     @PutMapping
     public AjaxResult edit(@RequestBody LiveVideo liveVideo)
@@ -93,7 +106,7 @@ public class LiveVideoController extends BaseController
     /**
      * 删除直播视频
      */
-    @PreAuthorize("@ss.hasPermi('live:liveVideo:remove')")
+//    @PreAuthorize("@ss.hasPermi('live:liveVideo:remove')")
     @Log(title = "直播视频", businessType = BusinessType.DELETE)
 	@DeleteMapping("/{videoIds}")
     public AjaxResult remove(@PathVariable Long[] videoIds)

+ 102 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveWatchConfigController.java

@@ -0,0 +1,102 @@
+package com.fs.live.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.framework.web.service.TokenService;
+import com.fs.live.domain.LiveWatchConfig;
+import com.fs.live.service.ILiveWatchConfigService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 直播观看奖励设置Controller
+ *
+ * @author fs
+ * @date 2025-07-08
+ */
+@RestController
+@RequestMapping("/live/config")
+public class LiveWatchConfigController extends BaseController
+{
+    @Autowired
+    private ILiveWatchConfigService liveWatchConfigService;
+    @Autowired
+    private TokenService tokenService;
+
+    /**
+     * 查询直播观看奖励设置列表
+     */
+//    @PreAuthorize("@ss.hasPermi('live:config:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LiveWatchConfig liveWatchConfig)
+    {
+        startPage();
+        List<LiveWatchConfig> list = liveWatchConfigService.selectLiveWatchConfigList(liveWatchConfig);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出直播观看奖励设置列表
+     */
+//    @PreAuthorize("@ss.hasPermi('live:config:export')")
+    @Log(title = "直播观看奖励设置", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(LiveWatchConfig liveWatchConfig)
+    {
+        List<LiveWatchConfig> list = liveWatchConfigService.selectLiveWatchConfigList(liveWatchConfig);
+        ExcelUtil<LiveWatchConfig> util = new ExcelUtil<LiveWatchConfig>(LiveWatchConfig.class);
+        return util.exportExcel(list, "直播观看奖励设置数据");
+    }
+
+    /**
+     * 获取直播观看奖励设置详细信息
+     */
+//    @PreAuthorize("@ss.hasPermi('live:config:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success("",liveWatchConfigService.selectLiveWatchConfigByLiveId(id));
+    }
+
+    /**
+     * 新增直播观看奖励设置
+     */
+//    @PreAuthorize("@ss.hasPermi('live:config:add')")
+    @Log(title = "直播观看奖励设置", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody String jsonConfig,@RequestParam(value = "liveId") Long liveId)
+    {
+        String userId = tokenService.getLoginUser(ServletUtils.getRequest()).getUser().getUserId().toString();
+        return toAjax(liveWatchConfigService.insertLiveWatchConfig(userId, jsonConfig, liveId));
+    }
+
+    /**
+     * 修改直播观看奖励设置
+     */
+//    @PreAuthorize("@ss.hasPermi('live:config:edit')")
+    @Log(title = "直播观看奖励设置", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody String jsonConfig,@RequestParam(value = "liveId") Long liveId)
+    {
+        return toAjax(liveWatchConfigService.updateLiveWatchConfig(jsonConfig,liveId));
+    }
+
+    /**
+     * 删除直播观看奖励设置
+     */
+//    @PreAuthorize("@ss.hasPermi('live:config:remove')")
+    @Log(title = "直播观看奖励设置", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+
+        return toAjax(liveWatchConfigService.deleteLiveWatchConfigByIds(ids));
+    }
+}

+ 63 - 20
fs-admin/src/main/java/com/fs/live/controller/LiveWatchUserController.java

@@ -1,28 +1,26 @@
 package com.fs.live.controller;
 
-import java.util.List;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.live.domain.LiveWatchUser;
 import com.fs.live.service.ILiveWatchUserService;
-import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.common.core.page.TableDataInfo;
+import com.fs.live.vo.LiveWatchUserVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 /**
  * 直播间观看用户Controller
- * 
+ *
  * @author fs
  * @date 2025-01-18
  */
@@ -36,7 +34,7 @@ public class LiveWatchUserController extends BaseController
     /**
      * 查询直播间观看用户列表
      */
-    @PreAuthorize("@ss.hasPermi('live:liveWatchUser:list')")
+//    @PreAuthorize("@ss.hasPermi('live:liveWatchUser:list')")
     @GetMapping("/list")
     public TableDataInfo list(LiveWatchUser liveWatchUser)
     {
@@ -45,10 +43,34 @@ public class LiveWatchUserController extends BaseController
         return getDataTable(list);
     }
 
+    @GetMapping("/liveUserTotals")
+    public R liveUserTotals(LiveWatchUser liveWatchUser)
+    {
+
+        return liveWatchUserService.liveUserTotals(liveWatchUser);
+    }
+
+    //    @PreAuthorize("@ss.hasPermi('live:liveWatchUser:list')")
+    @GetMapping("/watchUserList")
+    public TableDataInfo watchUserList(@RequestParam Map<String,Object> param) {
+
+        startPage();
+        List<LiveWatchUserVO> onLineUserList = liveWatchUserService.selectWatchUserList(param);
+        return getDataTable(onLineUserList);
+    }
+
+    @GetMapping("/dashBoardWatchUserList")
+    public TableDataInfo dashBoardWatchUserList(@RequestParam Map<String,Object> param) {
+
+        startPage();
+        List<LiveWatchUserVO> onLineUserList = liveWatchUserService.dashBoardWatchUserList(param);
+        return getDataTable(onLineUserList);
+    }
+
     /**
      * 导出直播间观看用户列表
      */
-    @PreAuthorize("@ss.hasPermi('live:liveWatchUser:export')")
+//    @PreAuthorize("@ss.hasPermi('live:liveWatchUser:export')")
     @Log(title = "直播间观看用户", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
     public AjaxResult export(LiveWatchUser liveWatchUser)
@@ -61,7 +83,7 @@ public class LiveWatchUserController extends BaseController
     /**
      * 获取直播间观看用户详细信息
      */
-    @PreAuthorize("@ss.hasPermi('live:liveWatchUser:query')")
+//    @PreAuthorize("@ss.hasPermi('live:liveWatchUser:query')")
     @GetMapping(value = "/{id}")
     public AjaxResult getInfo(@PathVariable("id") Long id)
     {
@@ -71,7 +93,7 @@ public class LiveWatchUserController extends BaseController
     /**
      * 新增直播间观看用户
      */
-    @PreAuthorize("@ss.hasPermi('live:liveWatchUser:add')")
+//    @PreAuthorize("@ss.hasPermi('live:liveWatchUser:add')")
     @Log(title = "直播间观看用户", businessType = BusinessType.INSERT)
     @PostMapping
     public AjaxResult add(@RequestBody LiveWatchUser liveWatchUser)
@@ -82,7 +104,7 @@ public class LiveWatchUserController extends BaseController
     /**
      * 修改直播间观看用户
      */
-    @PreAuthorize("@ss.hasPermi('live:liveWatchUser:edit')")
+//    @PreAuthorize("@ss.hasPermi('live:liveWatchUser:edit')")
     @Log(title = "直播间观看用户", businessType = BusinessType.UPDATE)
     @PutMapping
     public AjaxResult edit(@RequestBody LiveWatchUser liveWatchUser)
@@ -93,11 +115,32 @@ public class LiveWatchUserController extends BaseController
     /**
      * 删除直播间观看用户
      */
-    @PreAuthorize("@ss.hasPermi('live:liveWatchUser:remove')")
+//    @PreAuthorize("@ss.hasPermi('live:liveWatchUser:remove')")
     @Log(title = "直播间观看用户", businessType = BusinessType.DELETE)
 	@DeleteMapping("/{ids}")
     public AjaxResult remove(@PathVariable Long[] ids)
     {
         return toAjax(liveWatchUserService.deleteLiveWatchUserByIds(ids));
     }
+
+    /**
+     * 修改直播间用户禁言状态
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveWatchUser:edit')")
+    @Log(title = "直播间观看用户", businessType = BusinessType.UPDATE)
+    @PutMapping("/changeUserState")
+    public AjaxResult changeUserState(@RequestParam Long liveId, @RequestParam Long userId) {
+        return toAjax(liveWatchUserService.changeUserState(liveId, userId));
+    }
+
+    /**
+     * 封禁用户账号
+     */
+//    @PreAuthorize("@ss.hasPermi('live:liveWatchUser:edit')")
+    @Log(title = "直播间观看用户", businessType = BusinessType.UPDATE)
+    @GetMapping("/blockUser/{userId}")
+    public AjaxResult blockUser(@PathVariable Long userId) {
+        return toAjax(liveWatchUserService.blockUser(userId));
+    }
+
 }

+ 326 - 0
fs-admin/src/main/java/com/fs/qw/controller/IpadAllocationRecordsController.java

@@ -0,0 +1,326 @@
+package com.fs.qw.controller;
+
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpUtil;
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.qw.domain.IpadAllocationDetails;
+import com.fs.qw.domain.IpadAllocationRecords;
+import com.fs.qw.domain.QwIpadServer;
+import com.fs.qw.mapper.IpadAllocationRecordsMapper;
+import com.fs.qw.param.ServerParam;
+import com.fs.qw.service.IIpadAllocationRecordsService;
+import com.fs.qw.service.IQwIpadServerService;
+import com.fs.qw.utils.HMACAuth;
+import com.fs.qw.vo.IpadAllocationRecordsVO;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 分配记录Controller
+ *
+ * @author fs
+ * @date 2025-11-20
+ */
+@RestController
+@RequestMapping("/qw/records")
+@Slf4j
+public class IpadAllocationRecordsController extends BaseController {
+    @Autowired
+    private IIpadAllocationRecordsService ipadAllocationRecordsService;
+    @Autowired
+    private IQwIpadServerService serverService;
+
+
+    @Autowired
+    private IpadAllocationRecordsMapper ipadAllocationRecordsMapper;
+    @Value("${ipad.watchUrl:https://manwatch.ylrzcloud.com/prod-api}")
+    private String ipadServerUrl;
+
+    /**
+     * 查询分配记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('shop:records:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(IpadAllocationRecords ipadAllocationRecords) {
+        startPage();
+        List<IpadAllocationRecords> list = ipadAllocationRecordsService.selectIpadAllocationRecordsList(ipadAllocationRecords);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出分配记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('shop:records:export')")
+    @Log(title = "分配记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(IpadAllocationRecords ipadAllocationRecords) {
+        List<IpadAllocationRecords> list = ipadAllocationRecordsService.selectIpadAllocationRecordsList(ipadAllocationRecords);
+        ExcelUtil<IpadAllocationRecords> util = new ExcelUtil<IpadAllocationRecords>(IpadAllocationRecords.class);
+        return util.exportExcel(list, "分配记录数据");
+    }
+
+    /**
+     * 获取分配记录详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('shop:records:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id) {
+        return AjaxResult.success(ipadAllocationRecordsService.selectIpadAllocationRecordsById(id));
+    }
+
+    /**
+     * 新增分配记录
+     */
+    @PreAuthorize("@ss.hasPermi('shop:records:add')")
+    @Log(title = "分配记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody IpadAllocationRecords ipadAllocationRecords) {
+        return toAjax(ipadAllocationRecordsService.insertIpadAllocationRecords(ipadAllocationRecords));
+    }
+
+    /**
+     * 修改分配记录
+     */
+    @PreAuthorize("@ss.hasPermi('shop:records:edit')")
+    @Log(title = "分配记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody IpadAllocationRecords ipadAllocationRecords) {
+        return toAjax(ipadAllocationRecordsService.updateIpadAllocationRecords(ipadAllocationRecords));
+    }
+
+    /**
+     * 删除分配记录
+     */
+    @PreAuthorize("@ss.hasPermi('shop:records:remove')")
+    @Log(title = "分配记录", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids) {
+        return toAjax(ipadAllocationRecordsService.deleteIpadAllocationRecordsByIds(ids));
+    }
+
+    //根据记录id查询他的服务器详情
+    @GetMapping("/server/{id}")
+    public AjaxResult getServerInfo(@PathVariable("id") Long id) {
+        IpadAllocationRecords ipadAllocationRecords = ipadAllocationRecordsService.selectIpadAllocationRecordsById(id);
+        if (ipadAllocationRecords == null) {
+            return AjaxResult.error("记录不存在");
+        }
+        List<IpadAllocationDetails> detailsList = JSON.parseArray(ipadAllocationRecords.getServerJson(), IpadAllocationDetails.class);
+        return AjaxResult.success(detailsList);
+    }
+
+    @Value("${ipad.fsCompanyId:13}")
+    private Long companyId;
+    //发起申请ipad服务器
+    @GetMapping("/apply")
+    @Transactional(rollbackFor = Exception.class)
+    public AjaxResult apply(Integer applyCount,String area) throws Exception {
+        //校验count是否为正整数
+        if (applyCount == null || applyCount <= 0) {
+            return AjaxResult.error("申请数量必须为正整数");
+        }
+        //校验area是否为空
+        if (area == null || area.isEmpty()) {
+            return AjaxResult.error("区域不能为空");
+        }
+
+        //插入数据库申请表
+        IpadAllocationRecords ipadAllocationRecords = new IpadAllocationRecords();
+        ipadAllocationRecords.setCompanyId(13L);
+        ipadAllocationRecords.setApplyQuantity(applyCount);
+        ipadAllocationRecords.setSubmitTime(LocalDateTime.now());
+        ipadAllocationRecords.setRegion(area);
+        ipadAllocationRecordsMapper.insert(ipadAllocationRecords);
+        //发起http请求
+        //调用ipad服务器申请接口
+        HashMap<Object, Object> param = new HashMap<>();
+        param.put("allocationId", ipadAllocationRecords.getId());//携带id过去,以后查询结果
+        param.put("companyId", companyId);//公司id自己去配置文件改自己公司的id去腕表找
+        param.put("region", area);//区域
+        param.put("applyQuantity", applyCount);
+        String paramJson = JSON.toJSONString(param);
+        HttpRequest post = HttpUtil.createPost(ipadServerUrl + "/ipad/records/addRecords");
+        log.info("发起请求,申请参数:{},url:{}", paramJson, ipadServerUrl + "/ipad/records/addRecords");
+        post.body(paramJson);
+        post.header("Authorization", HMACAuth.generateToken());
+        //发起请求
+        String result = post.execute().body();
+        log.info("发起ipad服务器申请,申请数量:{},申请id:{},申请结果:{}", applyCount, ipadAllocationRecords.getId(), result);
+        //code不为200,回滚数据库
+        AjaxResult response = JSON.parseObject(result, AjaxResult.class);
+        if (response == null || (Integer) response.get("code") != 200) {
+            ipadAllocationRecordsMapper.deleteById(ipadAllocationRecords.getId());
+            throw new Exception("申请失败");
+        }
+        return AjaxResult.success("申请成功");
+    }
+
+    //批量更新分配记录状态
+    @PostMapping("/batchUpdate")
+    @Transactional(rollbackFor = Exception.class)
+    public AjaxResult batchUpdate(@RequestBody Long[] ids) throws Exception {
+        //校验ids是否为空
+        if (ids == null || ids.length == 0) {
+            return AjaxResult.error("ids不能为空");
+        }
+        //发起http请求
+        //调用ipad服务器更新接口
+        HashMap<Object, Object> param = new HashMap<>();
+        param.put("ids", ids);
+        String paramJson = JSON.toJSONString(param);
+        HttpRequest post = HttpUtil.createPost(ipadServerUrl + "/ipad/records/updateRecords");
+        post.body(paramJson);
+        post.header("Authorization", HMACAuth.generateToken());
+        //发起请求
+        String result = post.execute().body();
+
+        log.info("发起ipad服务器更新状态,更新数量:{},拉取结果:{}", ids.length, result);
+
+        //解析返回的JSON结果
+        AjaxResult response = JSON.parseObject(result, AjaxResult.class);
+
+        //首先判断code是否为200
+        if (response != null && (Integer) response.get("code") == 200) {
+            //获取data字段
+            Object data = response.get("data");
+
+            //将data转换为List<IpadAllocationRecordsVO>
+            List<IpadAllocationRecordsVO> recordsList = JSON.parseArray(JSON.toJSONString(data), IpadAllocationRecordsVO.class);
+
+            for (IpadAllocationRecordsVO vo : recordsList) {
+                IpadAllocationRecords ipadAllocationRecords = ipadAllocationRecordsMapper.selectById(vo.getId());
+                if (!ipadAllocationRecords.getAuditStatus().equals(0)) {
+                    ipadAllocationRecords.setServerJson(JSON.toJSONString(vo.getDetailsList()));
+                    ipadAllocationRecordsMapper.updateById(ipadAllocationRecords);
+                    log.info("分配记录id:{},状态已更新,无需重复更新", vo.getId());
+                    continue;
+                }
+                log.info("更新分配记录,记录id:{},更新状态:{},分配数量:{},审核时间:{},拒绝原因:{},公司名称:{}",
+                        vo.getId(), vo.getAuditStatus(), vo.getAllocatedQuantity(), vo.getReviewTime(), vo.getRejectionReason(), vo.getCompanyName());
+                if (ipadAllocationRecords != null) {
+                    ipadAllocationRecords.setAuditStatus(vo.getAuditStatus());
+                    ipadAllocationRecords.setUpdatedTime(LocalDateTime.now());
+                    ipadAllocationRecords.setAllocatedQuantity(vo.getAllocatedQuantity());
+                    ipadAllocationRecords.setReviewTime(vo.getReviewTime());
+                    ipadAllocationRecords.setRejectionReason(vo.getRejectionReason());
+                    ipadAllocationRecords.setCompanyName(vo.getCompanyName());
+                    ipadAllocationRecords.setServerJson(JSON.toJSONString(vo.getDetailsList()));
+                    ipadAllocationRecords.setRegion(vo.getRegion());
+                    ipadAllocationRecordsMapper.updateById(ipadAllocationRecords);
+                }
+                List<IpadAllocationDetails> detailsList = vo.getDetailsList();
+                for (IpadAllocationDetails details : detailsList) {
+                    //去查询是否有相同端口和ip的服务器,有则去更新total_count和count都加上allocatedSeats,没有则添加一条服务器记录。
+                    Integer allocatedSeats = details.getAllocatedSeats();
+                    QwIpadServer server = serverService.selectIpAndPort(details.getIpAddress(), details.getPort());
+                    if (server != null) {
+                        server.setTotalCount(server.getTotalCount() + allocatedSeats);
+                        server.setCount(server.getCount() + allocatedSeats);
+                        server.setUpdateTime(DateUtils.getNowDate());
+//                        server.setRecordId(details.getAllocationId());//后面的审核记录会覆盖之前的审核记录id,这里存的是最新的审核记录id
+                        serverService.updateById(server);
+                    } else {
+                        //添加一条服务器记录
+                        QwIpadServer newServer = new QwIpadServer();
+//                        newServer.setRecordId(details.getAllocationId());
+                        newServer.setIp(details.getIpAddress());
+                        newServer.setPort(String.valueOf(details.getPort()));
+                        newServer.setTotalCount(Long.valueOf(allocatedSeats));
+                        newServer.setCount(Long.valueOf(allocatedSeats));
+                        newServer.setAddressId("520000000000");
+                        newServer.setUrl(details.getAccessUrl());
+                        newServer.setCreateTime(DateUtils.getNowDate());
+                        serverService.getBaseMapper().insert(newServer);
+                    }
+                }
+            }
+
+            //返回成功结果
+            return AjaxResult.success("更新成功", recordsList);
+        } else {
+            //返回错误结果
+            String errorMsg = response != null ? (String) response.get("msg") : "更新失败";
+            return AjaxResult.error(errorMsg);
+        }
+    }
+
+    //释放已申请的ipad服务器
+    //释放哪条记录的那台服务器多少台
+    @PostMapping("/release")
+    @Transactional(rollbackFor = Exception.class)
+    public AjaxResult release(@RequestBody ServerParam serverParam) throws Exception {
+        //校验参数是否为空
+        if (serverParam == null) {
+            return AjaxResult.error("serverParam不能为空");
+        }
+
+        QwIpadServer server = serverService.selectIpAndPort(serverParam.getIpAddress(), Long.valueOf(serverParam.getPort()));
+        if (server == null) {
+            log.info("服务器地址:{},端口:{},未查询到服务器记录,无法释放", serverParam.getIpAddress(), serverParam.getPort());
+            return AjaxResult.error("未查询到服务器记录,无法释放");
+        }
+        if (serverParam.getReleaseCount() > server.getCount()) {
+            log.info("服务器id:{},释放数量:{},剩余数量:{},释放数量大于剩余数量,无法释放", server.getId(), serverParam.getReleaseCount(), server.getCount());
+            return AjaxResult.error("释放数量大于剩余数量,无法释放");
+        }
+        IpadAllocationRecords record = ipadAllocationRecordsMapper.selectById(serverParam.getRecordId());
+        if (record == null) {
+            log.info("服务器id:{},释放数量:{},申请记录为空,无法释放", server.getId(), serverParam.getReleaseCount());
+            return AjaxResult.error("申请记录为空,无法释放");
+        }
+        record.setAllocatedQuantity(record.getAllocatedQuantity() - serverParam.getReleaseCount());
+//        record.setApplyQuantity(record.getApplyQuantity() - serverParam.getReleaseCount());
+
+        server.setCount(server.getCount() - serverParam.getReleaseCount());
+        server.setTotalCount(server.getTotalCount() - serverParam.getReleaseCount());
+        ipadAllocationRecordsMapper.updateById(record);
+        serverService.updateById(server);
+
+        ServerParam build = ServerParam.builder()
+                .ipadServerId(serverParam.getIpadServerId())
+                .recordId(serverParam.getRecordId())
+                .releaseCount(serverParam.getReleaseCount())
+                .ipAddress(serverParam.getIpAddress())
+                .port(serverParam.getPort())
+                .build();
+
+        //发起http请求
+        String body = JSON.toJSONString(build);
+
+        HttpRequest post = HttpUtil.createPost(ipadServerUrl + "/ipad/records/release");
+        post.body(body);
+        post.header("Authorization", HMACAuth.generateToken());
+        //发起请求
+        String result = post.execute().body();
+        log.info("发起ipad服务器释放状态,释放数量:{},拉取结果:{}", body, result);
+
+        //解析返回的JSON结果
+        AjaxResult response = JSON.parseObject(result, AjaxResult.class);
+
+        //首先判断code是否为200,不是回滚事务
+        if (!response.get("code").equals(200)) {
+            String errorMsg = response != null ? (String) response.get("msg") : "释放失败";
+            throw new Exception(errorMsg);
+        }
+        return AjaxResult.success("释放成功");
+    }
+}

+ 138 - 0
fs-admin/src/main/java/com/fs/qw/controller/QwDeptController.java

@@ -0,0 +1,138 @@
+package com.fs.qw.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.qw.domain.QwDept;
+import com.fs.qw.mapper.QwCompanyMapper;
+import com.fs.qw.service.IQwDeptService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 企业微信部门Controller
+ *
+ * @author fs
+ * @date 2024-08-27
+ */
+@RestController
+@RequestMapping("/qw/qwDept")
+public class QwDeptController extends BaseController
+{
+    @Autowired
+    private IQwDeptService qwDeptService;
+
+
+    /**
+     * 查询企业微信部门列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwDept:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(QwDept qwDept)
+    {
+        startPage();
+        List<QwDept> list = qwDeptService.selectQwDeptList(qwDept);
+        return getDataTable(list);
+    }
+    @Autowired
+    QwCompanyMapper qwCompanyMapper;
+
+    /**
+     * 同步企业微信 部门信息
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwDept:list')")
+    @GetMapping("/syncDept/{companyId}")
+    public R syncDept(@PathVariable("companyId") Long companyId){
+
+        List<String> strings = qwCompanyMapper.selectQwCompanyCorpIdListByCompanyId(companyId);
+        for (String string : strings) {
+            qwDeptService.insertOrUpdateQwDept(string);
+        }
+
+        return  R.ok();
+    }
+
+    /**
+     * 导出企业微信部门列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwDept:export')")
+    @Log(title = "企业微信部门", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(QwDept qwDept)
+    {
+        List<QwDept> list = qwDeptService.selectQwDeptList(qwDept);
+        ExcelUtil<QwDept> util = new ExcelUtil<QwDept>(QwDept.class);
+        return util.exportExcel(list, "企业微信部门数据");
+    }
+
+    /**
+     * 获取企业微信部门详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwDept:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(qwDeptService.selectQwDeptById(id));
+    }
+
+    /**
+     * 新增企业微信部门
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwDept:add')")
+    @Log(title = "企业微信部门", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody QwDept qwDept)
+    {
+        return toAjax(qwDeptService.insertQwDept(qwDept));
+    }
+
+    /**
+     * 修改企业微信部门
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwDept:edit')")
+    @Log(title = "企业微信部门", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody QwDept qwDept)
+    {
+        return toAjax(qwDeptService.updateQwDept(qwDept));
+    }
+
+    /**
+     * 删除企业微信部门
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwDept:remove')")
+    @Log(title = "企业微信部门", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(qwDeptService.deleteQwDeptByIds(ids));
+    }
+
+    /**
+     * @Description: 获取企微部门 按Treeselect返回 每一个企微主体有自己的部门,按企微主体查询
+     * @Param:
+     * @Return:
+     * @Author xgb
+     * @Date 2025/10/30 9:33
+     */
+    @GetMapping("/treeselect")
+    public AjaxResult treeselect(QwDept qwDept)
+    {
+        if(StringUtils.isEmpty(qwDept.getCorpId())){
+            return AjaxResult.error("请选择企微主体");
+        }
+        List<QwDept> depts = qwDeptService.selectQwDeptList(qwDept);
+        return AjaxResult.success(qwDeptService.buildDeptTreeSelect(depts));
+    }
+
+}

+ 2 - 0
fs-admin/src/main/java/com/fs/qw/controller/QwSopTempController.java

@@ -1,5 +1,6 @@
 package com.fs.qw.controller;
 
+import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
@@ -9,6 +10,7 @@ import com.fs.common.core.domain.model.LoginUser;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.TimeUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.framework.web.service.TokenService;
 import com.fs.qw.vo.SortDayVo;

+ 309 - 5
fs-admin/src/main/java/com/fs/qw/controller/QwUserController.java

@@ -1,22 +1,48 @@
 package com.fs.qw.controller;
 
+import com.alibaba.fastjson.JSON;
+import com.fs.common.annotation.Log;
+import com.fs.common.annotation.RepeatSubmit;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.ServletUtils;
+import com.fs.company.domain.Company;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.mapper.CompanyUserMapper;
+import com.fs.company.service.ICompanyUserService;
+import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.domain.QwExternalContactTransferCompanyAudit;
+import com.fs.qw.domain.QwUser;
+import com.fs.qw.mapper.QwCompanyMapper;
+import com.fs.qw.mapper.QwExternalContactMapper;
 import com.fs.qw.param.QwFsUserParam;
+import com.fs.qw.param.QwUserBingParam;
+import com.fs.qw.param.QwUserListParam;
+import com.fs.qw.service.IQwDeptService;
 import com.fs.qw.service.IQwExternalContactTransferCompanyAuditService;
 import com.fs.qw.service.IQwUserService;
 import com.fs.qw.vo.QwOptionsVO;
+import com.fs.qw.vo.QwUserVO;
+import com.fs.qwApi.domain.QwExternalContactAllListResult;
+import com.fs.qwApi.domain.inner.ExternalContact;
+import com.fs.qwApi.domain.inner.ExternalContactInfo;
+import com.fs.qwApi.domain.inner.FollowInfo;
+import com.fs.qwApi.param.QwExternalListParam;
+import com.fs.qwApi.service.QwApiService;
+import com.fs.voice.utils.StringUtil;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
 
+import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * 企微用户Controller
@@ -29,8 +55,28 @@ import java.util.List;
 public class QwUserController extends BaseController {
     @Autowired
     private IQwUserService qwUserService;
+
     @Autowired
     private IQwExternalContactTransferCompanyAuditService auditService;
+
+    @Autowired
+    private ICompanyUserService companyUserService;
+
+    @Autowired
+    private CompanyUserMapper companyUserMapper;
+
+    @Autowired
+    private QwApiService qwApiService;
+
+    @Autowired
+    private QwCompanyMapper qwCompanyMapper;
+
+    @Autowired
+    private IQwDeptService qwDeptService;
+
+    @Autowired
+    private QwExternalContactMapper qwExternalContactMapper;
+
     @GetMapping("/getQwUserAll")
     public AjaxResult getQwUserAll(){
         return AjaxResult.success(qwUserService.getQwUserAll());
@@ -47,7 +93,265 @@ public class QwUserController extends BaseController {
    @GetMapping("/getMyQwCompanyList")
     public R getMyQwCompanyList()
     {
-        List<QwOptionsVO> list = qwUserService.selectQwCompanyListOptionsVOBySys();
+        List<QwOptionsVO> list = qwUserService.selectQwCompanyListOptionsVOAll();
         return  R.ok().put("data",list);
     }
+
+    /**
+     * 绑定企微用户
+     */
+    @PreAuthorize("@ss.hasPermi('qw:user:bind')")
+    @Log(title = "企微用户", businessType = BusinessType.UPDATE)
+    @PutMapping("/bindQwUser")
+    @RepeatSubmit
+    public R bindQwUser(@RequestBody QwUserBingParam qwUserParam)
+    {
+        CompanyUser companyUser = companyUserService.selectCompanyUserById(qwUserParam.getCompanyUserId());
+
+        String qwUserIdCompanyStr = companyUser.getQwUserId();
+        Set<String> qwUserIdCompanySet = new HashSet<>();
+        if (!StringUtil.strIsNullOrEmpty(qwUserIdCompanyStr)) {
+            String[] qwUserId = qwUserIdCompanyStr.split(",");
+            qwUserIdCompanySet = Arrays.stream(qwUserId)
+                    .filter(id -> !id.isEmpty())
+                    .collect(Collectors.toSet());
+        }
+
+        if (companyUser!=null){
+
+            //选择的企业微信账号为“”
+            if (StringUtil.strIsNullOrEmpty(qwUserParam.getId())&&qwUserParam.getCompanyUserId()!=null){
+                //制空企业微信的绑定
+                qwUserService.updateUserByUserId(qwUserParam.getCompanyUserId());
+
+                //制空销售的绑定
+                companyUserMapper.updateCompanyUserByNullQwUserID(companyUser.getUserId());
+
+            }else {
+                String idParam = qwUserParam.getId();
+                String[] splitParam = idParam.split(",");
+                Set<String> splitParamSet = Arrays.stream(splitParam)
+                        .filter(s -> !s.isEmpty())
+                        .collect(Collectors.toSet());
+
+                // 找出在 qwUserIdCompanySet 中存在但在 splitParamSet 中不存在的元素
+                Set<String> difference = new HashSet<>(qwUserIdCompanySet);
+                difference.removeAll(splitParamSet);
+
+                //制空绑定
+                if (!difference.isEmpty()){
+                    difference.forEach(id->{
+                        qwUserService.updateUnBindUserById(id);
+                    });
+
+                }
+
+
+                for (String paramId : splitParamSet) {
+                    QwUser qu= qwUserService.selectQwUserById(Long.parseLong(paramId));
+                    if (qu.getCompanyUserId()!=null&&!qu.getCompanyUserId().equals(qwUserParam.getCompanyUserId())){
+                        return R.error( qu.getQwUserName()+"已经被其他人绑定,请先解绑");
+                    }
+
+
+                    CompanyUser user = new CompanyUser();
+                    user.setQwUserId(qwUserParam.getId());
+                    user.setUserId(companyUser.getUserId());
+                    user.setQwStatus(1);
+                    companyUserMapper.updateCompanyUser(user);
+
+
+
+                    qu.setCompanyUserId(qwUserParam.getCompanyUserId());
+                    qu.setStatus(1);
+                    qu.setCompanyId(companyUser.getCompanyId());
+                    qwUserService.updateQwUser(qu);
+
+                }
+
+                //同步最后单独跑/先不异步了pp
+                for (String paramId : splitParamSet){
+
+                    //如果销售没绑定过,全刷,否则只同步新的增加的
+                    if (StringUtil.strIsNullOrEmpty(qwUserIdCompanyStr)){
+                        updateAndSyncQwUser(paramId, companyUser);
+
+                    }
+                    else if (!StringUtil.strIsNullOrEmpty(qwUserIdCompanyStr) && !qwUserIdCompanySet.contains(paramId)){
+                        updateAndSyncQwUser(paramId, companyUser);
+                    }
+                }
+            }
+
+
+            return R.ok();
+        }
+        return R.error("绑定失败");
+
+    }
+
+
+    private void updateAndSyncQwUser(String paramId, CompanyUser companyUser) {
+
+        QwUser qu= qwUserService.selectQwUserById(Long.parseLong(paramId));
+
+        qwExternalContactMapper.updateBindUserByQwUser(qu.getCorpId(),qu.getQwUserId(),companyUser.getCompanyId(),companyUser.getUserId());
+
+        //根据企微账号和公司id 同步企业微信账号(游标初始为空)
+        syncMyQwExternalContact(qu,null);
+    }
+
+    public R  syncMyQwExternalContact(QwUser qwUser,String getNextCursor )  {
+
+        String qwUserId = qwUser.getQwUserId();
+        String corpId = qwUser.getCorpId();
+        Long companyId = qwUser.getCompanyId();
+
+        QwExternalListParam param = new QwExternalListParam();
+        param.setLimit(100);
+        param.setUserid_list(Arrays.asList(qwUserId));
+        param.setCursor(getNextCursor);
+
+        QwExternalContactAllListResult list = qwApiService.getAllExternalcontactList(param, corpId);
+
+        logger.info("批量获取客户详情" + list);
+
+        if (list.getErrcode() == 0) {
+            List<ExternalContactInfo> externalContactList = list.getExternal_contact_list();
+            for (ExternalContactInfo externalContactInfo : externalContactList) {
+
+                ExternalContact externalContact = externalContactInfo.getExternal_contact();
+                FollowInfo followInfo = externalContactInfo.getFollow_info();
+                QwExternalContact qwExternalContact = qwExternalContactMapper.selectQwExternalContactUserIdAndExternalIdAndCompanyId(externalContact.getExternal_userid(), qwUserId, corpId);
+                logger.info("客户详情" + qwExternalContact);
+
+                if (qwExternalContact == null) {
+                    qwExternalContact = new QwExternalContact();
+                    qwExternalContact.setUserId(qwUserId); // 设置属于用户ID
+                    qwExternalContact.setExternalUserId(externalContact.getExternal_userid()); // 设置外部联系人ID
+
+
+                    qwExternalContact.setCorpId(corpId); // 设置企业ID
+                    qwExternalContact.setCompanyId(companyId); // 设置公司ID
+                }
+
+
+                // 设置公共属性
+                qwExternalContact.setCompanyUserId(qwUser.getCompanyUserId());
+                qwExternalContact.setQwUserId(qwUser.getId());
+                qwExternalContact.setName(externalContact.getName()); // 设置名称
+                qwExternalContact.setAvatar(externalContact.getAvatar()); // 设置头像
+                qwExternalContact.setType(externalContact.getType()); // 设置外部联系人类型(1微信用户,2企业微信用户)
+                qwExternalContact.setGender(externalContact.getGender()); // 设置性别 (0-未知, 1-男性, 2-女性)
+                qwExternalContact.setDescription(followInfo.getDescription()); // 设置描述信息
+                qwExternalContact.setRemark(followInfo.getRemark());
+
+//                        if (followInfo.getTag_id() != null && !followInfo.getTag_id().isEmpty()) {
+                qwExternalContact.setTagIds(JSON.toJSONString(followInfo.getTag_id())); // 设置标签ID
+//                        }
+
+//                        if (followInfo.getRemark_mobiles() != null && !followInfo.getRemark_mobiles().isEmpty()) {
+                qwExternalContact.setRemarkMobiles(JSON.toJSONString(followInfo.getRemark_mobiles())); // 设置备注电话号码
+//                        }
+
+                qwExternalContact.setState(followInfo.getState());
+
+                if (followInfo.getState() != null && !followInfo.getState().isEmpty()) {
+                    String s = "way:" + corpId + ":";
+                    if (followInfo.getState().contains(s)) {
+                        String wayId = followInfo.getState().substring(followInfo.getState().indexOf(s) + s.length());
+                        qwExternalContact.setWayId(Long.parseLong(wayId));
+                    }
+                }
+
+                qwExternalContact.setRemarkCorpName(followInfo.getRemark_corp_name()); // 设置备注企业名称
+                qwExternalContact.setAddWay(followInfo.getAdd_way()); // 设置来源
+                qwExternalContact.setOperUserid(followInfo.getOper_userid()); // 设置oper用户ID
+
+                // 根据是否存在记录进行更新或插入
+                if (qwExternalContact.getId() != null) {
+                    qwExternalContactMapper.updateQwExternalContact(qwExternalContact);
+                } else {
+                    qwExternalContactMapper.insertQwExternalContact(qwExternalContact);
+                }
+            }
+
+        }else {
+            return R.error("同步失败:"+list.getErrmsg());
+        }
+
+        if (!StringUtil.strIsNullOrEmpty(list.getNext_cursor())){
+            syncMyQwExternalContact(qwUser,list.getNext_cursor());
+        }
+        return R.ok();
+    }
+
+
+    /**
+     * 同步企微用户
+     */
+    @RepeatSubmit
+    @PreAuthorize("@ss.hasPermi('qw:user:sync')")
+    @Log(title = "企微用户", businessType = BusinessType.INSERT)
+    @PostMapping("sync/{corpId}")
+    public R sync(@PathVariable("corpId") String corpId)
+    {
+
+        List<String> strings = qwCompanyMapper.selectQwCompanyCorpIdListByAll();
+        for (String string : strings) {
+
+            if (string.equals(corpId)){
+                qwUserService.syncQwUser(string);
+                qwDeptService.insertOrUpdateQwDept(string);
+                logger.info("同步完成");
+            }
+        }
+        return R.ok();
+    }
+
+    /**
+     * 获取企微用户详细信息
+     */
+
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(qwUserService.selectQwUserVOById(id));
+    }
+    /**
+     * 批量查询 企微用户详细信息
+     */
+    @GetMapping(value = "/getInfo/{ids}")
+    public AjaxResult getInfoByIds(@PathVariable("ids") Long[] ids)
+    {
+        return AjaxResult.success(qwUserService.selectQwUserVOByIds(ids));
+    }
+
+    @RepeatSubmit
+    @PreAuthorize("@ss.hasPermi('qw:user:sync')")
+    @Log(title = "同步企微用户名称", businessType = BusinessType.INSERT)
+    @PostMapping("syncName/{corpId}")
+    public R syncName(@PathVariable("corpId") String corpId)
+    {
+        List<String> strings = qwCompanyMapper.selectQwCompanyCorpIdListByAll();
+        for (String string : strings) {
+            if (string.equals(corpId)){
+                qwUserService.syncQwUserName(string);
+            }
+        }
+        return R.ok();
+    }
+
+
+    /**
+     * 查询企微用户列表
+     */
+
+    @GetMapping("/userList")
+    public TableDataInfo userList(QwUserListParam qwUser)
+    {
+        startPage();
+        List<QwUserVO> list = qwUserService.selectAllQwUserListVO(qwUser);
+        return getDataTable(list);
+    }
 }

+ 93 - 6
fs-admin/src/main/java/com/fs/qw/qwTask/qwTask.java

@@ -1,21 +1,24 @@
 package com.fs.qw.qwTask;
 
 import com.fs.course.service.IFsUserCourseService;
-import com.fs.qw.service.IQwExternalContactService;
-import com.fs.qw.service.IQwGroupMsgService;
-import com.fs.qw.service.IQwMaterialService;
-import com.fs.qw.service.IQwUserService;
+import com.fs.qw.domain.QwIpadServerLog;
+import com.fs.qw.domain.QwUser;
+import com.fs.qw.mapper.QwUserMapper;
+import com.fs.qw.service.*;
 import com.fs.sop.service.impl.QwSopLogsServiceImpl;
 import com.fs.sop.service.impl.QwSopServiceImpl;
 import com.fs.sop.service.ISopUserLogsService;
 import com.fs.statis.IFsStatisQwWatchService;
 import com.fs.statis.service.FsStatisSalerWatchService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import com.fs.wxwork.dto.WxWorkGetQrCodeDTO;
+import com.fs.wxwork.service.WxWorkService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
 import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.Date;
+import java.util.List;
 
 @Component("qwTask")
 public class qwTask {
@@ -51,6 +54,25 @@ public class qwTask {
     private IQwMaterialService iQwMaterialService;
 
 
+    @Autowired
+    private QwUserMapper qwUserMapper;
+
+    @Autowired
+    private IQwIpadServerService ipadServerService;
+
+    @Autowired
+    private IQwIpadServerLogService qwIpadServerLogService;
+
+    @Autowired
+    private IQwIpadServerUserService qwIpadServerUserService;
+
+    @Autowired
+    private IQwExternalContactService externalContactService;
+
+    @Autowired
+    private WxWorkService wxWorkService;
+
+
     //正在使用
     public void qwExternalContact()
     {
@@ -199,4 +221,69 @@ public class qwTask {
     public void updateMaterialByTwoDays(){
         iQwMaterialService.updateQwMaterialByQw();
     }
+
+    /**
+     * 统计 每天的官方群发统计
+     */
+    public void countQwApiAopLogToken(){
+        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        // 获取当前日期(只包含年月日)
+        LocalDate currentDate = LocalDate.now();
+
+        String todayStr = currentDate.format(dateFormatter);
+         qwSopLogsService.countQwApiAopLogToken(todayStr);
+
+
+    }
+
+    /**
+     * 定时清除 占着茅坑不拉屎的ipad 账号
+     */
+    public void selectQwUserByUnbindIpad(){
+        List<QwUser> list = qwUserMapper.selectQwUserByTest();
+        for (QwUser qwUser : list) {
+            try {
+                Integer serverStatus = qwUser.getServerStatus();
+                Long serverId = qwUser.getServerId();
+                if (serverStatus==0){
+                    System.out.println("不需要解绑");
+                }
+                if (serverId==null){
+                    System.out.println("serverId不存在");
+                }
+                QwUser u = new QwUser();
+                u.setId(qwUser.getId());
+                u.setServerId(null);
+                u.setServerStatus(0);
+                qwUserMapper.updateQwUser(u);
+                ipadServerService.addServer(serverId);
+                QwIpadServerLog qwIpadServerLog = new QwIpadServerLog();
+                qwIpadServerLog.setType(2);
+                qwIpadServerLog.setTilie("解绑");
+                qwIpadServerLog.setServerId(serverId);
+                qwIpadServerLog.setQwUserId(qwUser.getId());
+                qwIpadServerLog.setCompanyUserId(qwUser.getCompanyUserId());
+                qwIpadServerLog.setCompanyId(qwUser.getCompanyId());
+                qwIpadServerLog.setCreateTime(new Date());
+                qwIpadServerLogService.insertQwIpadServerLog(qwIpadServerLog);
+                qwIpadServerUserService.deleteQwIpadServerUserByQwUserId(qwUser.getId());
+                WxWorkGetQrCodeDTO wxWorkGetQrCodeDTO = new WxWorkGetQrCodeDTO();
+                wxWorkGetQrCodeDTO.setUuid(qwUser.getUid());
+                wxWorkService.LoginOut(wxWorkGetQrCodeDTO,qwUser.getServerId());
+                updateIpadStatus(qwUser.getId(),0);
+            } catch (Exception e) {
+                System.out.println("解绑ipad报错"+e);
+
+            }
+        }
+    }
+
+
+    void updateIpadStatus(Long id ,Integer status){
+        QwUser u = new QwUser();
+        u.setId(id);
+        u.setIpadStatus(status);
+        qwUserMapper.updateQwUser(u);
+    }
+
 }

+ 51 - 25
fs-admin/src/main/java/com/fs/task/FsCompanyTask.java

@@ -3,6 +3,8 @@ package com.fs.task;
 import com.fs.common.constant.FsConstants;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.company.domain.Company;
+import com.fs.company.domain.CompanyMoneyLogs;
+import com.fs.company.mapper.CompanyMoneyLogsMapper;
 import com.fs.company.service.ICompanyService;
 import com.fs.company.vo.RedPacketMoneyVO;
 import com.fs.course.mapper.FsCourseRedPacketLogMapper;
@@ -29,6 +31,9 @@ public class FsCompanyTask {
     @Autowired
     private RedisTemplate<String, Object> redisTemplate;
 
+    @Autowired
+    private CompanyMoneyLogsMapper moneyLogsMapper;
+
     public void refreshCompanyMoney() {
         LocalDateTime now = LocalDateTime.now();
         // 获取上一个小时的开始时间
@@ -49,38 +54,59 @@ public class FsCompanyTask {
      * 同步公司缓存余额到公司数据表
      */
     public void syncRedisCompanyMoneyToDB(){
-            // 获取所有的公司余额key
-            String companyMoneyKeyAll = FsConstants.COMPANY_MONEY_KEY + "*";
-            Collection<String> keys = redisCache.keys(companyMoneyKeyAll);
+        // 获取所有的公司余额key
+        String companyMoneyKeyAll = FsConstants.COMPANY_MONEY_KEY + "*";
+        Collection<String> keys = redisCache.keys(companyMoneyKeyAll);
 
-            if (keys != null && !keys.isEmpty()) {
-                log.info("同步缓存余额到公司表,keys:{}", keys);
-                List<Object> values = redisTemplate.opsForValue().multiGet(keys);
-                Iterator<String> keyIterator = keys.iterator();
-                if(values != null && !values.isEmpty()){
-                    Iterator<Object> valueIterator = values.iterator();
-                    List<Company> companies = companyService.selectCompanyList(new Company());
+        if (keys != null && !keys.isEmpty()) {
+            log.info("同步缓存余额到公司表,keys:{}", keys);
+            List<Object> values = redisTemplate.opsForValue().multiGet(keys);
+            Iterator<String> keyIterator = keys.iterator();
+            if(values != null && !values.isEmpty()){
+                Iterator<Object> valueIterator = values.iterator();
+                List<Company> companies = companyService.selectCompanyList(new Company());
+
+                Map<Long, BigDecimal> moneyMap = new HashMap<>();
+                while (keyIterator.hasNext() && valueIterator.hasNext()) {
+                    String next = keyIterator.next();
+                    String[] keySplit = next.split(":");
+                    Long companyId = Long.parseLong(keySplit[2]);
+                    String value = valueIterator.next().toString();
+                    moneyMap.put(companyId, new BigDecimal(value));
+                }
 
-                    Map<Long, BigDecimal> moneyMap = new HashMap<>();
-                    while (keyIterator.hasNext() && valueIterator.hasNext()) {
-                        String next = keyIterator.next();
-                        String[] keySplit = next.split(":");
-                        Long companyId = Long.parseLong(keySplit[2]);
-                        String value = valueIterator.next().toString();
-                        moneyMap.put(companyId, new BigDecimal(value));
+                // 新增账户流水
+                // 直接循环保存,由于是定时任务执行,暂时不优化
+                for (Company company : companies) {
+                    if(moneyMap.containsKey(company.getCompanyId()) && !(moneyMap.get(company.getCompanyId()).compareTo(company.getMoney()) == 0)){
+                        CompanyMoneyLogs log = new CompanyMoneyLogs();
+                        log.setCompanyId(company.getCompanyId());
+                        log.setRemark("扣除红包金额-同步");
+                        // 让减出来的金额为负数
+                        if(moneyMap.get(company.getCompanyId()).compareTo(company.getMoney()) <= 0 ){
+                            log.setMoney(moneyMap.get(company.getCompanyId()).subtract(company.getMoney()));
+                        } else {
+                            log.setMoney(company.getMoney().subtract(moneyMap.get(company.getCompanyId())));
+                        }
+                        log.setLogsType(15);
+                        log.setBalance(moneyMap.get(company.getCompanyId()));
+                        log.setCreateTime(new Date());
+                        moneyLogsMapper.insertCompanyMoneyLogs(log);
                     }
+                }
 
-                    // 使用Stream进行匹配赋值
-                    List<Company> collect = companies.stream()
-                            .filter(company -> moneyMap.containsKey(company.getCompanyId()))
-                            .peek(company -> company.setMoney(moneyMap.get(company.getCompanyId()))).collect(Collectors.toList());
+                // 使用Stream进行匹配赋值
+                List<Company> collect = companies.stream()
+                        .filter(company -> moneyMap.containsKey(company.getCompanyId()))
+                        .peek(company -> company.setMoney(moneyMap.get(company.getCompanyId()))).collect(Collectors.toList());
 
-                    // 保存公司余额
-                    if(!collect.isEmpty()){
-                        companyService.batchUpdateCompany(collect);
-                    }
+                // 保存公司余额
+                if(!collect.isEmpty()){
+                    companyService.batchUpdateCompany(collect);
                 }
+
             }
+        }
 
     }
 }

+ 30 - 39
fs-admin/src/main/java/com/fs/web/controller/system/SysConfigController.java

@@ -30,13 +30,10 @@ import com.fs.system.service.ISysConfigService;
 
 /**
  * 参数配置 信息操作处理
- *
-
  */
 @RestController
 @RequestMapping("/system/config")
-public class SysConfigController extends BaseController
-{
+public class SysConfigController extends BaseController {
     @Autowired
     private ISysConfigService configService;
     @Autowired
@@ -47,8 +44,7 @@ public class SysConfigController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('system:config:list')")
     @GetMapping("/list")
-    public TableDataInfo list(SysConfig config)
-    {
+    public TableDataInfo list(SysConfig config) {
         startPage();
         List<SysConfig> list = configService.selectConfigList(config);
         return getDataTable(list);
@@ -57,8 +53,7 @@ public class SysConfigController extends BaseController
     @Log(title = "参数管理", businessType = BusinessType.EXPORT)
     @PreAuthorize("@ss.hasPermi('system:config:export')")
     @GetMapping("/export")
-    public AjaxResult export(SysConfig config)
-    {
+    public AjaxResult export(SysConfig config) {
         List<SysConfig> list = configService.selectConfigList(config);
         ExcelUtil<SysConfig> util = new ExcelUtil<SysConfig>(SysConfig.class);
         return util.exportExcel(list, "参数数据");
@@ -69,8 +64,7 @@ public class SysConfigController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('system:config:query')")
     @GetMapping(value = "/{configId}")
-    public AjaxResult getInfo(@PathVariable Long configId)
-    {
+    public AjaxResult getInfo(@PathVariable Long configId) {
         return AjaxResult.success(configService.selectConfigById(configId));
     }
 
@@ -78,8 +72,7 @@ public class SysConfigController extends BaseController
      * 根据参数键名查询参数值
      */
     @GetMapping(value = "/configKey/{configKey}")
-    public AjaxResult getConfigKey(@PathVariable String configKey)
-    {
+    public AjaxResult getConfigKey(@PathVariable String configKey) {
         return AjaxResult.success(configService.selectConfigByKey(configKey));
     }
 
@@ -90,10 +83,8 @@ public class SysConfigController extends BaseController
     @Log(title = "参数管理", businessType = BusinessType.INSERT)
     @PostMapping
     @RepeatSubmit
-    public AjaxResult add(@Validated @RequestBody SysConfig config)
-    {
-        if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config)))
-        {
+    public AjaxResult add(@Validated @RequestBody SysConfig config) {
+        if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config))) {
             return AjaxResult.error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在");
         }
         config.setCreateBy(getUsername());
@@ -106,10 +97,8 @@ public class SysConfigController extends BaseController
     @PreAuthorize("@ss.hasPermi('system:config:edit')")
     @Log(title = "参数管理", businessType = BusinessType.UPDATE)
     @PutMapping
-    public AjaxResult edit(@Validated @RequestBody SysConfig config)
-    {
-        if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config)))
-        {
+    public AjaxResult edit(@Validated @RequestBody SysConfig config) {
+        if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config))) {
             return AjaxResult.error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在");
         }
         config.setUpdateBy(getUsername());
@@ -122,8 +111,7 @@ public class SysConfigController extends BaseController
     @PreAuthorize("@ss.hasPermi('system:config:remove')")
     @Log(title = "参数管理", businessType = BusinessType.DELETE)
     @DeleteMapping("/{configIds}")
-    public AjaxResult remove(@PathVariable Long[] configIds)
-    {
+    public AjaxResult remove(@PathVariable Long[] configIds) {
         configService.deleteConfigByIds(configIds);
         return success();
     }
@@ -134,50 +122,53 @@ public class SysConfigController extends BaseController
     @PreAuthorize("@ss.hasPermi('system:config:remove')")
     @Log(title = "参数管理", businessType = BusinessType.CLEAN)
     @DeleteMapping("/refreshCache")
-    public AjaxResult refreshCache()
-    {
+    public AjaxResult refreshCache() {
         configService.resetConfigCache();
         return AjaxResult.success();
     }
 
     @GetMapping(value = "/getConfigByKey/{configKey}")
-    public AjaxResult getConfigByKey(@PathVariable String configKey)
-    {
-        SysConfig config=configService.selectConfigByConfigKey(configKey);
+    public AjaxResult getConfigByKey(@PathVariable String configKey) {
+        SysConfig config = configService.selectConfigByConfigKey(configKey);
         return AjaxResult.success(config);
     }
 
     @PostMapping(value = "/updateConfigByKey")
     @Log(title = "更改参数", businessType = BusinessType.UPDATE)
     @RepeatSubmit
-    public AjaxResult updateConfigByKey(@Validated @RequestBody SysConfig config)
-    {
+    public AjaxResult updateConfigByKey(@Validated @RequestBody SysConfig config) {
         config.setCreateBy(SecurityUtils.getUsername());
-        return toAjax(configService.updateConfig(config));
+        //修复只能更新的BUG
+        if (null != config.getConfigId()) {
+            return toAjax(configService.updateConfig(config));
+        } else {
+            return toAjax(configService.insertConfig(config));
+        }
+
     }
 
 
     /**
      * 启用-关闭小程序销售管理
+     *
      * @param bock
      * @return
      */
     @GetMapping("/updateIsTownOn")
-    public R queryIsTownOn(String bock, String appId)
-    {
-        String key = appId+"start_status_001";
+    public R queryIsTownOn(String bock, String appId) {
+        String key = appId + "start_status_001";
         String start = redisCache.getCacheObject(key);
-        if (ObjectUtil.isNotEmpty(bock)){
-            if (bock.equals("001")){
-                redisCache.setCacheObject(key,bock);
+        if (ObjectUtil.isNotEmpty(bock)) {
+            if (bock.equals("001")) {
+                redisCache.setCacheObject(key, bock);
                 return R.ok("调整成功");
-            }else if (bock.equals("002")){
-                redisCache.setCacheObject(key,bock);
+            } else if (bock.equals("002")) {
+                redisCache.setCacheObject(key, bock);
                 return R.ok("调整成功");
             }
 
         }
-        return R.ok().put("date",start);
+        return R.ok().put("date", start);
     }
 
 }

+ 0 - 37
fs-admin/src/test/java/com/fs/api/controller/IndexStatisticsControllerTest.java

@@ -1,37 +0,0 @@
-package com.fs.api.controller;
-
-import com.fs.FSApplication;
-import com.fs.common.core.domain.R;
-import com.fs.statis.dto.AnalysisPreviewQueryDTO;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.junit.jupiter.api.Test;
-import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
-
-import static org.junit.jupiter.api.Assertions.*;
-
-@RunWith(SpringRunner.class)
-@SpringBootTest(classes = FSApplication.class)
-@RequiredArgsConstructor
-@Slf4j
-public class IndexStatisticsControllerTest {
-
-    @Autowired
-    private IndexStatisticsController indexStatisticsController;
-
-    @Test
-    public void analysisPreview() {
-        AnalysisPreviewQueryDTO dto = new AnalysisPreviewQueryDTO();
-        dto.setCompanyId(null);
-        dto.setDeptId(1L);
-        dto.setEndTime("2025-10-31 23:59:59");
-        dto.setStartTime("2025-10-01 00:00:00");
-        dto.setType(4);
-        dto.setUserType(1);
-        R r = indexStatisticsController.analysisPreview(dto);
-        log.info("r: {}",r);
-    }
-}

+ 1 - 0
fs-common/src/main/java/com/fs/common/constant/FsConstants.java

@@ -14,6 +14,7 @@ public interface FsConstants {
 
     // 公司余额redis key "company:money:" + company.getCompanyId()
     String COMPANY_MONEY_KEY = "company:money:";
+    String COMPANY_MONEY_DATE_KEY = "company:money:date:";
     // 公司余额redis 锁
     String COMPANY_MONEY_LOCK = "company_money_lock:";
     // 看客统计  按公司分组 按TimeType 0-今天,1-昨天,2-本周,3-本月,4-上月;

+ 34 - 0
fs-common/src/main/java/com/fs/common/constant/LiveKeysConstant.java

@@ -0,0 +1,34 @@
+package com.fs.common.constant;
+
+public class LiveKeysConstant {
+
+    public static final String USER_VISIT_KEY = "live:user:visit:";  // 用户访问标识用于判断是否是首次访问
+    public static final String UNIQUE_VISITORS_KEY = "live:unique:visitors:";  //访客数
+    public static final String UNIQUE_VIEWERS_KEY = "live:unique:viewers:";  //累计观看人数
+    public static final String PAGE_VIEWS_KEY = "live:page:views:";  //浏览量
+    public static final String TOTAL_VIEWS_KEY = "live:total:views:";  //累计观看人次
+    public static final String MAX_ONLINE_USERS_KEY = "live:max:online:"; //最大在线人数
+    public static final String ONLINE_USERS_KEY = "live:online:users:";  //当前在线人数
+    public static final String ONLINE_USERS_SET_KEY = "live:online:users:set:";  //在线用户Set(用于统计最大同时在线人数)
+
+
+    public static final String LIVE_HOME_PAGE_LIST = "live:homePage:list"; //直播列表数据
+    public static final Integer LIVE_HOME_PAGE_LIST_EXPIRE = 300; //首页缓存过期时间
+    public static final String LIVE_WATCH_USERS = "live:watch:users:%s"; //在线人数
+    public static final String LIVE_COUPON_NUM = "live:coupon:num:%s"; //直播间优惠券数量
+
+    public static final String LIVE_HOME_PAGE_DETAIL = "live:detail:%s"; //直播间详情
+    public static final Integer LIVE_HOME_PAGE_DETAIL_EXPIRE = 300; //直播间详情过期时间
+
+    public static final String LIVE_HOME_PAGE_CONFIG = "live:config:%s:%s"; //直播间配置信息
+    public static final Integer LIVE_HOME_PAGE_CONFIG_EXPIRE = 300; //直播间配置信息过期时间
+    public static final String LIVE_HOME_PAGE_CONFIG_RED = "live:config:%s:red:%s"; //红包记录
+    public static final String LIVE_HOME_PAGE_CONFIG_COUPON = "live:config:%s:coupon:%s"; //优惠券记录
+    public static final String LIVE_HOME_PAGE_CONFIG_DRAW = "live:config:%s:draw:%s"; //抽奖记录
+    public static final String TOP_MSG = "topMsg"; //抽奖记录
+
+    public static final String LIVE_FLAG_CACHE = "live:flag:%s"; //直播间直播/回放状态缓存
+    public static final Integer LIVE_FLAG_CACHE_EXPIRE = 300; //直播间状态缓存过期时间(秒)
+
+
+}

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