Parcourir la source

Merge remote-tracking branch 'origin/master'

dengweize il y a 1 semaine
Parent
commit
ea8fc3c44a

+ 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, "会员每日看课统计数据");
     }
 
+
+
     /**
      * 获取会员每日看课统计详细信息
      */

+ 11 - 23
fs-service/src/main/java/com/fs/course/domain/FsUserCourseCompanyStatistics.java

@@ -17,67 +17,55 @@ import lombok.EqualsAndHashCode;
  */
 @Data
 @EqualsAndHashCode(callSuper = true)
-public class FsUserCourseCompanyStatistics extends BaseEntity{
+public class FsUserCourseCompanyStatistics extends BaseEntity {
 
-    /** 主键ID */
     private Long id;
 
-    /** 项目ID */
-//    @Excel(name = "项目ID")
     private Long projectId;
 
-    /** 完播次数(人次) */
-    @Excel(name = "完播次数", readConverterExp = "人=次")
+    @Excel(name = "完播次数")
     private Long completeWatchCount;
 
-    /** 观看次数(人次) */
-    @Excel(name = "观看次数", readConverterExp = "人=次")
+    @Excel(name = "观看次数")
     private Long watchCount;
 
-    /** 完播率(完播次数/观看次数) */
-    @Excel(name = "完播率", readConverterExp = "完=播次数/观看次数")
+    /** DB字段,存放放大100倍后的比例整数值,例 12.34% -> 1234 */
     private Long completeRate;
 
-    /** 答题人次 */
     @Excel(name = "答题人次")
     private Long answerCount;
 
-    /** 正确人次 */
     @Excel(name = "正确人次")
     private Long correctCount;
 
-    /** 正确率(正确人次/答题人次) */
-    @Excel(name = "正确率", readConverterExp = "正=确人次/答题人次")
+    /** DB字段,同样放大100倍后存储 */
     private Long correctRate;
 
-    /** 领取次数 */
     @Excel(name = "领取次数")
     private Long receiveCount;
 
-    /** 领取金额(元) */
-    @Excel(name = "领取金额", readConverterExp = "元=")
+    @Excel(name = "领取金额(元)")
     private BigDecimal receiveAmount;
 
-    /** 会员数量 */
     @Excel(name = "会员数量")
     private Long userCount;
 
-    /** 会员黑名单数量 */
     @Excel(name = "会员黑名单数量")
     private Long userBlacklistCount;
 
-    /** 公司ID */
-//    @Excel(name = "公司ID")
     private Long companyId;
 
-    /** 公司名称 */
     @Excel(name = "公司名称")
     private String companyName;
 
-    /** 统计日期 */
     @JsonFormat(pattern = "yyyy-MM-dd")
     @Excel(name = "统计日期", width = 30, dateFormat = "yyyy-MM-dd")
     private Date createDate;
 
+    /** 用于 Excel 导出显示的字符串,不入库 */
+    @Excel(name = "完播率(%)")
+    private String completeRateStr;
 
+    @Excel(name = "正确率(%)")
+    private String correctRateStr;
 }

+ 1 - 1
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -1498,7 +1498,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             // 更新观看记录的奖励类型
             log.setRewardType(config.getRewardType());
             courseWatchLogMapper.updateFsCourseWatchLog(log);
-            return R.ok("红包发送成功");
+            return R.ok("答题成功!");
         }
 
     }

+ 2 - 0
fs-service/src/main/java/com/fs/his/config/FsSmsConfig.java

@@ -21,4 +21,6 @@ public class FsSmsConfig {
     private String dhPassword2;
     private String dhSign;
 
+    private Integer isSmsVerification; //是否开启短信验证
+
 }

+ 17 - 10
fs-service/src/main/java/com/fs/hisStore/service/impl/FsMenuScrmServiceImpl.java

@@ -3,6 +3,8 @@ package com.fs.hisStore.service.impl;
 import java.util.List;
 import com.fs.common.utils.DateUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
 import org.springframework.stereotype.Service;
 import com.fs.hisStore.mapper.FsMenuScrmMapper;
 import com.fs.hisStore.domain.FsMenuScrm;
@@ -10,7 +12,7 @@ import com.fs.hisStore.service.IFsMenuScrmService;
 
 /**
  * 用户端菜单管理Service业务层处理
- * 
+ *
  * @author fs
  * @date 2022-03-15
  */
@@ -22,7 +24,7 @@ public class FsMenuScrmServiceImpl implements IFsMenuScrmService
 
     /**
      * 查询用户端菜单管理
-     * 
+     *
      * @param menuId 用户端菜单管理ID
      * @return 用户端菜单管理
      */
@@ -34,23 +36,25 @@ public class FsMenuScrmServiceImpl implements IFsMenuScrmService
 
     /**
      * 查询用户端菜单管理列表
-     * 
-     * @param fsMenu 用户端菜单管理
+     *
+     * @param param 用户端菜单管理
      * @return 用户端菜单管理
      */
     @Override
-    public List<FsMenuScrm> selectFsMenuList(FsMenuScrm fsMenu)
+    @Cacheable(value = "selectFsMenuList", key = "#param")
+    public List<FsMenuScrm> selectFsMenuList(FsMenuScrm param)
     {
-        return fsMenuMapper.selectFsMenuList(fsMenu);
+        return fsMenuMapper.selectFsMenuList(param);
     }
 
     /**
      * 新增用户端菜单管理
-     * 
+     *
      * @param fsMenu 用户端菜单管理
      * @return 结果
      */
     @Override
+    @CacheEvict(value = "selectFsMenuList",allEntries = true)
     public int insertFsMenu(FsMenuScrm fsMenu)
     {
         fsMenu.setCreateTime(DateUtils.getNowDate());
@@ -59,11 +63,12 @@ public class FsMenuScrmServiceImpl implements IFsMenuScrmService
 
     /**
      * 修改用户端菜单管理
-     * 
+     *
      * @param fsMenu 用户端菜单管理
      * @return 结果
      */
     @Override
+    @CacheEvict(value = "selectFsMenuList",allEntries = true)
     public int updateFsMenu(FsMenuScrm fsMenu)
     {
         fsMenu.setUpdateTime(DateUtils.getNowDate());
@@ -72,11 +77,12 @@ public class FsMenuScrmServiceImpl implements IFsMenuScrmService
 
     /**
      * 批量删除用户端菜单管理
-     * 
+     *
      * @param menuIds 需要删除的用户端菜单管理ID
      * @return 结果
      */
     @Override
+    @CacheEvict(value = "selectFsMenuList",allEntries = true)
     public int deleteFsMenuByIds(Long[] menuIds)
     {
         return fsMenuMapper.deleteFsMenuByIds(menuIds);
@@ -84,11 +90,12 @@ public class FsMenuScrmServiceImpl implements IFsMenuScrmService
 
     /**
      * 删除用户端菜单管理信息
-     * 
+     *
      * @param menuId 用户端菜单管理ID
      * @return 结果
      */
     @Override
+    @CacheEvict(value = "selectFsMenuList",allEntries = true)
     public int deleteFsMenuById(Long menuId)
     {
         return fsMenuMapper.deleteFsMenuById(menuId);

+ 3 - 2
fs-service/src/main/resources/application-config-dev.yml

@@ -92,10 +92,10 @@ nuonuo:
 tencent_cloud_config:
   secret_id: AKIDiMq9lDf2EOM9lIfqqfKo7FNgM5meD0sT
   secret_key: u5SuS80342xzx8FRBukza9lVNHKNMSaB
-  bucket: jkj-1323137866
+  bucket: cqsft-1323137866
   app_id: 1323137866
   region: ap-chongqing
-  proxy: jkj
+  proxy: cqsft
 tmp_secret_config:
   secret_id: AKIDCj7NSNAovtqeJpBau8GZ4CGB71thXIxX
   secret_key: lTB5zwqqz7CNhzDOWivFWedgfTBgxgBT
@@ -109,6 +109,7 @@ cloud_host:
 headerImg:
   imgUrl: https://jz-cos-1356808054.cos.ap-chengdu.myqcloud.com/fs/20250515/0877754b59814ea8a428fa3697b20e68.png
 ipad:
+  url:
   ipadUrl: http://ipad.cdwjyyh.com
   aiApi: http://152.136.202.157:3000/api
   voiceApi:

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

@@ -83,6 +83,7 @@ cloud_host:
 headerImg:
   imgUrl: https
 ipad:
+  url:
   ipadUrl: https://qwipad.yytcdtb.cn
   aiApi: http://127.0.0.1:3000/api
   voiceApi:

+ 6 - 5
fs-service/src/main/resources/application-config-druid-sft.yml

@@ -67,12 +67,12 @@ nuonuo:
   secret: A2EB20764D304D16
 # 存储捅配置
 tencent_cloud_config:
-  secret_id: AKIDpY8d3KcptqdCaoqeVHuKYZMvITULzQta
-  secret_key: cBShmjU4SwNejgS2PYUFnR7dzAC6pW3Q
-  bucket: sft-1361917636
-  app_id: 1361917636
+  secret_id: AKIDiMq9lDf2EOM9lIfqqfKo7FNgM5meD0sT
+  secret_key: u5SuS80342xzx8FRBukza9lVNHKNMSaB
+  bucket: cqsft-1323137866
+  app_id: 1323137866
   region: ap-chongqing
-  proxy: fs
+  proxy: cqsft
 cloud_host:
   company_name: 四福堂
   projectCode: SFT
@@ -80,6 +80,7 @@ cloud_host:
 headerImg:
   imgUrl: https://sft-1361917636.cos.ap-chongqing.myqcloud.com/sft/20250606/b08b1a6212f44f2998423c8c5d7712ee.png
 ipad:
+  url:
   ipadUrl: http://qwipad.cqsft.vip
   aiApi:
   voiceApi:

+ 1 - 0
fs-service/src/main/resources/application-config-zkzh.yml

@@ -144,6 +144,7 @@ nuonuo:
   key: 10924508
   secret: A2EB20764D304D16
 ipad:
+  url:
   ipadUrl: http://qwipad.muyi88.com
   aiApi: http://152.136.202.157:3000/api
   voiceApi:

+ 1 - 1
fs-service/src/main/resources/mapper/course/FsUserCourseCompanyStatisticsMapper.xml

@@ -239,7 +239,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                 AND DATE(create_date) <![CDATA[ <= ]]> #{endTime}
             </if>
         </where>
-
+        group by company_id,DATE(create_date)
         <!-- 排序:合计行放最后 -->
         ORDER BY create_time DESC
     </select>

+ 75 - 0
fs-user-app/src/main/java/com/fs/app/controller/AppLoginController.java

@@ -120,6 +120,81 @@ public class AppLoginController extends AppBaseController{
         }
     }
 
+    @PostMapping("/registerSendCode")
+    public R registerSendCode(@RequestBody Map<String, String> body){
+        String phone = body.get("phone");
+        String encryptPhone = encryptPhone(phone);
+        List<FsUser> user = userService.selectFsUserListByPhone(encryptPhone);
+        if(CollectionUtil.isEmpty(user)){
+            user = userService.selectFsUserListByPhone(encryptPhoneOldKey(phone));
+        }
+        if (!CollectionUtil.isEmpty(user)){
+            return R.error("此电话号码已注册");
+        }
+
+        // 验证码 key(存验证码,3分钟有效)
+        String smsCodeKey = "sms:code:" + phone;
+        // 发送冷却 key(限制60秒内不能再次发送)
+        String smsCooldownKey = "sms:cooldown:" + phone;
+
+        // 判断是否在60秒冷却时间内
+        if (redisCache.getCacheObject(smsCooldownKey) != null) {
+            return R.error("验证码已发送,请稍后再试");
+        }
+
+        // 生成新的验证码
+        String smsCode = VerifyCodeUtil.generateCode();
+
+        // 发送短信
+        smsService.sendCaptcha(phone, smsCode, "验证码");
+
+        // 缓存验证码(3分钟有效)
+        redisCache.setCacheObject(smsCodeKey, smsCode, 180, TimeUnit.SECONDS);
+        // 设置冷却时间(60秒内不能再发)
+        redisCache.setCacheObject(smsCooldownKey, "1", 60, TimeUnit.SECONDS);
+
+        return R.ok("验证码已发送");
+    }
+
+
+    @PostMapping("/registerByPhone")
+    public R registerByPhone(@RequestBody Map<String,String> map){
+        String phone = map.get("phone");
+        String code = map.get("code");
+        String password = map.get("password");
+        String encryptPhone = encryptPhone(phone);
+        List<FsUser> users = userService.selectFsUserListByPhone(encryptPhone);
+        if (users == null || CollectionUtil.isEmpty(users)){
+            String s = encryptPhoneOldKey(phone);
+            users = userService.selectFsUserListByPhone(s);
+        }
+        if (!CollectionUtil.isEmpty(users)){
+            return R.error("此账号已经注册");
+        }
+        String redisCode = redisCache.getCacheObject("sms:code:" + phone);
+        if (StringUtils.isEmpty(redisCode)){
+            return R.error("验证码已过期,请重新发送");
+        }
+        if (!redisCode.equals(code)) {
+            return R.error("验证码错误");
+        }
+        FsUser user = new FsUser();
+        // 创建新用户
+        user.setPhone(phone);
+        user.setJpushId(map.get("jpushId"));
+        user.setSource(map.get("source"));
+        user.setNickName("app用户" + phone.substring(phone.length() - 4));
+        user.setStatus(1);
+        user.setAvatar("https://cos.his.cdwjyyh.com/fs/20240926/420728ee06e54575ba82665dedb4756b.png");
+        user.setPassword(Md5Utils.hash(password));
+        user.setCreateTime(new Date());
+        if (userService.insertFsUser(user) > 0) {
+            return R.ok("注册成功");
+        } else {
+            return R.error("注册失败");
+        }
+    }
+
 
 
 

+ 17 - 0
fs-user-app/src/main/java/com/fs/app/controller/CommonController.java

@@ -41,6 +41,7 @@ import com.fs.event.TemplateEvent;
 import com.fs.event.TemplateListenEnum;
 import com.fs.event.WeixinTemplateService;
 import com.fs.framework.config.ServerConfig;
+import com.fs.his.config.FsSmsConfig;
 import com.fs.his.config.FsSysConfig;
 import com.fs.his.domain.*;
 import com.fs.his.param.FsInquiryOrderFinishParam;
@@ -662,4 +663,20 @@ public class CommonController {
 
 		return R.ok().put("addressUrl", addressUrl).put("imgpath", imgPath).put("sendType", sendType);
 	}
+
+	@GetMapping(value = "/isSmsVerification")
+	@ApiOperation("获取app是否短信验证配置")
+	public R isSmsVerification()
+	{
+		String config=configService.selectConfigByKey("his.sms");
+		if (StringUtils.isBlank(config)){
+			return  R.ok().put("isSmsVerification",0);
+		}
+		FsSmsConfig sms = JSON.parseObject(config, FsSmsConfig.class);
+		if (sms != null && sms.getIsSmsVerification() != null){
+			return R.ok().put("isSmsVerification",sms.getIsSmsVerification());
+		}
+		return  R.ok().put("isSmsVerification",0);
+
+	}
 }

+ 8 - 0
fs-user-app/src/main/java/com/fs/app/controller/store/IndexScrmController.java

@@ -91,6 +91,14 @@ public class IndexScrmController extends AppBaseController {
 		return R.ok().put("data",list);
 	}
 
+	@ApiOperation("读取菜单配置")
+	@GetMapping("/getMenuList")
+	public R getMenuList(FsMenuScrm map){
+		map.setIsShow(1);
+		List<FsMenuScrm> list=menuService.selectFsMenuList(map);
+		return R.ok().put("data",list);
+	}
+
 	@ApiOperation("读取个人中心")
 	@GetMapping("/getMenuUser")
 	@Cacheable("menuUser")