前言

最近在公司里得到了一项任务,人事给了一个 飞书的职位表格 ,要求将里面的信息更新到官网上面去。其中涉及了已有岗位的信息更新,删除部分岗位和添加部分岗位。这种工作虽然简单,但是很琐碎,很麻烦。

三十个岗位的 岗位列表岗位详情 花了我一个早上去 更新及核对 。主要的工作量都在于 表格的数据结构和代码中的数据结构不同需要进行一个修改 以及 更新后数据后网站展示情况的核对

作为一个程序员当然得想办法优化一下整体的流程,正好本身就知道飞书是有开放api的,于是就开始琢磨着能不能基于飞书表格将内容自动化生成一下,这样人事那边只需要 维护飞书表格 即可。

开发

获取数据

说锤就锤,首先要了解的是飞书的开放api是如何调用的,这里可以直接参考 飞书开放平台 中对应功能的介绍,还是很清晰的。

如果想要获取一个多维表格中的数据主要的工作是以下两步:

  1. 注册一个飞书应用以获取 appIdappSecret
  2. 调用接口传入appIdappSecret 鉴权获取 应用身份(tenant_access_token)
  3. 调用多维表开放api并将 token 及对应的表格信息传入获取 表格数据

开放平台提供了3种不同类型的访问凭证,用于验证调用方身份、确保调用方具有执行操作所需要的权限:
app_access_token:

应用:授权凭证,开放平台可据此识别调用方的应用身份,应用可以访问应用自身相关的信息,不归属到具体的企业或者用户,比如获取当前登录应用的用户身份。tenant_access_token:

租户:授权凭证,使用该access token,应用将代表公司或者团队执行对应的操作,比如获取一个通讯录用户的信息。user_access_token:

用户:授权凭证,使用该access token,应用将代表用户执行对应的操作,比如通过API 创建一篇云文档或者一个日程。

因为我们的网站是使用 next.js 写的,服务端渲染并没有涉及到前后端交互,因此我没有使用 axios 而是直接使用 request 这个库进行请求发送。事实上飞书的开放api为了保障安全也只允许 服务端 进行调用。

实现的代码如下:

const { promisify } = require("util")
const request = promisify(require("request"))
async function updateCareer() {// 请求获取tokenconst tokenRes = await request({url: "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",body: {app_id: APP_ID,app_secret: APP_SECRET},json: true,method: "POST",headers: {"content-type": "application/json",},})// 请求获取表格数据const tableRes = await request({url: "https://open.feishu.cn/open-apis/bitable/v1/apps/bascnuEd4NBfjyptIQKl6I75J3e/tables/tbl22HQor1gcwe2A/records",method: "GET",headers: {"Content-Type": "application/json; charset=utf-8","Authorization": "Bearer " + tokenRes.body.tenant_access_token},})
}

在上面的代码中,我首先引入了 promisify 这个方法使 request 可以实现 promise化 的使用,更加清晰的进行异步编程,然后就是分别调用两个接口获取表格的数据。

我们先发送请求获取 tenant_access_token ,之后将 tenant_access_token 拼接后作为请求头的 Authorization 发送给获取表格数据的接口,接口的url中需要拼接上我们的 表格id

数据格式化

在获取到表格的数据后,我们需要进行一定的格式化后再将其生成为代码,我们网站的岗位列表页面如下图:

这样的一个列表是基于一个json文件生成的,其中有两个列表分别对应中文和英文,每一张卡片对应的数据结构如下:

{"zh-CN": [{"title": "产品运营经理","href": "/careers/product-marketing-manager","type": "技术中心","description": " 学习研究公司的 SaaS 产品 APISEVEN Cloud;"}],"en-US": [{"title": "Product Marketing Manager","href": "/careers/product-marketing-manager","type": "Technology Center","description": " Learn about our SaaS product APISEVEN Cloud;"}]}

而咱们从表格中取出的数据结构如下:

{id: 'recwb6xrfK',record_id: 'recwb6xrfK',fields: {'Job Responsibilities': 'xxx','部门': '运营部','岗位说明最后修改日期': 1635523200000,'任职要求': 'xxxx','岗位状态': 'OPEN','岗位名称': '技术文档 实习生\nTechnical Writer(Internship)'},fileName: 'technical-writer(internship)'},

因此需要一个方法将数据进行格式化,这里的实现与表格具体内容关联性较强,不展开介绍,下面是我写的一个格式化的方法:

function formatCareerList(tableData) {const careerList = {"zh-CN": [],"en-US": []}tableData.forEach((item, index) => {const [zhTitle, enTitle] = item.fields["岗位名称"].split("\n")const fileName = (enTitle || zhTitle).replace(/ |\/|\\/ig, "-").toLowerCase()tableData[index].fileName = fileNameconst href = "/careers/" + fileNameconst typeMap = {"技术中心": "Technology Center","运营部": "Operation Department","职能部": "Functional Department","销售部": "Sales Department","Global Team": "Global Team"}const zhType = item.fields["部门"]const enType = typeMap[zhType]const zhDesc = item.fields["岗位职责"].split("\n")[0].substr(2)const enDesc = item.fields["Job Responsibilities"].split("\n")[0].substr(2)careerList["zh-CN"].push({title: zhTitle,href,type: zhType,description: zhDesc})careerList["en-US"].push({title: enTitle || "",href,type: enType,description: enDesc})})return careerList
}

主要的操作就是解构赋值或者对象进行一个数据的映射,实现一个数据的格式化,并且生成中文和英文的两个对象数组。

生成岗位详情

在岗位列表生成后,还需要生成 岗位介绍详情 ,也就是列表中 href 字段跳转过去的那个页面。当前我们的岗位介绍是通过 markdown文档 渲染生成的,格式大致如下:

---
title: job name
date: xxx
---### 岗位职责xxx### 任职要求xxx### 附加信息xxx### 联系方式xxx

因此我写了两个生成中文内容和英文内容两个单独的方法,利用 模板字符串 传入参数生成md文档的内容,使用模板字符串可以支持我们编辑可以换行的文本,而且在文本中嵌入变量也特别方便,下面展示一下英文版模板生成的方法:

// enTemplate.js
module.exports = function enTemplate(fields) {const date = new Date()return `---
title: ${fields["岗位名称"].split("\n")[1]}
date: ${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}:00
---### Job Responsibilities${fields["Job Responsibilities"]}### Job Requirements${fields["Job Requirements"]}
​
## AdditionalWe"re a remote work company with employees in 6 cities across China, and we do all of our collaboration through GitHub, Slack and Google Docs.## Contact[recruit@api7.ai](mailto:recruit@api7.ai)
`}

内容生成后,我们需要将内容写到文件中并创建md文件和对应的json列表:

fs.writeFileSync(path.join(__dirname, '../data/career.json'), JSON.stringify(careerList, null, 2), 'utf8')tableData.forEach(item => {fs.writeFileSync(path.join(__dirname, '../_posts/careers/en-US/', item.fileName + '.md'), enTemplate(item.fields), 'utf8')fs.writeFileSync(path.join(__dirname, '../_posts/careers/zh-CN/', item.fileName + '.md'), zhTemplate(item.fields), 'utf8')})

在上面的代码中我使用了 writeFileSync 这个方法创建文件,第一个参数传入创建文件的位置和名称,如果文件已存在则会 覆盖 掉,第三个参数传入 文件内容,第三个参数传入编码方式。通过遍历表格数据的方式传入参数,调用前面写的方法创建多个md文档。

在生成列表的时候,为了json字符串的可读性我传入了第三个参数用于 指定缩进用的空白字符串 ,用于美化输出(pretty-print);如果参数是个数字,它代表有多少的空格;上限为10。

下图为最终生成的md文档:

最后再为我们这个生成文档的脚本新增一个启动命令,在 package.jsonscripts 新增一个字段:

//package.json
"scripts": {"dev": "next dev","build": "next build","start": "next start --port=80","postbuild": "next-sitemap","career":"node career-api/app.js"}

下次启动时只需要执行 npm run career 即可。

总结

当前需要更新岗位信息的话还需要开发人员进入项目中执行指定命令,如果想要更加轻松的话我们可以在 github action 中配置定时自动执行,亦或者使用 next.js 的服务将这个更新岗位的接口暴露出去,让人事那边想要更新时直接调用接口就好了~

通过飞书开放api可以实现大量的自动化功能,将维护某些简单功能的精力从技术人员转移到非技术人员,降低开发成本。通过我两个小时的开发就可以避免之后每次修改都需要花半天的时间去改和核对,这才是 程序员的价值 嘛~

帮你早点下班~基于飞书API实现next.js网站内容自动生成实践相关推荐

  1. python的api库_python 利用toapi库自动生成api

    在学习做接口测试自动化的时候,我们往往会自己动手写一些简单的API,比如写一个简单的TODO API之类. 不过自己写API的时候经常需要造一些假数据,以及处理分页逻辑,开始的时候还觉得比较有意思,但 ...

  2. java如何生成api文档_api文档自动生成工具

    java开发,根据代码自动生成api接口文档工具,支持RESTful风格,今天我们来学一下api-doc的生成 预览 在线预览地址 开发原理 这个工具是一个典型的前后端分离开发的项目,想了解前后端分离 ...

  3. 创建一个提供数据 API 的 Node.js 网站

    创建站点目录 首先,创建一个文件夹用来保存你的站点文件,使用 mkdir 就可以了 PS C:\> mkdir mysite 然后,进入到这个文件夹进行下一步的操作. 创建包说明 使用记事本或者 ...

  4. 【日常问题】API文档的.chm后缀自动生成.chw后缀文件

    CHM(Compiled Help Manual)叫已编译的帮助文件. CHW文件是索引文件,用于提高 msdn 查阅器的索引.关键字和全文搜索性能,能够加快chm文件的索引. 一开始有强迫症,删了好 ...

  5. 简书makedown自动生成目录

    makedown在CSDN和博客园之中使用[TOC]可以直接生成目录,但是简书不行. 部分大牛使用CSS/HTML自动生成目录,但是对于我们来说这样有点不方便,而且不美观. 部分人使用Visual S ...

  6. 『简书API:jianshu 基于golang -- 用法介绍 (2)』

    首先我做这个项目的目的是朴素的: 熟悉golang 语法 通过这个项目呢,大家可以分析任意网站, 任意解析网站形成自己的API. 这个项目受项目:zhihu-go 影响.阅读完该项目的源码后,我立刻觉 ...

  7. 可能是全网最全,JAVA日志框架适配/冲突解决方案,可以早点下班了

    点击关注公众号,Java干货及时送达 你是否遇到过配置了日志,但打印不出来的情况? 你是否遇到过配置了logback,启动时却提示log4j错误的情况?像下面这样: log4j:WARN No app ...

  8. 听说用 Lombok 可以早点下班?

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:分享一个牛逼的 Java 开源后台管理系统,不要造轮子了!个人原创+1博客:点击前往,查看更多 作者:武培轩 出 ...

  9. lombok原理_听说学会用 Lombok 就可以让你早点下班?(你还不看)

    听说隔壁用 Lombok 的六点就下班了,我也想六点下班! 好的,那么这篇文章就介绍下什么是 Lombok,Lombok 做了什么以及 Lombok 是怎么做的? 在介绍之前,先通过是否使用 Lomb ...

最新文章

  1. 深度学习模型压缩方法(3)-----模型剪枝(Pruning)
  2. 关于Rocchio算法和向量空间模型反馈
  3. c语言期末作业自己设计个小程序,帮看一个小程序吧,c语言期末考…求求各位大神了...
  4. Github 开源了新型肺炎防疫项目,助力抗击疫情!
  5. cbow word2vec 损失_word2vec个人总结-理论篇
  6. xshell堡垒机_Jumpserver开源堡垒机管理
  7. ContextAttribute类
  8. linux 创建LVM磁盘
  9. fgets 和gets_C编程中的fgets()和gets()
  10. Prism 文档 第三章 管理组件之间的依赖关系
  11. script language=JavaScript defer
  12. 数据分析和数据开发的区别
  13. Web票据在线打印和套打解决方案
  14. 解决无法删除文件夹的情况:文件夹正在使用,操作无法完成,因为其中的文件,或文件夹已在另一个程序中打开...
  15. Python深度学习之处理文本数据
  16. python-今日头条
  17. 【CSS】一个div在另外一个div中居中显示(水平居中,竖直居中)
  18. 原创 PDF 电子书 V4.0,限时免费下载!
  19. ubuntu系统20.4搭建c语言环境,ubuntu 20.04 中文环境和英文环境切换
  20. Leetcode第314场周赛

热门文章

  1. 嵌入式系统开发的架构和应用
  2. java集合之trove4j高性能集合库
  3. 学习Python可以做什么工作?选哪些工作方向?
  4. VUE前端二级部门联动下拉菜单
  5. 7周入门数据分析:(2)分析界的No.1——Excel
  6. 蓝桥冲刺31天打卡—Day14
  7. PS 滤镜——(扭曲)逆球面化 (凹陷效果)
  8. 如果让测试员来拍《程序员那么可爱》,剧情会是什么样的?
  9. IOS苹果ipa重签名工具(苹果签名工具,ios签名工具,支持Windows系统和Macos系统)
  10. 软件测试之——性能测试(超级详细)这些你都知道吗?