Просмотр исходного кода

改造sop发送飞书链接逻辑

cgp 12 часов назад
Родитель
Сommit
f2a6018e65

+ 0 - 37
fs-company-app/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java

@@ -349,41 +349,4 @@ public class FsUserCourseVideoController extends AppBaseController {
     public ResponseResult<Boolean> deleteImSendLog(@RequestParam Long logId) {
         return imMsgSendLogService.deleteFsImMsgSendLogAndDetail(logId);
     }
-
-    @Autowired
-    private FeiShuService feiShuService;
-
-    @Autowired
-    private ISysConfigService configService;
-
-    @Login
-    @ApiOperation("生成飞书初始链接")
-    @GetMapping("/getFeiShuCourseLink")
-    public R getFeiShuCourseLink(@RequestParam Long companyUserId,
-                                 @RequestParam Long videoId,
-                                 @RequestParam(required = false) Long companyId,
-                                 @RequestParam(required = false) Long courseId,
-                                 @RequestParam(required = false) Long projectId,
-                                 @RequestParam(required = false) Long id) {
-        // 读取配置判断是否启用飞书新跳转
-        Boolean enableFeishuNewLink = null;
-        try {
-            String json = configService.selectConfigByKey("course.config");
-            if (StringUtils.isNotBlank(json)) {
-                com.fs.course.config.CourseConfig config = cn.hutool.json.JSONUtil.toBean(json, com.fs.course.config.CourseConfig.class);
-                enableFeishuNewLink = config.getEnableFeishuNewLink();
-            }
-        } catch (Exception e) {
-            log.warn("读取飞书跳转配置失败", e);
-            throw new CustomException("读取飞书看课配置失败");
-        }
-
-        if (Boolean.TRUE.equals(enableFeishuNewLink)) {
-            String link = feiShuService.getFeishuRegisterLink(videoId, companyId, courseId,companyUserId);
-            log.info("链接{}", link);
-            return R.ok().put("data", link);
-        }
-        return R.error("未开启飞书看课,生成链接失败!");
-    }
-
 }

+ 2 - 1
fs-company/src/main/java/com/fs/company/controller/course/FeiShuCourseController.java

@@ -49,7 +49,8 @@ public class FeiShuCourseController extends BaseController {
 
         // 4. 调用业务层生成链接
         try {
-            String feishuLink = feiShuService.getFeishuRegisterLink(videoId, companyId, courseId, companyUserId);
+            //String feishuLink = feiShuService.getFeishuRegisterLink(videoId, companyId, courseId, companyUserId);
+            String feishuLink = null;
             return AjaxResult.success(feishuLink);
         } catch (CustomException e) {
             log.error("生成飞书看课链接业务异常:{}", e.getMessage());

+ 8 - 7
fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java

@@ -1211,18 +1211,19 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                     setting.setMiniprogramPage(phoneLinkBy);
                     setting.setContentType("17");
                     break;
+
                 case "18" :
                     //飞书看课链接
                     addWatchLogIfNeeded(sopLogs, videoId, courseId, sendTime, qwUserId, companyUserId, companyId, externalId, logVo);
 
                     Map<String, String> feiShuLinkMap = createFeiShuLinkByMiniApp(setting, sopLogs.getCorpId(), sendTime, courseId, videoId,
                             qwUserId, companyUserId, companyId, Long.parseLong(externalId), cachedCourseConfig);
-                    String feishuRealLink = feiShuLinkMap.get("url");
-                    String feishuLink = feiShuLinkMap.get("link");
-                    String feishuRedirectUrl = feiShuService.getFeishuRegisterLink(videoId,Long.valueOf(companyId),courseId,Long.valueOf(companyUserId));
-                    if (StringUtils.isNotEmpty(feishuRedirectUrl)) {
-                        setting.setFeiShuLinkUrl(feishuRedirectUrl);
-                        setting.setLinkUrl(feishuRedirectUrl);
+                    //课程短码
+                    String shortCode = feiShuLinkMap.get("link");
+                    String feishuLink = feiShuService.getFeishuRegisterLink(videoId,Long.valueOf(companyId),courseId,Long.valueOf(companyUserId),shortCode);
+                    if (StringUtils.isNotEmpty(feishuLink)) {
+                        setting.setFeiShuLinkUrl(feishuLink);
+                        setting.setLinkUrl(feishuLink);
                     }
                     break;
                 case "21"://短信看课
@@ -2416,7 +2417,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
     }
 
     /**
-     * 批量生成飞书课程链
+     * 生成课程
      * */
     private Map<String, String> createFeiShuLinkByMiniApp(QwSopTempSetting.Content.Setting setting, String corpId, Date sendTime,
                                                         Long courseId, Long videoId, String qwUserId,

+ 2 - 2
fs-service/src/main/java/com/fs/course/config/CourseConfig.java

@@ -18,8 +18,8 @@ public class CourseConfig implements Serializable {
     private Integer answerIntegral;//答题获得积分
     private Integer defaultLine;//默认看课线路
     private String realLinkDomainName;//真链域名
-    private String feishuLinkDomainName;//飞书看课域名
-    private String feishuNewLinkDomainName;//新飞书看课域名
+    private String feishuCourseDomain;//飞书看课域名
+    private String feishuAuthDomain;//飞书授权域名
     private Boolean enableFeishuNewLink;//是否启用飞书新跳转
     private String authDomainName;//网页授权域名
     private String smsDomainName;//短信推送域名

+ 154 - 175
fs-service/src/main/java/com/fs/feishu/service/FeiShuService.java

@@ -1,14 +1,13 @@
 package com.fs.feishu.service;
 
 import cn.hutool.json.JSONUtil;
-import com.fs.feishu.config.FeiShuConfig;
-import com.fs.feishu.model.FeishuFileDTO;
-import com.fs.feishu.model.FeishuLinkParam;
-import com.fs.feishu.util.SecureTokenUtil;
 import com.fs.common.exception.CustomException;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.FsUserCourseVideo;
 import com.fs.course.mapper.FsUserCourseVideoMapper;
+import com.fs.feishu.config.FeiShuConfig;
+import com.fs.feishu.model.FeishuFileDTO;
+import com.fs.feishu.model.FeishuLinkParam;
 import com.fs.system.service.ISysConfigService;
 import com.lark.oapi.Client;
 import com.lark.oapi.service.docx.v1.model.*;
@@ -21,23 +20,27 @@ import com.lark.oapi.service.drive.v2.model.PermissionPublic;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
 import javax.annotation.PostConstruct;
 import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
 import java.util.*;
 
-import org.springframework.stereotype.Component;
-
+/**
+ * 飞书云文档服务
+ * 负责生成飞书看课相关的注册文档和课程文档
+ */
 @Component
 @Slf4j
 public class FeiShuService {
 
-    private final String COURSE_PATH = "/feishu/pages_course/video?token=%s";
-
     @Autowired
     private FeiShuConfig feishuConfig;
+
     @Autowired
     private ISysConfigService configService;
+
     @Autowired
     private FsUserCourseVideoMapper videoMapper;
 
@@ -45,221 +48,197 @@ public class FeiShuService {
 
     @PostConstruct
     public void init() {
-        this.client = Client.newBuilder(feishuConfig.getAppId(), feishuConfig.getAppSecret()).logReqAtDebug(true).build();
+        this.client = Client.newBuilder(feishuConfig.getAppId(), feishuConfig.getAppSecret())
+                .logReqAtDebug(true)
+                .build();
     }
 
+    // ==================== 对外业务方法 ====================
+
     /**
-     * 001 生成飞书初始链接
+     * 生成注册授权页飞书文档(第一阶段)
      */
-    public String getFeishuRegisterLink(Long videoId, Long companyId, Long courseId,Long companyUserId) {
-        // 读取配置判断是否启用飞书新跳转
-        String json = configService.selectConfigByKey("course.config");
-        if (StringUtils.isBlank(json)) {
-            throw new CustomException("飞书看课配置为空");
-        }
-        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        Boolean enableFeishuNewLink = config.getEnableFeishuNewLink();
-        if (!Boolean.TRUE.equals(enableFeishuNewLink)) {
-            throw new CustomException("未开启飞书看课");
-        }
-
-        // 构建参数
-        FeishuLinkParam param = new FeishuLinkParam();
-        param.setCompanyId(companyId);
-        param.setCompanyUserId(companyUserId);
-        param.setCourseId(courseId);
-        param.setVideoId(videoId);
+    public String getFeishuRegisterLink(Long videoId, Long companyId, Long courseId,
+                                        Long companyUserId, String shortCode) {
+        CourseConfig config = getCourseConfig();
+        FsUserCourseVideo video = getVideoEntity(videoId);
 
-        FsUserCourseVideo userCourseVideo = videoMapper.selectFsUserCourseVideoByVideoId(param.getVideoId());
-        if (userCourseVideo == null) {
-            throw new CustomException("视频不存在: " + param.getVideoId());
-        }
+        // 1. 构建授权URL
+        String authUrl = buildAuthUrl(config, companyId, companyUserId, courseId, videoId, shortCode);
 
-        try {
-            // 创建云文档
-            String documentId = createDocument(userCourseVideo.getTitle() + "-注册");
-
-            // 拼接授权url
-            String authUrl = buildAuthLink(param.getCompanyId(), param.getCompanyUserId(),
-                    param.getCourseId(), param.getVideoId());
-
-            // 创建关注公众号 text + link block
-            createTextLinkBlock(documentId, authUrl);
-            // 更新文档权限
-            changeDocumentPermissions(documentId);
+        // 2. 构造文档内容
+        Block linkBlock = buildTextLinkBlock(authUrl, "观看课程");
 
-            // 返回飞书看课链接
-            return "https://www.feishu.cn/docx/" + documentId;
-        } catch (Exception e) {
-            throw new CustomException("创建飞书注册链接失败: " + e.getMessage(), e);
-        }
+        // 3. 创建文档并返回链接
+        String documentId = createFeishuDocument(video.getTitle() + "-注册", new Block[]{linkBlock});
+        return "https://www.feishu.cn/docx/" + documentId;
     }
 
-
-
     /**
-     * 002生成飞书课程链接
+     * 生成课程播放页飞书文档(第二阶段)
      */
     public String getFeishuCourseNewLink(FeishuLinkParam param) {
         if (param == null || param.getCompanyUserId() == null || param.getCompanyId() == null) {
             throw new CustomException("参数不能为空");
         }
 
-        FsUserCourseVideo userCourseVideo = videoMapper.selectFsUserCourseVideoByVideoId(param.getVideoId());
-        if (userCourseVideo == null) {
-            throw new CustomException("视频不存在: " + param.getVideoId());
-        }
-        try {
-            // 创建云文档
-            String documentId = createDocument(userCourseVideo.getTitle());
+        CourseConfig config = getCourseConfig();
+        FsUserCourseVideo video = getVideoEntity(param.getVideoId());
 
-            // 拼接新看课url
-            String url = buildCourseNewLink(param.getCompanyId(), param.getCompanyUserId(), param.getCourseId(), param.getVideoId(),param.getUserId());
+        // 1. 构建课程播放URL(已双重编码)
+        String courseUrl = buildCourseUrl(config, param);
 
-            // 创建iframe块
-            createIframeBlock(documentId, url);
+        // 2. 构造文档内容(一个iframe块)
+        Block iframeBlock = buildIframeBlock(courseUrl);
 
-            // 更新文档权限
-            changeDocumentPermissions(documentId);
+        // 3. 创建文档并返回链接
+        String documentId = createFeishuDocument(video.getTitle(), new Block[]{iframeBlock});
+        return "https://www.feishu.cn/docx/" + documentId;
+    }
+
+    // ==================== 核心文档创建流程 ====================
 
-            // 返回飞书看课链接
-            return "https://www.feishu.cn/docx/" + documentId;
+    /**
+     * 通用文档创建流程:创建文档 → 添加子块 → 设置权限
+     */
+    private String createFeishuDocument(String title, Block[] children) {
+        try {
+            String documentId = createDocument(title);
+            addDocumentChildren(documentId, children);
+            changeDocumentPermissions(documentId);
+            return documentId;
         } catch (Exception e) {
-            throw new CustomException("创建飞书课程链接失败: " + e.getMessage(), e);
+            throw new CustomException("创建飞书文档失败: " + e.getMessage(), e);
         }
     }
 
+    // ==================== 文档内容块构建 ====================
+
+    private Block buildTextLinkBlock(String url, String text) {
+        return Block.newBuilder()
+                .blockType(2) // 文本块
+                .text(Text.newBuilder()
+                        .elements(new TextElement[]{
+                                TextElement.newBuilder()
+                                        .textRun(TextRun.newBuilder()
+                                                .content(text)
+                                                .textElementStyle(TextElementStyle.newBuilder()
+                                                        .link(Link.newBuilder().url(url).build())
+                                                        .build())
+                                                .build())
+                                        .build()
+                        })
+                        .build())
+                .build();
+    }
+
+    private Block buildIframeBlock(String url) {
+        return Block.newBuilder()
+                .blockType(26) // iframe块
+                .iframe(Iframe.newBuilder()
+                        .component(IframeComponent.newBuilder()
+                                .iframeType(1)
+                                .url(url)
+                                .build())
+                        .build())
+                .build();
+    }
+
+    // ==================== 飞书API操作封装 ====================
 
-    /**
-     * 创建云文档
-     */
     private String createDocument(String title) throws Exception {
         CreateDocumentReq req = CreateDocumentReq.newBuilder()
                 .createDocumentReqBody(CreateDocumentReqBody.newBuilder().title(title).build())
                 .build();
-        CreateDocumentResp resp = client.docx().v1().document().create(req);
+        return client.docx().v1().document().create(req)
+                .getData().getDocument().getDocumentId();
+    }
+
+    private void addDocumentChildren(String documentId, Block[] children) throws Exception {
+        CreateDocumentBlockChildrenReq req = CreateDocumentBlockChildrenReq.newBuilder()
+                .documentId(documentId)
+                .blockId(documentId)
+                .documentRevisionId(-1)
+                .createDocumentBlockChildrenReqBody(
+                        CreateDocumentBlockChildrenReqBody.newBuilder()
+                                .index(0)
+                                .children(children)
+                                .build()
+                )
+                .build();
+        client.docx().v1().documentBlockChildren().create(req);
+    }
 
-        CreateDocumentRespBody data = resp.getData();
-        return data.getDocument().getDocumentId();
+    // ==================== URL构建工具 ====================
+
+    private String buildAuthUrl(CourseConfig config, Long companyId, Long companyUserId,
+                                Long courseId, Long videoId, String shortCode) {
+        Map<String, Object> params = new LinkedHashMap<>();
+        params.put("companyUserId", companyUserId);
+        params.put("videoId", videoId);
+        params.put("companyId", companyId);
+        params.put("courseId", courseId);
+        params.put("link", shortCode);
+        String fullUrl = config.getFeishuAuthDomain()
+                + "/feishuCourse/pages_course/wxauth?course=" + encodeJsonParam(params);
+        return encodeUrl(fullUrl);
     }
 
+    private String buildCourseUrl(CourseConfig config, FeishuLinkParam param) {
+        Map<String, Object> params = new LinkedHashMap<>();
+        params.put("companyUserId", param.getCompanyUserId());
+        params.put("videoId", param.getVideoId());
+        params.put("companyId", param.getCompanyId());
+        params.put("courseId", param.getCourseId());
+        String fullUrl = config.getFeishuCourseDomain()
+                + "/feishuCourse/pages_course/video?course=" + encodeJsonParam(params)
+                + "&userId=" + param.getUserId();
+        return encodeUrl(fullUrl);
+    }
 
     /**
-     * 拼接看课url(课程参数JSON方式,适配飞书iframe,双重URL编码)
+     * 将参数Map编码为JSON并URL编码(第一次编码)
      */
-    private String buildCourseNewLink(Long companyId, Long companyUserId, Long courseId, Long videoId,Long userId) {
-        String json = configService.selectConfigByKey("course.config");
-        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-
-        // 构造课程参数 JSON
-        Map<String, Object> courseParam = new LinkedHashMap<>();
-        courseParam.put("companyUserId", companyUserId);
-        courseParam.put("videoId", videoId);
-        courseParam.put("companyId", companyId);
-        courseParam.put("courseId", courseId);
-        //TODO: 查询这个用户对应的sop课程短链
-        courseParam.put("link", courseId);
-        String courseJson = JSONUtil.toJsonStr(courseParam);
+    private String encodeJsonParam(Map<String, Object> params) {
         try {
-            // 第一次编码:对JSON进行URL编码
-            String encodedJson = URLEncoder.encode(courseJson, "UTF-8");
-            // 拼接完整URL(userId与course参数同级)
-            String baseUrl = config.getFeishuNewLinkDomainName();
-            String fullUrl = baseUrl + "/feishuCourse/pages_course/video?course=" + encodedJson + "&userId=" +userId;
-            // 第二次编码:对整个URL进行URL编码(适配飞书iframe创建要求)
-            return URLEncoder.encode(fullUrl, "UTF-8");
+            String json = JSONUtil.toJsonStr(params);
+            return URLEncoder.encode(json, "UTF-8");
         } catch (UnsupportedEncodingException e) {
-            throw new CustomException("看课URL拼接失败", e);
+            throw new CustomException("参数JSON编码失败", e);
         }
     }
 
     /**
-     * 拼接授权url(课程参数JSON方式,适配飞书iframe,双重URL编码
+     * 对整个URL进行URL编码(第二次编码,用于iframe)
      */
-    private String buildAuthLink(Long companyId, Long companyUserId, Long courseId, Long videoId) {
-        String json = configService.selectConfigByKey("course.config");
-        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-
-        Map<String, Object> authParam = new LinkedHashMap<>();
-        authParam.put("companyUserId", companyUserId);
-        authParam.put("videoId", videoId);
-        authParam.put("companyId", companyId);
-        authParam.put("courseId", courseId);
-        String authJson = JSONUtil.toJsonStr(authParam);
-
+    private String encodeUrl(String url) {
         try {
-            String encodedJson = URLEncoder.encode(authJson, "UTF-8");
-            String baseUrl =config.getFeishuNewLinkDomainName();
-            String fullUrl = baseUrl + "/feishuCourse/pages_course/wxauth?course=" + encodedJson;
-            return URLEncoder.encode(fullUrl, "UTF-8");
+            return URLEncoder.encode(url, "UTF-8");
         } catch (UnsupportedEncodingException e) {
-            throw new CustomException("授权URL拼接失败", e);
+            throw new CustomException("URL编码失败", e);
         }
     }
 
-    /**
-     * 创建iframe块
-     */
-    private void createIframeBlock(String documentId, String url) throws Exception {
-        CreateDocumentBlockChildrenReq req = CreateDocumentBlockChildrenReq.newBuilder()
-                .documentId(documentId)
-                .blockId(documentId)
-                .documentRevisionId(-1)
-                .createDocumentBlockChildrenReqBody(CreateDocumentBlockChildrenReqBody.newBuilder()
-                        .children(new Block[] {
-                                Block.newBuilder()
-                                        .blockType(26)
-                                        .iframe(Iframe.newBuilder()
-                                                .component(IframeComponent.newBuilder()
-                                                        .iframeType(1)
-                                                        .url(url).build()
-                                                ).build()
-                                        )
-                                        .build()
-                        })
-                        .index(0)
-                        .build())
-                .build();
+    // ==================== 配置与数据获取 ====================
 
-        // 发起请求
-        client.docx().v1().documentBlockChildren().create(req);
+    private CourseConfig getCourseConfig() {
+        String json = configService.selectConfigByKey("course.config");
+        if (StringUtils.isBlank(json)) {
+            throw new CustomException("飞书看课配置为空");
+        }
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        if (!Boolean.TRUE.equals(config.getEnableFeishuNewLink())) {
+            throw new CustomException("未开启飞书看课");
+        }
+        return config;
     }
 
-    /**
-     * 创建 text + link block
-     */
-    private void createTextLinkBlock(String documentId, String url) throws Exception {
-
-        CreateDocumentBlockChildrenReq req = CreateDocumentBlockChildrenReq.newBuilder()
-                .documentId(documentId)
-                .blockId(documentId)
-                .documentRevisionId(-1)
-                .createDocumentBlockChildrenReqBody(
-                        CreateDocumentBlockChildrenReqBody.newBuilder()
-                                .index(0)
-                                .children(new Block[] {
-                                        Block.newBuilder()
-                                                .blockType(2)
-                                                .text(Text.newBuilder()
-                                                        .elements(new TextElement[] {
-                                                                TextElement.newBuilder()
-                                                                        .textRun(TextRun.newBuilder()
-                                                                                .content("观看课程")
-                                                                                .textElementStyle(TextElementStyle.newBuilder()
-                                                                                        .link(Link.newBuilder()
-                                                                                                .url(url)
-                                                                                                .build())
-                                                                                        .build())
-                                                                                .build())
-                                                                        .build()
-                                                        })
-                                                        .build())
-                                                .build()
-                                })
-                                .build())
-                .build();
-
-        client.docx().v1().documentBlockChildren().create(req);
+    private FsUserCourseVideo getVideoEntity(Long videoId) {
+        FsUserCourseVideo video = videoMapper.selectFsUserCourseVideoByVideoId(videoId);
+        if (video == null) {
+            throw new CustomException("视频不存在: " + videoId);
+        }
+        return video;
     }
 
     /**
@@ -391,7 +370,7 @@ public class FeiShuService {
                 log.error("删除失败: {} | token={} | err={}", file.getName(), file.getToken(), e.getMessage());
             }
         }
-        log.info("飞书文档清理完成 | 列表总数={} | 删除成功={}", total, deleted);
+        log.info("飞书看课文档清理完成 | 列表总数={} | 删除成功={}", total, deleted);
     }
 
-}
+}

+ 38 - 28
fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsInfoServiceImpl.java

@@ -1136,39 +1136,43 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                             break;
                         //飞书看课
                         case "18":
-                            // 飞书看课(第一阶段:发送注册授权链接)
+
                             addWatchLogIfNeeded(param.getSopId(), param.getVideoId(), param.getCourseId(),
                                     item.getFsUserId(), qwUserId, companyUserId, companyId,
                                     item.getExternalId(), param.getStartTime(), createTime);
 
-                            // 参数转换(注意判空,避免NPE)
-                            Long videoId = param.getVideoId() != null ? param.getVideoId().longValue() : null;
-                            Long courseId = param.getCourseId() != null ? param.getCourseId().longValue() : null;
+                            // 参数转换
+                            Integer videoId = param.getVideoId() != null ? param.getVideoId().intValue() : null;
+                            Integer courseId = param.getCourseId() != null ? param.getCourseId().intValue() : null;
                             Long companyIdLong = Long.parseLong(companyId);
                             Long companyUserIdLong = Long.parseLong(companyUserId);
-
                             if (videoId == null) {
                                 log.error("飞书链接生成失败:视频ID为空,sopId={}", param.getSopId());
                                 break;
                             }
+                            // 替换占位符(销售称呼、客户称呼等)
+                            String txt = StringUtil.strIsNullOrEmpty(qwUser.getWelcomeText()) ? "" : qwUser.getWelcomeText();
+                            String customerTitle = StringUtil.strIsNullOrEmpty(contact.getStageStatus()) || "0".equals(contact.getStageStatus()) ? "同学" : contact.getStageStatus();
+                            if (StringUtils.isNotEmpty(st.getLinkTitle())) {
+                                st.setLinkTitle(st.getLinkTitle()
+                                        .replaceAll("#销售称呼#", txt)
+                                        .replaceAll("#客户称呼#", customerTitle));
+                            }
+                            if (StringUtils.isNotEmpty(st.getLinkDescribe())) {
+                                st.setLinkDescribe(st.getLinkDescribe()
+                                        .replaceAll("#销售称呼#", txt)
+                                        .replaceAll("#客户称呼#", customerTitle));
+                            }
 
-                            // 调用 001 方法:生成注册授权链接
-                            String feishuLink = feiShuService.getFeishuRegisterLink(videoId, companyIdLong, courseId, companyUserIdLong);
+
+                            Map<String, String> feishuH5Link = createFeishuH5Link(st, param.getCorpId(), createTime, courseId, videoId, String.valueOf(qwUser.getId()), companyUserId, companyId, item.getExternalId(), config);
+                            //获取生成的课程短链码
+                            String shortCode = feishuH5Link.get("link");
+                            // 调用生成飞书注册授权链接
+                            String feishuLink = feiShuService.getFeishuRegisterLink(videoId.longValue(), companyIdLong, courseId.longValue(), companyUserIdLong,shortCode);
 
                             if (StringUtils.isNotEmpty(feishuLink)) {
-                                // 替换占位符(销售称呼、客户称呼等)
-                                String txt = StringUtil.strIsNullOrEmpty(qwUser.getWelcomeText()) ? "" : qwUser.getWelcomeText();
-                                String customerTitle = StringUtil.strIsNullOrEmpty(contact.getStageStatus()) || "0".equals(contact.getStageStatus()) ? "同学" : contact.getStageStatus();
-                                if (StringUtils.isNotEmpty(st.getLinkTitle())) {
-                                    st.setLinkTitle(st.getLinkTitle()
-                                            .replaceAll("#销售称呼#", txt)
-                                            .replaceAll("#客户称呼#", customerTitle));
-                                }
-                                if (StringUtils.isNotEmpty(st.getLinkDescribe())) {
-                                    st.setLinkDescribe(st.getLinkDescribe()
-                                            .replaceAll("#销售称呼#", txt)
-                                            .replaceAll("#客户称呼#", customerTitle));
-                                }
+
                                 st.setLinkUrl(feishuLink);
                             } else {
                                 log.error("生成飞书注册链接失败,sopId={}", param.getSopId());
@@ -1821,24 +1825,27 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                     break;
                 //飞书看课
                 case "18":
-                    // 飞书看课(第一阶段:发送注册授权链接)
                     addWatchLogIfNeeded(item.getSopId(), param.getVideoId(), param.getCourseId(),
                             item.getFsUserId(), String.valueOf(qwUser.getId()), companyUserId, companyId,
                             item.getExternalId(), item.getStartTime(), dataTime);
 
                     // 参数转换
-                    Long videoId = param.getVideoId() != null ? param.getVideoId().longValue() : null;
-                    Long courseId = param.getCourseId() != null ? param.getCourseId().longValue() : null;
+                    Integer videoId = param.getVideoId() != null ? param.getVideoId().intValue() : null;
+                    Integer courseId = param.getCourseId() != null ? param.getCourseId().intValue() : null;
                     Long companyIdLong = Long.parseLong(companyId);
                     Long companyUserIdLong = Long.parseLong(companyUserId);
-
+                    String qwUserId = String.valueOf(qwUser.getId());
+                    Long externalId = item.getExternalId();
                     if (videoId == null) {
                         log.error("飞书链接生成失败:视频ID为空,sopId={}", item.getSopId());
                         break;
                     }
 
-                    // 调用 001 方法:生成注册授权链接
-                    String feishuLink = feiShuService.getFeishuRegisterLink(videoId, companyIdLong, courseId, companyUserIdLong);
+                    Map<String, String> feishuH5Link = createFeishuH5Link(st, param.getCorpId(), dataTime, courseId, videoId, qwUserId, companyUserId, companyId, externalId, config);
+                    //获取生成的课程短链码
+                    String shortCode = feishuH5Link.get("link");
+                    // 调用生成飞书注册授权链接
+                    String feishuLink = feiShuService.getFeishuRegisterLink(videoId.longValue(), companyIdLong, courseId.longValue(), companyUserIdLong,shortCode);
 
                     if (StringUtils.isNotEmpty(feishuLink)) {
                         // 替换占位符
@@ -1909,6 +1916,9 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
         return  list;
     }
 
+    /**
+     * 生成课程链接
+     * */
     private Map<String, String> createFeishuH5Link(QwSopCourseFinishTempSetting.Setting setting, String corpId, Date sendTime,
                                                    Integer courseId, Integer videoId, String qwUserId,
                                                    String companyUserId, String companyId, Long externalId, CourseConfig config) {
@@ -1925,8 +1935,8 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
         link.setUpdateTime(createUpdateTime(setting, sendTime, config));
         fsCourseLinkMapper.insertFsCourseLink(link);
         Map<String, String> result = new HashMap<>();
-        result.put("url", link.getRealLink());
-        result.put("link", link.getLink());
+        result.put("url", link.getRealLink());//真实课程链接
+        result.put("link", link.getLink());//课程短链
         return result;
     }