Selaa lähdekoodia

Merge branch 'master' into 企微聊天

ct 1 päivä sitten
vanhempi
commit
a88f27c36f
42 muutettua tiedostoa jossa 324 lisäystä ja 42 poistoa
  1. 1 0
      fs-admin/src/main/java/com/fs/his/task/Task.java
  2. 1 0
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStorePaymentScrmController.java
  3. 1 0
      fs-admin/src/main/java/com/fs/hisStore/task/LiveTask.java
  4. 28 0
      fs-company/src/main/java/com/fs/company/controller/live/LiveMixLiuTestOpenController.java
  5. 1 0
      fs-company/src/main/java/com/fs/framework/config/SecurityConfig.java
  6. 3 1
      fs-company/src/main/java/com/fs/hisStore/controller/FsStoreOrderScrmController.java
  7. 25 4
      fs-company/src/main/java/com/fs/user/FsUserAdminController.java
  8. 95 0
      fs-live-app/src/main/java/com/fs/live/websocket/service/WebSocketServer.java
  9. 3 0
      fs-service/src/main/java/com/fs/his/service/IFsUserService.java
  10. 1 0
      fs-service/src/main/java/com/fs/his/service/impl/FsStorePaymentServiceImpl.java
  11. 39 0
      fs-service/src/main/java/com/fs/his/service/impl/FsUserServiceImpl.java
  12. 1 1
      fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreAfterSalesScrmMapper.java
  13. 1 1
      fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderItemExportRefundZMVO.java
  14. 1 1
      fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderItemExportVO.java
  15. 1 1
      fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderItemExportZMVO.java
  16. 1 1
      fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderPromotionExportVO.java
  17. 1 1
      fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderVO.java
  18. 1 1
      fs-service/src/main/java/com/fs/hisStore/vo/FsStoreProductExportVO.java
  19. 12 0
      fs-service/src/main/java/com/fs/huifuPay/sdk/opps/core/request/V2TradePaymentScanpayQueryRequest.java
  20. 13 1
      fs-service/src/main/java/com/fs/huifuPay/service/impl/HuiFuServiceImpl.java
  21. 1 1
      fs-service/src/main/java/com/fs/live/domain/LiveOrder.java
  22. 1 1
      fs-service/src/main/java/com/fs/live/param/LiveOrderSearchParam.java
  23. 10 0
      fs-service/src/main/java/com/fs/live/service/ILiveCompletionPointsRecordService.java
  24. 8 0
      fs-service/src/main/java/com/fs/live/service/impl/LiveCompletionPointsRecordServiceImpl.java
  25. 7 4
      fs-service/src/main/java/com/fs/live/service/impl/LiveOrderServiceImpl.java
  26. 32 0
      fs-service/src/main/java/com/fs/live/service/impl/LiveServiceImpl.java
  27. 8 1
      fs-service/src/main/java/com/fs/live/service/impl/LiveWatchUserServiceImpl.java
  28. 1 1
      fs-service/src/main/java/com/fs/live/vo/LiveOrderListVo.java
  29. 1 1
      fs-service/src/main/java/com/fs/live/vo/LiveOrderVoZm.java
  30. 1 1
      fs-service/src/main/java/com/fs/live/vo/MergedOrderExportVO.java
  31. 1 1
      fs-service/src/main/java/com/fs/store/vo/FsStoreProductScrmExportVO.java
  32. 3 0
      fs-service/src/main/java/com/fs/store/vo/h5/FsUserPageListVO.java
  33. 1 1
      fs-service/src/main/resources/application-config-druid-bjzm.yml
  34. 2 2
      fs-service/src/main/resources/application-config-druid-hcl.yml
  35. 2 2
      fs-service/src/main/resources/application-config-druid-hzyy.yml
  36. 2 2
      fs-service/src/main/resources/application-config-druid-jzzx.yml
  37. 2 2
      fs-service/src/main/resources/application-config-druid-sczy.yml
  38. 5 5
      fs-service/src/main/resources/application-druid-shdn.yml
  39. 2 1
      fs-service/src/main/resources/mapper/MerchantAppConfigMapper.xml
  40. 2 1
      fs-service/src/main/resources/mapper/his/FsUserMapper.xml
  41. 1 1
      fs-service/src/main/resources/mapper/live/LiveAfterSalesMapper.xml
  42. 1 1
      fs-store/src/main/java/com/fs/store/vo/FsStoreProductStoreExcelVO.java

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

@@ -1155,6 +1155,7 @@ public class Task {
                 V2TradePaymentScanpayQueryRequest request = new V2TradePaymentScanpayQueryRequest();
                 request.setOrgReqDate(new SimpleDateFormat("yyyyMMdd").format(payment.getCreateTime()));
                 request.setOrgHfSeqId(payment.getTradeNo());
+                request.setAppId(payment.getAppId());
                 HuiFuQueryOrderResult o = null;
                 try {
                     o = huiFuService.queryOrder(request);

+ 1 - 0
fs-admin/src/main/java/com/fs/hisStore/controller/FsStorePaymentScrmController.java

@@ -135,6 +135,7 @@ public class FsStorePaymentScrmController extends BaseController
             V2TradePaymentScanpayQueryRequest request = new V2TradePaymentScanpayQueryRequest();
             request.setOrgReqDate(new SimpleDateFormat("yyyyMMdd").format(payment.getCreateTime()));
             request.setOrgHfSeqId(payment.getTradeNo());
+            request.setAppId(payment.getAppId());
             HuiFuQueryOrderResult o = null;
             try {
                 o = huiFuService.queryOrder(request);

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

@@ -266,6 +266,7 @@ public class LiveTask {
                 V2TradePaymentScanpayQueryRequest request = new V2TradePaymentScanpayQueryRequest();
                 request.setOrgReqDate(new SimpleDateFormat("yyyyMMdd").format(payment.getCreateTime()));
                 request.setOrgHfSeqId(payment.getTradeNo());
+                request.setAppId(payment.getAppId());
                 HuiFuQueryOrderResult o = null;
                 try {
                     o = huiFuService.queryOrder(request);

+ 28 - 0
fs-company/src/main/java/com/fs/company/controller/live/LiveMixLiuTestOpenController.java

@@ -0,0 +1,28 @@
+package com.fs.company.controller.live;
+
+import com.fs.live.service.ILiveWatchUserService;
+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;
+
+/**
+ * @author MixLiu
+ * @date 2025/12/18 下午3:26)
+ */
+
+@RestController
+@RequestMapping("/live/LiveMixLiuTestOpen")
+public class LiveMixLiuTestOpenController {
+
+    @Autowired
+    private ILiveWatchUserService liveWatchUserService;
+
+    @GetMapping("/goToMarkUser/{liveId}")
+    public void goToMarkUser(@PathVariable Long liveId){
+        liveWatchUserService.qwTagMarkByLiveWatchLog(liveId);
+
+
+    }
+}

+ 1 - 0
fs-company/src/main/java/com/fs/framework/config/SecurityConfig.java

@@ -132,6 +132,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
                 .antMatchers("/druid/**").anonymous()
                 .antMatchers("/qw/data/**").anonymous()
                 .antMatchers("/qw/user/selectCloudByCompany").anonymous()
+                .antMatchers("/live/LiveMixLiuTestOpen/**").anonymous()
                 // 除上面外的所有请求全部需要鉴权认证
                 .anyRequest().authenticated()
                 .and()

+ 3 - 1
fs-company/src/main/java/com/fs/hisStore/controller/FsStoreOrderScrmController.java

@@ -43,6 +43,7 @@ import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
+import java.math.BigDecimal;
 import java.text.ParseException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -182,7 +183,7 @@ public class FsStoreOrderScrmController extends BaseController
                 if (vo.getUserAddress()!=null){
                     vo.setUserAddress(ParseUtils.parseAddress(vo.getUserAddress()));
                 }
-
+                vo.setCost(BigDecimal.ZERO);
             }
         }
 
@@ -391,6 +392,7 @@ public class FsStoreOrderScrmController extends BaseController
                     catch (Exception e){
                     }
                 }
+                vo.setCost(BigDecimal.ZERO);
             }
         }
         ExcelUtil<FsStoreOrderItemExportVO> util = new ExcelUtil<FsStoreOrderItemExportVO>(FsStoreOrderItemExportVO.class);

+ 25 - 4
fs-company/src/main/java/com/fs/user/FsUserAdminController.java

@@ -9,14 +9,14 @@ 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.ServletUtils;
-import com.fs.common.utils.StringUtils;
 import com.fs.company.cache.ICompanyUserCacheService;
+import com.fs.course.domain.FsUserCompanyUser;
 import com.fs.course.dto.BatchSendCourseDTO;
 import com.fs.course.param.FsCourseLinkCreateParam;
+import com.fs.course.service.IFsUserCompanyUserService;
 import com.fs.course.service.IFsUserCourseService;
 import com.fs.framework.security.LoginUser;
 import com.fs.framework.service.TokenService;
-
 import com.fs.his.domain.FsUser;
 import com.fs.his.service.IFsUserService;
 import com.fs.his.utils.PhoneUtil;
@@ -37,8 +37,6 @@ import org.springframework.web.bind.annotation.*;
 
 import java.util.Date;
 
-import static com.fs.his.utils.PhoneUtil.encryptPhone;
-
 @Api(tags = "会员管理接口")
 @RestController
 @Slf4j
@@ -64,6 +62,9 @@ public class FsUserAdminController extends BaseController {
     @Autowired
     private OpenIMService openIMService;
 
+    @Autowired
+    private IFsUserCompanyUserService fsUserCompanyUserService;
+
     @PreAuthorize("@ss.hasPermi('user:fsUser:list')")
     @PostMapping("/list")
     @ApiOperation("会员列表(与移动端使用的相同查询)")
@@ -146,6 +147,15 @@ public class FsUserAdminController extends BaseController {
         return AjaxResult.success(fsUserService.selectFsUserPageListVOByUserId(userId));
     }
 
+    /**
+     * 获取项目用户详细信息
+     */
+    @GetMapping(value = "/member/{id}")
+    public AjaxResult getMemberInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsUserService.selectFsMemberUserPageListVOById(id));
+    }
+
     /**
      * 修改用户
      */
@@ -157,6 +167,17 @@ public class FsUserAdminController extends BaseController {
         return toAjax(fsUserService.updateFsUser(fsUser));
     }
 
+    /**
+     * 修改用户
+     */
+    @PreAuthorize("@ss.hasPermi('user:fsUser:edit')")
+    @Log(title = "用户", businessType = BusinessType.UPDATE)
+    @PutMapping("/member")
+    public AjaxResult editMemberUser(@RequestBody FsUserCompanyUser fsUser)
+    {
+        return toAjax(fsUserCompanyUserService.updateFsUserCompanyUser(fsUser));
+    }
+
 
     @ApiOperation("后台会员批量发送课程消息")
     @PostMapping("/batchSendCourse")

+ 95 - 0
fs-live-app/src/main/java/com/fs/live/websocket/service/WebSocketServer.java

@@ -36,7 +36,9 @@ import javax.websocket.*;
 import javax.websocket.server.ServerEndpoint;
 import java.io.EOFException;
 import java.io.IOException;
+import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.time.ZoneId;
 import java.util.*;
 import java.util.concurrent.*;
 import java.util.concurrent.locks.Lock;
@@ -246,6 +248,9 @@ public class WebSocketServer {
             }
             redisCache.setCacheObject( "live:user:first:entry:" + liveId + ":" + userId, liveUserFirstEntry,1, TimeUnit.HOURS);
 
+            // 推送完课积分倒计时配置信息给前端
+            sendCompletionPointsConfigToUser(session, liveId, userId, live);
+
 
         } else {
             adminRoom.add(session);
@@ -1392,5 +1397,95 @@ public class WebSocketServer {
         }
     }
 
+    /**
+     * 向用户推送完课积分倒计时配置信息
+     * 在用户连接WebSocket时调用,让前端能够显示倒计时
+     * @param session WebSocket会话
+     * @param liveId 直播间ID
+     * @param userId 用户ID
+     * @param live 直播信息
+     */
+    private void sendCompletionPointsConfigToUser(Session session, Long liveId, Long userId, Live live) {
+        try {
+
+            boolean isLiveStarted = false;
+            if (live.getStatus() != null && live.getStatus() == 2) {
+                isLiveStarted = true;
+            } else if (live.getStartTime() != null) {
+                LocalDateTime now = LocalDateTime.now();
+                isLiveStarted = now.isAfter(live.getStartTime()) || now.isEqual(live.getStartTime());
+            }
+
+            if (!isLiveStarted) {
+                // 直播未开始,不推送完课配置
+                log.debug("[完课配置推送] 直播未开始,跳过推送, liveId={}, userId={}", liveId, userId);
+                return;
+            }
+
+            String configJson = live.getConfigJson();
+            if (configJson == null || configJson.isEmpty()) {
+                return;
+            }
+
+            JSONObject jsonConfig = JSON.parseObject(configJson);
+            boolean enabled = jsonConfig.getBooleanValue("enabled");
+            if (!enabled) {
+                return;
+            }
+
+            Integer completionRate = jsonConfig.getInteger("completionRate");
+            if (completionRate == null || completionRate <= 0 || completionRate > 100) {
+                return;
+            }
+
+            // 3. 计算完课所需观看时长
+            Long videoDuration = live.getDuration();
+            if (videoDuration == null || videoDuration <= 0) {
+                return;
+            }
+
+            // 完课所需时长(秒) = 视频总时长 × 完课比例 / 100
+            long requiredDuration = (long) Math.ceil(videoDuration * completionRate / 100.0);
+
+            // 4. 获取用户当前观看时长
+            String hashKey = "live:watch:duration:hash:" + liveId;
+            String userIdField = String.valueOf(userId);
+            Object existingDuration = redisCache.hashGet(hashKey, userIdField);
+            long currentDuration = existingDuration != null ? Long.parseLong(existingDuration.toString()) : 0L;
+
+            // 5. 检查今天是否已有完课记录
+            LocalDate today = LocalDate.now();
+            Date currentDate = Date.from(today.atStartOfDay(ZoneId.systemDefault()).toInstant());
+            LiveCompletionPointsRecord todayRecord = completionPointsRecordService.selectByUserAndDate(liveId, userId, currentDate);
+
+            boolean hasCompletedToday = (todayRecord != null);
+
+            // 6. 构建配置信息
+            JSONObject configData = new JSONObject();
+            configData.put("videoDuration", videoDuration);  // 视频总时长(秒)
+            configData.put("completionRate", completionRate);  // 完课比例(%)
+            configData.put("requiredDuration", requiredDuration);  // 完课所需时长(秒)
+            configData.put("currentDuration", currentDuration);  // 当前观看时长(秒)
+            configData.put("remainingDuration", Math.max(0, requiredDuration - currentDuration));  // 剩余时长(秒)
+            configData.put("hasCompletedToday", hasCompletedToday);  // 今天是否已完课
+
+            // 7. 推送配置消息
+            SendMsgVo sendMsgVo = new SendMsgVo();
+            sendMsgVo.setLiveId(liveId);
+            sendMsgVo.setUserId(userId);
+            sendMsgVo.setCmd("completionPointsConfig");
+            sendMsgVo.setMsg("完课积分配置");
+            sendMsgVo.setData(configData.toJSONString());
+
+            sendMessage(session, JSONObject.toJSONString(R.ok().put("data", sendMsgVo)));
+
+            log.debug("[完课配置推送] 推送成功, liveId={}, userId={}, 所需时长={}秒, 当前时长={}秒, 剩余={}秒",
+                    liveId, userId, requiredDuration, currentDuration, Math.max(0, requiredDuration - currentDuration));
+
+        } catch (Exception e) {
+            log.error("[完课配置推送] 推送失败, liveId={}, userId={}", liveId, userId, e);
+        }
+    }
+
 }
 

+ 3 - 0
fs-service/src/main/java/com/fs/his/service/IFsUserService.java

@@ -188,6 +188,9 @@ public interface IFsUserService
 
     FsUserPageListVO selectFsUserPageListVOByUserId(Long userId);
 
+
+    FsUserPageListVO selectFsMemberUserPageListVOById(Long id);
+
     /**
      * 查询项目会员数据
      *

+ 1 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsStorePaymentServiceImpl.java

@@ -389,6 +389,7 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
             V2TradePaymentScanpayQueryRequest request = new V2TradePaymentScanpayQueryRequest();
             request.setOrgReqDate(new SimpleDateFormat("yyyyMMdd").format(fsStorePayment.getCreateTime()));
             request.setOrgHfSeqId(fsStorePayment.getTradeNo());
+            request.setAppId(fsStorePayment.getAppId());
             HuiFuQueryOrderResult queryOrderResult = null;
             try {
                 queryOrderResult = huiFuService.queryOrder(request);

+ 39 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsUserServiceImpl.java

@@ -1221,6 +1221,45 @@ public class FsUserServiceImpl implements IFsUserService {
         return item;
     }
 
+    @Override
+    public FsUserPageListVO selectFsMemberUserPageListVOById(Long id) {
+        FsUserCompanyUser userCompanyUser = userCompanyUserService.selectFsUserCompanyUserById(id);
+        if(userCompanyUser == null || userCompanyUser.getUserId() == null){
+            return null;
+        }
+
+        FsUser fsUser = fsUserMapper.selectFsUserByUserId(userCompanyUser.getUserId());
+        FsUserPageListVO item = new FsUserPageListVO();
+        BeanUtils.copyProperties(fsUser, item);
+        item.setNickname(fsUser.getNickName());
+        item.setStatus(userCompanyUser.getStatus()); // 取项目会员的状态
+        Map<Long, CompanyTag> tagMap = companyTagCacheService.queryAllTagMap();
+        if (item.getPhone() != null) {
+            item.setPhone(ParseUtils.parsePhone(item.getPhone()));
+        }
+        String userTagByUserId = null;
+        if (item.getUserId() != null && item.getCompanyUserId() != null) {
+            userTagByUserId = companyTagCacheService
+                    .findUserTagByUserId(item.getUserId(), item.getCompanyUserId());
+        }
+        if (StringUtils.isNotEmpty(userTagByUserId)) {
+            String[] split = userTagByUserId.split(",");
+            Set<String> tagNames = new HashSet<>();
+            for (String tag : split) {
+                if (StringUtils.isNotBlank(tag)) {
+                    Long tagL = Long.parseLong(tag);
+                    CompanyTag companyTag = tagMap.get(tagL);
+                    if (companyTag != null) {
+                        tagNames.add(companyTag.getTag());
+                    }
+                }
+            }
+            item.setTagIds(userTagByUserId);
+            item.setTag(String.join(",", tagNames));
+        }
+        return item;
+    }
+
     @Override
     @Transactional
     public void addMoney(FsStoreOrderScrm order) {

+ 1 - 1
fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreAfterSalesScrmMapper.java

@@ -255,7 +255,7 @@ public interface FsStoreAfterSalesScrmMapper
             " left join company c on c.company_id=s.company_id " +
             " left join company_user cu on cu.user_id=s.company_user_id " +
             " left join fs_store_payment_scrm fsps on fsps.business_order_id = o.id and fsps.status in (-1,1) " +
-            " where 1=1 and s.status = 4 " +
+            " where 1=1 and s.status = 4 and fsps.bank_transaction_id is not null " +
             "<if test =\"maps.hfOrderCode != null and  maps.hfOrderCode!='' \"> " +
             "and fsps.pay_code = #{maps.hfOrderCode} " +
             "</if>" +

+ 1 - 1
fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderItemExportRefundZMVO.java

@@ -49,7 +49,7 @@ public class FsStoreOrderItemExportRefundZMVO implements Serializable  {
     @Excel(name = "产品价格",sort =70)
     private String price;
 
-    @Excel(name = "成本价",sort =80)
+    @Excel(name = "成本价",sort =80)
     private String cost;
     @Excel(name = "结算价",sort =90)
     private BigDecimal FPrice;

+ 1 - 1
fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderItemExportVO.java

@@ -41,7 +41,7 @@ public class FsStoreOrderItemExportVO implements Serializable
     @Excel(name = "产品价格")
     private BigDecimal price;
 
-    @Excel(name = "成本价")
+    @Excel(name = "成本价")
     private BigDecimal cost;
     @Excel(name = "结算价")
     private BigDecimal FPrice;

+ 1 - 1
fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderItemExportZMVO.java

@@ -46,7 +46,7 @@ public class FsStoreOrderItemExportZMVO implements Serializable  {
     @Excel(name = "产品价格",sort =70)
     private BigDecimal price;
 
-    @Excel(name = "成本价",sort =80)
+    @Excel(name = "成本价",sort =80)
     private BigDecimal cost;
     @Excel(name = "结算价",sort =90)
     private BigDecimal FPrice;

+ 1 - 1
fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderPromotionExportVO.java

@@ -132,7 +132,7 @@ public class FsStoreOrderPromotionExportVO implements Serializable
     private String packageTitle;
 
     /** 成本价 */
-    @Excel(name = "订单成本价")
+    @Excel(name = "成本价")
     private BigDecimal cost;
 
     private String phone;

+ 1 - 1
fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderVO.java

@@ -194,7 +194,7 @@ public class FsStoreOrderVO implements Serializable
     private Integer isDel;
 
     /** 成本价 */
-    @Excel(name = "成本价")
+    @Excel(name = "成本价")
     private BigDecimal cost;
 
     /** 结算价 */

+ 1 - 1
fs-service/src/main/java/com/fs/hisStore/vo/FsStoreProductExportVO.java

@@ -118,7 +118,7 @@ public class FsStoreProductExportVO implements Serializable {
     private BigDecimal giveIntegral;
 
     /** 成本价 */
-    @Excel(name = "成本价")
+    @Excel(name = "成本价")
     private BigDecimal cost;
 
     /** 是否优品推荐 */

+ 12 - 0
fs-service/src/main/java/com/fs/huifuPay/sdk/opps/core/request/V2TradePaymentScanpayQueryRequest.java

@@ -47,6 +47,10 @@ public class V2TradePaymentScanpayQueryRequest extends BaseRequest {
     @JSONField(name = "party_order_id")
     private String partyOrderId;
 
+
+
+    String appId; //多小程序支付
+
     @Override
     public FunctionCodeEnum getFunctionCode() {
         return FunctionCodeEnum.V2_TRADE_PAYMENT_SCANPAY_QUERY;
@@ -121,4 +125,12 @@ public class V2TradePaymentScanpayQueryRequest extends BaseRequest {
         this.partyOrderId = partyOrderId;
     }
 
+    public String getAppId() {
+        return appId;
+    }
+
+    public void setAppId(String appId) {
+        this.appId = appId;
+    }
+
 }

+ 13 - 1
fs-service/src/main/java/com/fs/huifuPay/service/impl/HuiFuServiceImpl.java

@@ -131,7 +131,19 @@ public class HuiFuServiceImpl implements HuiFuService {
 
     @Override
     public HuiFuQueryOrderResult queryOrder(V2TradePaymentScanpayQueryRequest request) throws Exception{
-        doInit(getMerConfig());
+        if (request.getAppId() != null) {
+            FsHfpayConfigMapper fsHfpayConfigMapper = SpringUtils.getBean(FsHfpayConfigMapper.class);
+            FsHfpayConfig fsHfpayConfig = fsHfpayConfigMapper.selectByAppId(request.getAppId());
+            if (fsHfpayConfig != null) {
+                //多汇付支付获取配置
+                doInit(getMerConfig(fsHfpayConfig));
+            } else {
+                //多小程序
+                doInit(getMerConfig());
+            }
+        } else {
+            doInit(getMerConfig());
+        }
         Map<String, Object> response = doExecute(request);
         String jsonString = JSONObject.toJSONString(response);
         HuiFuQueryOrderResult huiFuQueryOrderResult = JSON.parseObject(jsonString, HuiFuQueryOrderResult.class);

+ 1 - 1
fs-service/src/main/java/com/fs/live/domain/LiveOrder.java

@@ -145,7 +145,7 @@ public class LiveOrder extends BaseEntity {
     private String isDel;
 
     /** 成本价 */
-    @Excel(name = "成本价")
+    @Excel(name = "成本价")
     private BigDecimal costPrice;
 
     /** 核销码 */

+ 1 - 1
fs-service/src/main/java/com/fs/live/param/LiveOrderSearchParam.java

@@ -131,7 +131,7 @@ public class LiveOrderSearchParam extends BaseEntity {
     private String isDel;
 
     /** 成本价 */
-    @Excel(name = "成本价")
+    @Excel(name = "成本价")
     private BigDecimal costPrice;
 
     /** 核销码 */

+ 10 - 0
fs-service/src/main/java/com/fs/live/service/ILiveCompletionPointsRecordService.java

@@ -2,6 +2,7 @@ package com.fs.live.service;
 
 import com.fs.live.domain.LiveCompletionPointsRecord;
 
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -40,4 +41,13 @@ public interface ILiveCompletionPointsRecordService {
      * @return 完课记录列表
      */
     List<LiveCompletionPointsRecord> getUserRecords(Long liveId, Long userId);
+
+    /**
+     * 根据用户和日期查询完课记录
+     * @param liveId 直播ID
+     * @param userId 用户ID
+     * @param date 日期
+     * @return 完课记录
+     */
+    LiveCompletionPointsRecord selectByUserAndDate(Long liveId, Long userId, Date date);
 }

+ 8 - 0
fs-service/src/main/java/com/fs/live/service/impl/LiveCompletionPointsRecordServiceImpl.java

@@ -261,6 +261,14 @@ public class LiveCompletionPointsRecordServiceImpl implements ILiveCompletionPoi
         return recordMapper.selectRecordsByUser(liveId, userId);
     }
 
+    /**
+     * 根据用户和日期查询完课记录
+     */
+    @Override
+    public LiveCompletionPointsRecord selectByUserAndDate(Long liveId, Long userId, Date date) {
+        return recordMapper.selectByUserAndDate(liveId, userId, date);
+    }
+
     /**
      * 从直播配置中获取完课积分配置
      */

+ 7 - 4
fs-service/src/main/java/com/fs/live/service/impl/LiveOrderServiceImpl.java

@@ -3193,7 +3193,7 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
                         });
                         String s = (String) resultMap.get("package");
                         resultMap.put("packageValue", s);
-                        return R.ok().put("payType", param.getPayType()).put("result", resultMap);
+                        return R.ok().put("payType", param.getPayType()).put("result", resultMap).put("type", "hf");
                     } else {
                         return R.error(result.getResp_desc());
                     }
@@ -3532,6 +3532,7 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
                     V2TradePaymentScanpayQueryRequest request = new V2TradePaymentScanpayQueryRequest();
                     request.setOrgReqDate(new SimpleDateFormat("yyyyMMdd").format(payment.getCreateTime()));
                     request.setOrgHfSeqId(payment.getTradeNo());
+                    request.setAppId(payment.getAppId());
                     HuiFuQueryOrderResult queryOrderResult = null;
                     try {
                         queryOrderResult = huiFuService.queryOrder(request);
@@ -3624,9 +3625,11 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
         }
 
         LiveUserFirstEntry liveUserFirstEntry = liveUserFirstEntryService.selectEntityByLiveIdUserId(liveOrder.getLiveId(), Long.parseLong(liveOrder.getUserId()));
-        liveOrder.setCompanyId(liveUserFirstEntry.getCompanyId());
-        liveOrder.setCompanyUserId(liveUserFirstEntry.getCompanyUserId());
-        liveOrder.setTuiUserId(liveUserFirstEntry.getCompanyUserId());
+        if (ObjectUtil.isNotEmpty(liveUserFirstEntry)) {
+            liveOrder.setCompanyId(liveUserFirstEntry.getCompanyId());
+            liveOrder.setCompanyUserId(liveUserFirstEntry.getCompanyUserId());
+            liveOrder.setTuiUserId(liveUserFirstEntry.getCompanyUserId());
+        }
         String orderSn = OrderCodeUtils.getOrderSn();
 //        String orderSn = "123"; // todo yhq
         log.info("订单生成:"+orderSn);

+ 32 - 0
fs-service/src/main/java/com/fs/live/service/impl/LiveServiceImpl.java

@@ -1,6 +1,7 @@
 package com.fs.live.service.impl;
 
 import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.thread.ThreadUtil;
 import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSON;
@@ -975,7 +976,38 @@ public class LiveServiceImpl implements ILiveService
             redisCache.redisTemplate.opsForZSet().add("live:auto_task:" + live.getLiveId(), JSON.toJSONString(liveAutoTask),liveAutoTask.getAbsValue().getTime());
             redisCache.redisTemplate.expire("live:auto_task:"+live.getLiveId(), 1, TimeUnit.DAYS);
         });
+        String cacheKey = String.format(LiveKeysConstant.LIVE_DATA_CACHE, live.getLiveId());
+        redisCache.deleteObject(cacheKey);
+        String cacheKey2 = String.format(LiveKeysConstant.LIVE_FLAG_CACHE, live.getLiveId());
+        redisCache.deleteObject(cacheKey2);
 
+        // 将开启的直播间信息写入Redis缓存,用于打标签定时任务
+        try {
+            // 获取视频时长
+            Long videoDuration = 0L;
+            List<LiveVideo> videos = liveVideoService.listByLiveId(live.getLiveId(), 1);
+            if (CollUtil.isNotEmpty(videos)) {
+                videoDuration = videos.stream()
+                        .filter(v -> v.getDuration() != null)
+                        .mapToLong(LiveVideo::getDuration)
+                        .sum();
+            }
+
+            // 如果视频时长大于0,将直播间信息存入Redis
+            if (videoDuration > 0 && live.getStartTime() != null) {
+                Map<String, Object> tagMarkInfo = new HashMap<>();
+                tagMarkInfo.put("liveId", live.getLiveId());
+                tagMarkInfo.put("startTime", live.getStartTime().atZone(java.time.ZoneId.systemDefault()).toInstant().toEpochMilli());
+                tagMarkInfo.put("videoDuration", videoDuration);
+
+                String tagMarkKey = String.format(LiveKeysConstant.LIVE_TAG_MARK_CACHE, live.getLiveId());
+                redisCache.setCacheObject(tagMarkKey, JSON.toJSONString(tagMarkInfo), 24, TimeUnit.HOURS);
+                log.info("手动开直播间开启,已加入打标签缓存: liveId={}, startTime={}, videoDuration={}",
+                        live.getLiveId(), live.getStartTime(), videoDuration);
+            }
+        } catch (Exception e) {
+            log.error("手动开写入直播间打标签缓存失败: liveId={}, error={}", live.getLiveId(), e.getMessage(), e);
+        }
 
         return R.ok();
     }

+ 8 - 1
fs-service/src/main/java/com/fs/live/service/impl/LiveWatchUserServiceImpl.java

@@ -863,6 +863,9 @@ public class LiveWatchUserServiceImpl implements ILiveWatchUserService {
         //查询直播间的标签配置
         List<LiveTagItemVO> liveTagConfig = liveTagConfigMapper.getLiveTagListByliveId(liveId);
         log.info("处理直播间打标签: liveTagConfig={}", liveTagConfig);
+        if(null == liveTagConfig || liveTagConfig.isEmpty()){
+            return;
+        }
         /**
          * 8	回放已下单
          * 7	直播已下单
@@ -881,7 +884,10 @@ public class LiveWatchUserServiceImpl implements ILiveWatchUserService {
                 ));
         //查询直播间的看课记录
         List<LiveWatchLog> liveWatchLogs = liveWatchLogMapper.selectLiveWatchLogByLiveId(liveId);
-
+        log.info("处理直播间打标签: liveWatchLogs={}", liveWatchLogs);
+        if(null == liveWatchLogs || liveWatchLogs.isEmpty()){
+            return;
+        }
         //根据配置给每位用户打上标签
         List<HandleUserTagVO> handleUserTagVOS = new ArrayList<>();
         liveWatchLogs.forEach(liveLog -> {
@@ -936,6 +942,7 @@ public class LiveWatchUserServiceImpl implements ILiveWatchUserService {
             }
             handleUserTagVOS.add(addItem);
         });
+        log.info("处理直播间打标签最终打标签:{}",handleUserTagVOS);
         handleUserTags2Qw(handleUserTagVOS);
     }
 

+ 1 - 1
fs-service/src/main/java/com/fs/live/vo/LiveOrderListVo.java

@@ -136,7 +136,7 @@ public class LiveOrderListVo extends BaseEntity {
     private String isDel;
 
     /** 成本价 */
-    @Excel(name = "成本价")
+    @Excel(name = "成本价")
     private BigDecimal costPrice;
 
     /** 核销码 */

+ 1 - 1
fs-service/src/main/java/com/fs/live/vo/LiveOrderVoZm.java

@@ -118,7 +118,7 @@ public class LiveOrderVoZm{
     @Excel(name = "销售价格")
     private BigDecimal price;
 
-    @Excel(name = "成本价")
+    @Excel(name = "成本价")
     private BigDecimal cost;
 
     @Excel(name = "结算价格")

+ 1 - 1
fs-service/src/main/java/com/fs/live/vo/MergedOrderExportVO.java

@@ -56,7 +56,7 @@ public class MergedOrderExportVO implements Serializable
     private BigDecimal price;
 
     /** 成本价 */
-    @Excel(name = "成本价")
+    @Excel(name = "成本价")
     private BigDecimal cost;
 
     /** 商品金额 */

+ 1 - 1
fs-service/src/main/java/com/fs/store/vo/FsStoreProductScrmExportVO.java

@@ -118,7 +118,7 @@ public class FsStoreProductScrmExportVO implements Serializable {
     private BigDecimal giveIntegral;
 
     /** 成本价 */
-    @Excel(name = "成本价")
+    @Excel(name = "成本价")
     private BigDecimal cost;
 
     /** 是否优品推荐 */

+ 3 - 0
fs-service/src/main/java/com/fs/store/vo/h5/FsUserPageListVO.java

@@ -106,4 +106,7 @@ public class FsUserPageListVO {
     @ApiModelProperty(value = "是否购买 1:是 0 否")
     private BigDecimal isBuy;
 
+    // 项目会员 主键
+    private Long id;
+
 }

+ 1 - 1
fs-service/src/main/resources/application-config-druid-bjzm.yml

@@ -92,7 +92,7 @@ headerImg:
 
 ipad:
   ipadUrl: http://aipad.klbycp.com
-  aiApi: 1212121212
+  aiApi: http://49.232.181.28:3000/api
   voiceApi:
   commonApi:
 wx_miniapp_temp:

+ 2 - 2
fs-service/src/main/resources/application-config-druid-hcl.yml

@@ -90,8 +90,8 @@ tmp_secret_config:
 cloud_host:
   company_name: 恒春来
   projectCode: HCL
-  spaceName:
-  volcengineUrl:
+  spaceName: hcl-2114522511
+  volcengineUrl: https://hclvolcengine.ylrztop.com
 #看课授权时显示的头像
 headerImg:
   imgUrl: http://hcl-1b2b.obs.cn-south-1.myhuaweicloud.com/fs/20250815/1755228988455.png

+ 2 - 2
fs-service/src/main/resources/application-config-druid-hzyy.yml

@@ -90,8 +90,8 @@ tmp_secret_config:
 cloud_host:
   company_name: 弘珍医药
   projectCode: HZYY
-  spaceName:
-  volcengineUrl:
+  spaceName: hzyy-2114522511
+  volcengineUrl: https://hzyyvolcengine.ylrztop.com
 #看课授权时显示的头像
 headerImg:
   imgUrl: https://hzyy.obs.cn-north-4.myhuaweicloud.com/fs/20250616/1750067609692.png

+ 2 - 2
fs-service/src/main/resources/application-config-druid-jzzx.yml

@@ -94,8 +94,8 @@ tmp_secret_config:
 cloud_host:
   company_name: 九州在线
   projectCode: JZZX
-  spaceName:
-  volcengineUrl:
+  spaceName: jzzx-2114522511
+  volcengineUrl: https://jzzxvolcengine.ylrztop.com
 headerImg:
   imgUrl: https://jiuzhouzaixian.obs.cn-southwest-2.myhuaweicloud.com/fs/20250623/1750665141214.png
 ipad:

+ 2 - 2
fs-service/src/main/resources/application-config-druid-sczy.yml

@@ -94,8 +94,8 @@ tmp_secret_config:
 cloud_host:
   company_name: 四川致医
   projectCode: SCZY
-  spaceName:
-  volcengineUrl:
+  spaceName: sczy-2114522511
+  volcengineUrl: https://sczytvolcengine.ylrztop.com
 headerImg:
   imgUrl: https://jiuzhouzaixian.obs.cn-southwest-2.myhuaweicloud.com/fs/20250623/1750665141214.png
 ipad:

+ 5 - 5
fs-service/src/main/resources/application-druid-shdn.yml

@@ -4,12 +4,12 @@ spring:
         include: config-druid-shdn,common
     # redis 配置
     redis:
-        host: 10.206.0.10
-        port: 6579
+        host: 172.17.0.10
+        port: 6379
         # 数据库索引
         database: 0
         # 密码
-        password:
+        password: !@#123QWe
         # 连接超时时间
         timeout: 30s
         lettuce:
@@ -39,7 +39,7 @@ spring:
             druid:
                 # 主库数据源
                 master:
-                  url: jdbc:mysql://172.17.0.12:65535/fs_his?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
+                  url: jdbc:mysql://172.17.0.12:3306/fs_his?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
                   username: root
                   password: QWEqwe123!@#
                 # 从库数据源
@@ -94,7 +94,7 @@ spring:
             druid:
                 # 主库数据源
                 master:
-                    url: jdbc:mysql://172.17.0.12:65535/fs_his_sop?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
+                    url: jdbc:mysql://172.17.0.12:3306/fs_his_sop?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
                     username: root
                     password: QWEqwe123!@#
                 # 初始连接数

+ 2 - 1
fs-service/src/main/resources/mapper/MerchantAppConfigMapper.xml

@@ -56,9 +56,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <where>
             <if test="merchantId != null and merchantId != ''"> and merchant_id = #{merchantId}</if>
             <if test="merchantType != null  and merchantType != ''"> and merchant_type = #{merchantType}</if>
-            <if test="appId != null  and appId != ''"> and app_id = #{appId}</if>
+            <if test="appId != null  and appId != ''"> and  FIND_IN_SET(#{appId},app_id)  </if>
             <if test="params.beginCreatedTime != null and params.beginCreatedTime != '' and params.endCreatedTime != null and params.endCreatedTime != ''"> and created_time between #{params.beginCreatedTime} and #{params.endCreatedTime}</if>
             <if test="isDeleted != null "> and is_deleted = #{isDeleted}</if>
+             <if test="id != null"> and id = #{id}</if>
         </where>
     </select>
 

+ 2 - 1
fs-service/src/main/resources/mapper/his/FsUserMapper.xml

@@ -358,9 +358,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         fs_user.nick_name as nickname,
         fs_user.avatar,
         fs_user.phone,
-        fs_user.status,
         fs_user.create_time,
         fs_user.remark,
+        ucu.id,
+        ucu.status,
         ucu.company_user_id,
         ucu.company_id,
         ucu.project_id,

+ 1 - 1
fs-service/src/main/resources/mapper/live/LiveAfterSalesMapper.xml

@@ -131,7 +131,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         left join live_order_item loi on loi.order_id = lo.order_id
         </if>
 
-        where 1=1 and las.status =4
+        where 1=1 and las.status =4 and lop.bank_transaction_id is not null
             <if test="hfOrderCode != null and hfOrderCode != ''"> and lop.pay_code = #{hfOrderCode}</if>
             <if test="liveId != null and liveId != ''"> and las.live_id = #{liveId}</if>
             <if test="companyUserNickName != null and companyUserNickName != ''"> and cu.nick_name like concat(#{companyUserNickName},'%')</if>

+ 1 - 1
fs-store/src/main/java/com/fs/store/vo/FsStoreProductStoreExcelVO.java

@@ -155,7 +155,7 @@ public class FsStoreProductStoreExcelVO extends BaseEntity {
     /**
      * 成本价
      */
-    @Excel(name = "成本价")
+    @Excel(name = "成本价")
     private BigDecimal costPrice;