vue页面嵌入飞书网页组件,用于在类似ERP,OA等系统中展示在线文档

news2025/1/11 6:54:22

先展示最终效果(就是在vue页面中,内嵌了一块ifream页面):

1. 注册进入飞书开放平台,地址为: 飞书开放平台

2.进入开放平台后,选择--创建企业自建应用--创建网页应用,然后在主页面记住该应用的appId和appSecret参数,后面要用

3.然后注意一点的是,因为后面的授权等逻辑我们一般用我们自己的文档做测试,但是自己的文档也属于企业,所以需要将平台应用正式上线,这个需要企业管理员审核,提前说明一下,还需要开通部分接口和数据权限,也是需要审核的.建议最好弄个管理员账号过来开一下

4.在开放平台--开发者后台这里,点击左侧菜单栏的[添加应用能力]页签,然后在右侧菜单选择网页组件

然后在弹出框中点击[如何开发]进入到官方文档中

进入文档页面后,切换左侧的菜单到网页组件中,使用这个组件:

5. 使用该组件,最开始的一件事就是要完成一圈授权流程,在这里将会用到的授权的参数记录如下:

private static final String APP_ID                  = "";

private static final String APP_SECRET              = "";

/** 用appId和appSecret获取tenant_access_token(租户授权,目前用不到,暂时留存) */
private static final String TENANT_ACCESS_TOKEN_URI = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal";

/** 获取ticket参数的api */
private static final String JSAPI_TICKET_URI        = "https://open.feishu.cn/open-apis/jssdk/ticket/get";

/** 加签sha1的一个随机参数 */
private static final String NONCE_STR               = "abc123def456";

/** 用appId和appSecret获取app_access_token(应用级别的授权(只允许查看,不允许编辑,分享等功能权限)) */
private static final String APP_ACCESS_TOKEN_URI    = "https://open.feishu.cn/open-apis/auth/v3/app_access_token/internal";

/** 用户访问令牌(用户级别授权,和用户权限挂钩,唯有这种授权在用户拥有权限的情况下,可以实现在线编辑文档,目前暂不做) */
private static final String USER_ACCESS_TOKEN_URI   = "https://open.feishu.cn/open-apis/authen/v1/access_token";

/** 用户信息接口路径 */
private static final String USER_INFO_URI           = "https://open.feishu.cn/open-apis/authen/v1/user_info";

private static final String DOCUMENT_URL            = "https://xxxxxxx.feishu.cn/docx/xxxxxxxxxxxxxx";

需要注意的两个点是:

(1). 如果你使用app_access_token去进行后续的验证,那么默认无法获得在线文档编辑的操作,只允许操作,只有当使用user_access_token权限认证,才可以根据用户的权限进行后续的编辑等操作

(2). 请注意DOCUMENT_URL这个参数,这个组件貌似目前只能用/docs下的文档进行渲染,而不可以用我们知识库下的wiki组件,也就是说,你打开的文档如果是wiki的,那么需要将他另存到共享空间中,就会自动变成docs.才可以用

6.授权参数明确后,还有一件事,就是需要开通对应权限,开通对应的权限后还需要上架最新的应用

        (1):TENANT_ACCESS_TOKEN_URI不需要开通权限

        (2):APP_ACCESS_TOKEN_URI: 不需要开通权限

        (3):USER_ACCESS_TOKEN_URI:需要权限如下

7.授权相关后台代码(用了Hutool的Http请求封装,自己引入或者改一下):

package com.ruoyi.biz.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.biz.vo.FeishuWebComponentAuthVo;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * @author zhaoyuyang
 */
@RestController
@RequestMapping("/biz/help")
@Slf4j
public class HelpController extends BaseController
{
    private static final String APP_ID                  = "";

    private static final String APP_SECRET              = "";

    /** 用appId和appSecret获取tenant_access_token(租户授权,目前用不到,暂时留存) */
    private static final String TENANT_ACCESS_TOKEN_URI = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal";

    /** 获取ticket参数的api */
    private static final String JSAPI_TICKET_URI        = "https://open.feishu.cn/open-apis/jssdk/ticket/get";

    /** 加签sha1的一个随机参数 */
    private static final String NONCE_STR               = "abc123def456";

    /** 用appId和appSecret获取app_access_token(应用级别的授权(只允许查看,不允许编辑,分享等功能权限)) */
    private static final String APP_ACCESS_TOKEN_URI    = "https://open.feishu.cn/open-apis/auth/v3/app_access_token/internal";

    /** 用户访问令牌(用户级别授权,和用户权限挂钩,唯有这种授权在用户拥有权限的情况下,可以实现在线编辑文档,目前暂不做) */
    private static final String USER_ACCESS_TOKEN_URI   = "https://open.feishu.cn/open-apis/authen/v1/access_token";

    /** 用户信息接口路径 */
    private static final String USER_INFO_URI           = "https://open.feishu.cn/open-apis/authen/v1/user_info";

    private static final String DOCUMENT_URL            = "替换你自己的文档全路径";

    /**
     * 获取签名数据
     */
    @GetMapping("/getSignData")
    public AjaxResult getSignData()
    {
        // 1. 通过app_id和app_secret获取app_access_token
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("app_id", HelpController.APP_ID);
        paramMap.put("app_secret", HelpController.APP_SECRET);
        String returnStr = HttpUtil.post(HelpController.APP_ACCESS_TOKEN_URI,
                paramMap);
        JSONObject jsonObject = JSONObject.parseObject(returnStr);
        String appAccessToken = jsonObject.getString("app_access_token");
        // 2.通过tenantAccessToken获取ticket
        String ticketResponseStr = HttpRequest
                .post(HelpController.JSAPI_TICKET_URI)
                .header("Authorization", "Bearer " + appAccessToken).execute()
                .body();
        String ticket = JSONObject.parseObject(ticketResponseStr)
                .getJSONObject("data").getString("ticket");
        // 3.按照要求拼接Signature,然后使用sha1进行加密
        StringBuilder signatureBuilder = new StringBuilder();
        Long timeStamp = System.currentTimeMillis();
        signatureBuilder.append("jsapi_ticket=").append(ticket)
                .append("&noncestr=").append(HelpController.NONCE_STR)
                .append("&timestamp=").append(timeStamp).append("&url=")
                .append(HelpController.DOCUMENT_URL);
        String signature = cn.hutool.crypto.SecureUtil
                .sha1(signatureBuilder.toString());
        // 4.返回数据,组装数据
        FeishuWebComponentAuthVo returnVo = new FeishuWebComponentAuthVo();
        List<String> list = new ArrayList<>();
        list.add("DocsComponent");
        // 如果为app_access_token模式进行授权,则不输入openId参数
        returnVo.setOpenId("").setSignature(signature)
                .setAppId(HelpController.APP_ID)
                .setTimestamp(timeStamp.toString())
                .setNonceStr(HelpController.NONCE_STR)
                .setUrl(HelpController.DOCUMENT_URL).setJsApiList(list)
                .setLocale("zh-CN");
        return AjaxResult.success(returnVo);
    }
}

8.前端代码:

<template>
  <div class="app-container">
    <div id="feishu-page"></div>
  </div>
</template>
<script>
import { getSignData } from '@/api/biz/help'
export default {
  data() {
    return {}
  },
  created() {
    this.$modal.loading('正在加载文档')
  },
  mounted() {
    const script = document.createElement('script')
    script.src =
      'https://lf1-cdn-tos.bytegoofy.com/goofy/locl/lark/external_js_sdk/h5-js-sdk-1.1.3.js'
    script.async = true
    script.onload = () => {
      // 执行一些操作,例如初始化该库或者调用一些方法
      this.authPage()
    }
    document.head.appendChild(script)
  },
  methods: {
    authPage() {
      getSignData().then((response) => {
        let openId = response.data.openId
        let signature = response.data.signature
        let appId = response.data.appId
        let timestamp = response.data.timestamp
        let nonceStr = response.data.nonceStr
        let url = response.data.url
        let jsApiList = response.data.jsApiList
        let locale = response.data.locale
        let that = this
        window.webComponent
          .config({
            openId, // 当前登录用户的open id,要确保与生成 signature 使用的 user_access_token 相对应,使用 app_access_token 时此项不填。注意:仅云文档组件可使用app_access_token
            signature, // 签名
            appId, // 应用 appId
            timestamp, // 时间戳(毫秒)
            nonceStr, // 随机字符串
            url, // 第3步参与加密计算的url,同时也是最终需要访问的url
            jsApiList, // 指定要使用的组件列表,请根据对应组件的开发文档填写。如云文档组件,填写['DocsComponent']
            locale, // 指定组件的国际化语言:en-US-英文、zh-CN-中文、ja-JP-日文
          })
          .then((res) => {
            // 动态渲染,返回组件实例。
            let myComponent = window.webComponent.render(
              'DocsComponent',
              {
                //组件参数
                src: url,
                minHeight: '500px',
                height: '1100px', //该参数控制了页面的最大展开高度,不允许为Auto,也不能不写,会导致锚点定位,文本搜索失效
                width: '100%',
              },
              document.querySelector('#feishu-page'), // 将组件挂在到哪个元素上
            )
            // 通过setFeatureConfig方法修改组件的配置属性
            myComponent.config.setFeatureConfig({
              //文档头部菜单栏
              HEADER: {
                enable: true, // 隐藏头部
              },
              //点赞
              LIKE: {
                enable: true, // 隐藏点赞
              },
              //图片
              IMAGE: {
                maxWidth: 500, // 图片最大宽度
              },
              //分享
              SHARE: {
                enable: false, // 是否显示分享按钮
                visibleConfig: {
                  // 区域的显隐配置
                  invite: false, //邀请区域
                  shareLink: false, //分享链接区域
                  shareMethod: false, //分享方式区域
                },
              },
              //模态窗
              MODAL: {
                innerMask: true, // 有模态窗时, 组件内是否有遮罩
                outerMask: {
                  enable: true, // 有模态窗时, 组件外是否有遮罩
                  zIndex: 1000, // 遮罩层的z-index
                },
                offset: {
                  // 模态窗的偏移量
                  x: 0,
                  y: 0,
                },
              },
              //文档内容
              CONTENT: {
                readonly: false, // 是否只读
                padding: [0, 0, 0, 0], // 文档内边距,例:[10, 0, 10, 0] 为上下增加 10 px 边距
                maxWidth: 0, //内部最大宽度
                titleVisible: true, //标题是否可见
                unscrollable: false, //云文档组件是都允许滚动
              },
              //评论
              COMMENT: {
                partial: {
                  //局部评论
                  enable: false, //是否启用局部评论
                  open: false, //是否展开局部评论侧栏
                },
                global: {
                  //全局评论
                  enable: false, //是否启用全局评论
                },
              },
              //侧边栏
              SIDEBAR: {
                borderSide: [false, false, false, false], //侧边栏边框显隐,例:[true, true, false, false] 上、右侧有边框
              },
              //目录
              DIRECTORY: {
                enable: true, //是否显示目录
                pin: true, //是否固定目录
              },
              //文档头部右侧更多菜单
              MORE_MENU: {
                enable: true, //是否显示更多菜单
                items: {
                  //菜单子项
                  findAndReplaceEnable: true, //是否显示查找替换
                  makeCopyEnable: false, //是否显示创建副本
                  applyEditPermissionEnable: false, //是否显示申请编辑权限入口
                  exportEnable: false, //是否显示导出
                  documentInfoEnable: false, //是否显示文档详情
                  editHistoryEnable: false, //是否显示编辑历史'
                  commentHistoryEnable: false, //是否显示评论历史
                  translateEnable: false, //是否显示翻译
                  printEnable: false, //是否显示打印
                  deleteEnable: false, //是否显示删除
                },
              },
              //右下角全屏按钮
              FULLSCREEN: {
                enable: true, //是否显示按钮
              },
              //文档头部右侧协作者列表
              COLLABORATOR: {
                enable: false, //是否显示协作者列表
              },
            })
            myComponent.event.onMountSuccess(function () {
              that.$modal.closeLoading()
            })
          })
      })
    },
  },
}
</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1030608.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android设计支持库

本文所有的代码均存于 https://github.com/MADMAX110/BitsandPizzas 设计支持库&#xff08;Design Support Library&#xff09;是 Google 在 2015 年的 I/O 大会上发布的全新 Material Design 支持库&#xff0c;在这个 support 库里面主要包含了 8 个新的 Material Design …

clickhouse简单安装部署

目录 前言(来源于官方文档)&#xff1a; 一.下载并上传 1.下载地址&#xff1a;点我跳转下载 2.上传至Linux 二.解压和配置 1.解压顺序 注意&#xff1a;必须按照以下顺序解压&#xff0c;并且每解压一个都要执行该解压后文件的install/doinst.sh文件 解压步骤&#xff…

antd-design-vue Table组件全局配置(分页器...)

描述&#xff1a;该框架许多默认配置好像还不支持&#xff0c;一般都是挨个使用挨个配置。我的项目中也遇到了类似的情况&#xff0c;但是当需求发生变化时&#xff0c;代码所有的组件使用则都需要修改&#xff0c;这种方式真的很不礼貌。 《我为了一口醋包了顿饺子》 需求是将…

MQ - 19 安全_限流方案的设计

文章目录 导图Pre概述集群中的数据加密加密算法分类消息队列限流机制思考单机限流全局限流全局限流还是单机限流?对哪些资源和维度进行限流发生限流后怎么处理消息队列全局限流设计单机限流方案全局限流方案消息队列的服务降级配置 Broker 的 CPU 或内存的使用率额度配置磁盘保…

C语言每日一题(5):求两个数二进制中不同位的个数

文章主题&#xff1a;求两个数二进制中不同位的个数&#x1f525;所属专栏&#xff1a;C语言每日一题&#x1f4d7;作者简介&#xff1a;每天不定时更新C语言的小白一枚&#xff0c;记录分享自己每天的所思所想&#x1f604;&#x1f3b6;个人主页&#xff1a;[₽]的个人主页&a…

BOA服务器移植

BOA服务器移植 1、源码下载 http://www.boa.org/ News! (last updated 23 February 2005) Latest Released Version (0.94.13) here (signature here) --- 下载地址1.1 boa简介&#xff1a; 其可执行代码只有大约60KB左右&#xff0c;Boa是一个单任务的HTTP服务器&#xff…

MyBatisPlus(五)配置表名前缀:table-prefix

说明 数据库中的表名&#xff0c;和项目中的实体类名&#xff0c;并不符合默认对应规则。所有表都有同样的前缀&#xff0c;而实体类名是和表名去掉前缀后的部分对应的。 解决方案 配置全局表名前缀&#xff0c;使实体类名对应的表名&#xff0c;自动加上一段前缀。 限制 …

JSON 串和 Java 对象的相互转换

JSON 串和 Java 对象的相互转换 以 json 格式的数据进行前后端交互 前端发送请求时&#xff0c;如果是复杂的数据就会以 json 提交给后端&#xff1b; 而后端如果需要响应一些复杂的数据时&#xff0c;也需要以 json 格式将数据响应回给浏览器 为达到以上目的就需要重点学习…

基于微信小程序的美术馆预约平台设计与实现(源码+lw+部署文档+讲解等)

前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f447;&#x1f3fb;…

Linux_9_网络协议和管理

目录 1网络基础1.1 网络概念1.2常见的网络物理组件1.3网络应用程序1.3.1各种网络应用1.3.2应用程序对网络的要求 1.4网络的特征1.4.1速度(带宽)1.4.2网络拓扑 1.5网络1.5.1网络准和分层1.5.2开放系统互联OSI1.5.3网络的通信过程1.5.3.1数据封装和数据解封1.5.3.2协议数据单元PD…

基于SSM的四六级报名与成绩查询系统的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

机器学习 day36(纯度)

熵 这些例子的纯度和熵如图所示&#xff0c;且左侧为熵函数图熵函数是判断某组数据是否纯度高的指标 熵函数公式如上图&#xff0c;底数为2仅为了使函数峰值为1&#xff0c;且设定0log(0)为0&#xff0c;但log(0)为无穷大

【Java 基础篇】Java实现文件搜索详解

文件搜索是计算机应用中的一个常见任务&#xff0c;它允许用户查找特定文件或目录&#xff0c;以便更轻松地管理文件系统中的内容。在Java中&#xff0c;您可以使用各种方法来实现文件搜索。本文将详细介绍如何使用Java编写文件搜索功能&#xff0c;以及一些相关的内容。 文件…

【数据结构】图的应用:最小生成树;最短路径;有向无环图描述表达式;拓扑排序;逆拓扑排序;关键路径

目录 1、最小生成树 1.1 概念 1.2 普利姆算法&#xff08;Prim&#xff09; 1.3 克鲁斯卡尔算法&#xff08;Kruskal&#xff09; 2、最短路径 2.1 迪杰斯特拉算法&#xff08;Dijkstra&#xff09; 2.2 弗洛伊德算法&#xff08;Floyd&#xff09; 2.3 BFS算法&…

windows主机和vmware ubuntu18.04虚拟机ping通

windows主机 网线连接电脑&#xff0c;读取当前windows的相关信息 powershell 更改IP地址指令 New-NetIPAddress -InterfaceIndex 23 -IPAddress 192.168.0.105 -PrefixLength 24 -DefaultGateway 192.168.0.1 虚拟机 虚拟机需要管理员权限打开 选择桥接方式 IPV4地址改成同…

求生之路2专用服务器搭建对抗模式,药抗模式,特殊模式Ubuntu系统另附上游戏代码以及控制台代码

求生之路2专用服务器搭建对抗模式,药抗模式,特殊模式Ubuntu系统另附上游戏代码以及控制台代码 大家好我是艾西&#xff0c;熟悉Left 4 Dead 2求生之路2这游戏的小伙伴都知道这个游戏分为以下几种模式&#xff1a; 对抗模式&#xff1a;在对抗模式下&#xff0c;玩家需要掌握一…

小白的入门二叉树(C语言实现)

前言&#xff1a; 二叉树属于数据结构的一个重要组成部分&#xff0c;很多小白可能被其复杂的外表所吓退&#xff0c;但我要告诉你的是“世上无难事&#xff0c;只怕有心人”&#xff0c;我将认真的对待这篇博客&#xff0c;我相信只要大家敢于思考&#xff0c;肯定会有所收获…

Stm32_标准库_1

代码&#xff1a; #include "stm32f10x.h" // Device headerGPIO_InitTypeDef GPIO_InitStructure;//定义变量结构体int main(void){/*使用RCC开启GPIO的时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//开启PA端口时钟/*使用GPIO_…

折线图geom_line()参数选项

往期折线图教程 图形复现| 使用R语言绘制折线图折线图指定位置标记折线图形状更改 | 绘制动态折线图跟着NC学作图 | 使用python绘制折线图 前言 我们折线的专栏推出一段时间&#xff0c;但是由于个人的原因&#xff0c;一直未进行更新。那么今天&#xff0c;我们也参考《R语…

(循环)mysql定时器删除某表中数据例子

CREATE EVENT clear_interactive_logs ON SCHEDULE EVERY 1 DAY STARTS 2023-09-21 23:36:36 DO DELETE from t_interactive_log WHERE id not IN (SELECT * from (SELECT id from t_interactive_log ORDER BY occer_time DESC limit 20000) x ); END ———————————…