关于javascript:Wechaty-NodeJS基于wechatypuppethostie协议手撸一个企业级微信机器人助手

38次阅读

共计 19560 个字符,预计需要花费 49 分钟才能阅读完成。

需要背景

目前所在企业是一家创新型汽车后市场互联网科技有限公司,拓展汽车后市场 B2C、B2B 和 O2O 业务。

后期打造链接线下 6 家自营大型汽车业余维修中心,12 家自营汽车配件、汽保设施销售核心,3000 余家加盟汽修、汽配企业及 10 余万集体客户的服务平台;

因为客户维系和供应商征询等都是基于微信群聊的。每天要在成千盈百的群聊中提供服务。须要实时在群内产品报价,车架号辨认,图片辨认,关键字反馈。数据推送等等性能。这样的需要状况下,人力老本是微小的。

而我作为一名前端开发工程师,平时也喜爱写技术博客和交朋友,为此我也创立了微信技术交换群和微信公众号,个别我都会在文章上面贴出公众号和我的集体二维码,给有趣味的小伙伴们增加微信而后我再拉他们进群这些,然而不停的批准微信好友验证,再发送群邀请真的是太苦楚了,置信很多做公众号的小伙伴都和我一样,作为一名开发,这种重复劳动是相对不能忍耐的基于这种状况和公司业务状况,调研发现了并理解到了 wechaty,发现其提供的性能可能笼罩到企业和集体微信,并且可能本人定制化开发合乎本人需要的性能。

介绍

Wechaty 是什么

微信集体号性能十分弱小和灵便,是一个非常适合用来做 ChatBot 的载体。它能够灵便不受限制的发送语音短信、视频、图片和文字,反对多人群聊。然而应用微信集体微信号作为 ChatBot,须要通过非官方的第三方库接入微信。因为截至 2018 年底,微信尚无任何官网的 ChatBot API 公布。

Wechaty 是一个开源的的对话机器人 SDK,反对 集体号 微信。它是一个应用 Typescript 构建的 Node.js 利用。反对多种微信接入计划,包含网页,ipad,ios,windows,android 等。同时反对 Linux, Windows, Darwin(OSX/Mac) 和 Docker 多个平台。

在 GitHub 上能够找到很多反对微信集体号接入的第三方类库,其中大多都是基于 Web Wechat 的 API 来实现的,如基于 Python 的 WeixinBot,基于 Node.js 的 Wechaty 等。多数反对非 Web 协定的库,大多是商业公有闭源的,Wechaty 是少有的开源我的项目反对非 Web 协定的类库。

只须要 6 行代码,你就能够 通过集体号 搭建一个 微信机器人性能,用来主动治理微信音讯。

import {Wechaty} from 'wechaty'
​
Wechaty.instance()
.on('scan',        qrcode  => console.log('扫码登录:' + qrcode))
.on('login',       user    => console.log('登录胜利:' + user))
.on('message',     message => console.log('收到音讯:' + message))
.on('friendship',  friendship => console.log('收到好友申请:' + friendship))
.on('room-invite', invitation => console.log('收到入群邀请:' + invitation))
.start()

更多功能包含

  • 音讯解决:关键词回复
  • 群治理:主动入群,拉人,踢人
  • 主动解决好友申请
  • 智能对话:通过简略配置,即可退出智能对话零碎,实现指定工作
  • … 请自行开脑洞 所有你能想到的交互模式。在微信上都有实现的可能。

每日定时拉取天气预报。

每天给你可爱的人发送早安和晚安信息。

什么成语接龙啦。快问快答等等性能

当然 wechaty 的性能服务并不是收费的

200/ 月的费用,如果你是集体开发可能会斟酌一二。然而你能够通过社区申请一个长达 15 天的收费 token 来尝试应用和开发一个小型机器人,从而决定你是否须要购买应用。

对于申请的地址我放在了这里 Wechaty Token 申请及应用文档和常见问题

基于 wechaty-puppet-hostie 开发企业级微信机器人

目录构造


├── config
│   └── index.js // 配置文件
├── package.json
├── service
│   ├── bot-service
│   │   ├── error-service.js
│   │   ├── friendship-service.js
│   │   ├── heartbeat-service.js
│   │   ├── login-service
│   │   │   ├── function-service.js
│   │   │   └── index.js
│   │   ├── logout-service.js
│   │   ├── message-service
│   │   │   ├── function-service.js
│   │   │   └── index.js
│   │   ├── ready-service
│   │   │   ├── function-service.js
│   │   │   └── index.js
│   │   ├── room-invite-service.js
│   │   ├── room-join-service.js
│   │   ├── room-leave-service.js
│   │   ├── room-topic-service.js
│   │   └── scan-service
│   │       └── index.js
│   ├── common-service
│   │   ├── chatbot-service.js
│   │   ├── ding-service.js
│   │   └── oss-service.js
│   └── redis-service
│       └── index.js
├── src
│   └── main.js // 入口
├── store
│   └── index.js // 全局存储对象
├── utils
│   ├── oss.js // 阿里云 oss 认证
│   └── redis.js // redis 认证登录
└── yarn.lock

src/main.js

const {Wechaty} = require('wechaty')                                          // 机器人木偶
​
const {onScan} = require("../service/bot-service/scan-service")               // 当机器人须要扫码登陆的时候会触发这个事件。const {onLogin} = require("../service/bot-service/login-service")             // 当机器人胜利登陆后,会触发事件,并会在事件中传递以后登陆机器人的信息
const {onLogout} = require("../service/bot-service/logout-service")           // 当机器人检测到登出的时候,会触发事件,并会在事件中传递机器人的信息。const {onReady} = require("../service/bot-service/ready-service")             // 当所有数据加载实现后,会触发这个事件。在 wechaty-puppet-padchat 中,它意味着曾经加载实现 Contact 和 Room 的信息。const {onMessage} = require("../service/bot-service/message-service")         // 当机器人收到音讯的时候会触发这个事件。const {onRoomInvite} = require("../service/bot-service/room-invite-service")  // 当收到群邀请的时候,会触发这个事件。const {onRoomTopic} = require("../service/bot-service/room-topic-service")    // 当有人批改群名称的时候会触发这个事件。const {onRoomJoin} = require("../service/bot-service/room-join-service")      // 当有人进入微信群的时候会触发这个事件。机器人被动进入某个微信群,那个样会触发这个事件。const {onRoomleave} = require("../service/bot-service/room-leave-service")    // 当机器人把群里某个用户移出群聊的时候会触发这个工夫。用户被动退群是无奈检测到的。const {onFriendship} = require("../service/bot-service/friendship-service")   // 当有人给机器人发好友申请的时候会触发这个事件。const {onHeartbeat} = require('../service/bot-service/heartbeat-service')     // 获取机器人的心跳。const {onError} = require('../service/bot-service/error-service')             // 当机器人外部出错的时候会触发 error 事件。​
​
const {wechatyToken} = require('../config/index') // 机器人 token
const {globalData} = require('../store/index') // 全局对象
​
globalData.bot = new Wechaty({
 puppet: 'wechaty-puppet-hostie',
 puppetOptions: {token: wechatyToken}
});
​
globalData.bot
 .on('scan', onScan)
 .on('login', onLogin)
 .on('logout', onLogout)
 .on('ready', onReady)
 .on('message', onMessage)
 .on('room-invite', onRoomInvite)
 .on('room-topic', onRoomTopic)
 .on('room-join', onRoomJoin)
 .on('room-leave', onRoomleave)
 .on('friendship', onFriendship)
 .on('heartbeat', onHeartbeat)
 .on('error', onError)
 .start()

具体性能实现及代码

  • 扫码登录 通过 node 启动后,触发 onScan 事件,将登录二维码打印在控制台,扫码登录
const QrcodeTerminal = require('qrcode-terminal');
const {ScanStatus} = require('wechaty-puppet')
​
/**
 * @method onScan 当机器人须要扫码登陆的时候会触发这个事件。倡议你装置 qrcode-terminal(运行 npm install qrcode-terminal) 这个包,这样你能够在命令行中间接看到二维码。* @param {*} qrcode 
 * @param {*} status 
 */
const onScan = async (qrcode, status) => {
 try {if (status === ScanStatus.Waiting) {console.log(`========================???? 二维码状态:${status}????========================nn`)
 QrcodeTerminal.generate(qrcode, {small: true})
 }
 } catch (error) {console.log('onScan', error)
 }
​
}
​
module.exports = {onScan}
  • 登录胜利 扫码登录胜利后会触发 onLogin 事件,通过事件接管到登录信息和机器人信息,通过钉钉接口将登录告诉发送至钉钉群内
const {notificationLoginInformation} = require('../../common-service/ding-service')
const {updateBotInfo} = require('./function-service')
const {globalData} = require('../../../store/index')
​
/**
 * @method onLogin 当机器人胜利登陆后,会触发事件,并会在事件中传递以后登陆机器人的信息
 * @param {*} botInfo 
 */
const onLogin = async botInfo => {
 try {console.log('========================???? onLogin ????========================nn')
 console.log(` 机器人信息:${JSON.stringify(botInfo)}nn`)
 console.log(`
 //
          //
        //
 ##DDDDDDDDDDDDDDDDDDDDDD##
 ## DDDDDDDDDDDDDDDDDDDD ## 
 ## DDDDDDDDDDDDDDDDDDDD ## 
 ## hh                hh ##      ##         ## ## ## ##   ## ## ## ###   ##    ####     ## 
 ## hh    //         hh ##      ##         ##       ##   ##             ##    ## ##    ##
 ## hh   //          hh ##      ##         ##       ##   ##             ##    ##   ##  ##
 ## hh                hh ##      ##         ##       ##   ##     ##      ##    ##    ## ##
 ## hh      wwww      hh ##      ##         ##       ##   ##       ##    ##    ##     ####
 ## hh                hh ##      ## ## ##   ## ## ## ##   ## ## ## ###   ##    ##      ###
 ## MMMMMMMMMMMMMMMMMMMM ## 
 ##MMMMMMMMMMMMMMMMMMMMMM##      微信机器人名为: [${botInfo.payload.name}] 曾经扫码登录胜利了。nn
 `)
 // 全局存储机器人信息
 globalData.botPayload = botInfo.payload
 // 更新机器人列表
 updateBotInfo()
 // 机器人登录登出揭示 / 告诉钉钉接口
 notificationLoginInformation(true)
 } catch (error) {console.log(`onLogin: ${error}`)
 }
​
}
​
module.exports = {onLogin}

— 机器人异样退出 当 node 服务异样终端,或者手机上退出机器人登录后会触发 onLogout 事件,同样钉钉群内告诉信息,并且销毁程序中运行的一些定时器等

const {notificationLoginInformation} = require('../common-service//ding-service')
const {globalData} = require('../../store/index')
​
/**
 * @method onLogout 当机器人检测到登出的时候,会触发事件,并会在事件中传递机器人的信息。* @param {*} botInfo 
 */
const onLogout = async botInfo => {
 try {console.log('========================???? onLogout ????========================')
 console.log(` 当 bot 检测到登记时,将与以后登录用户的联系人收回登记。`)
 // 全局存储机器人信息
 globalData.botPayload = botInfo.payload
 const {updateRoomInfoTimer, chatbotSayQueueTimer} = globalData
 // 机器人退出清空定时器
 if (updateRoomInfoTimer) {clearTimeout(updateRoomInfoTimer)
 }
 if (chatbotSayQueueTimer) {clearInterval(chatbotSayQueueTimer)
 }
 // 机器人登录登出揭示 / 告诉钉钉接口
 notificationLoginInformation(false)
 } catch (error) {console.log(`error in onLogout:${error}`)
 }
​
}
​
module.exports = {onLogout}
  • 音讯接管解决 当微信接管到新的音讯时候会触发 onMessage 事件,通过事件内对音讯的判断,群内音讯还是私聊音讯等做出不同的逻辑解决。从而实现业务需要。局部代码如下
const dayjs = require('dayjs');
const {say} = require('../../common-service/chatbot-service')
const {
 isCanSay,
 roomIdentifyVin,
 rooImageIdentifyVin,
 contactIdentifyVin,
 contactImageIdentifyVin,
 messageProcessing,
 storageRoomMessage,
 storageContactMessage,
} = require('./function-service')
const {
 roomMessageFeedback,
 contactMessageFeedback
} = require('../../common-service/ding-service')
const {globalData} = require('../../../store/index');
const {Message} = require('wechaty');
​
/**
 * @method onMessage 当机器人收到音讯的时候会触发这个事件。* @param {*} message 
 */
const onMessage = async message => {
 try {console.log('========================???? onMessage ????========================nn')
 // 机器人信息
 const {botPayload} = globalData
 // 获取发送音讯的联系人
 const contact = message.from()
 // 获取音讯所在的微信群,如果这条音讯不在微信群中,会返回 null 
 const room = message.room()
 // 查看这条音讯是否为机器人发送的
 const isSelf = message.self()
 // 解决音讯内容
 const text = await messageProcessing(message)
 // console.log(`========================???? 解决音讯后内容为:${text} ????========================nn`)
 // 音讯为空不解决
 if (!text) return
​
 // 音讯详情
 const messagePayload = message.payload
 // console.log(`========================???? 音讯详情:${JSON.stringify(messagePayload)} ????========================nn`)
 // 音讯联系人详情
 const contactPayload = contact.payload
 // console.log(`========================???? 音讯联系人详情:${JSON.stringify(contactPayload)} ????========================nn`)
 // 群音讯
 if (room) {console.log(`========================???? 群聊音讯 ????========================nn`)
 // 房间详情
 const roomPayload = room.payload
 // console.log(`========================???? 房间详情:${JSON.stringify(roomPayload)} ????========================nn`)
 console.log(` 音讯工夫:${dayjs(messagePayload.timestamp).format('YYYY-MM-DD HH:mm:ss')}nn 群聊名称:${roomPayload.topic}nn 微信名称:${contactPayload.name}nn 微信类型:${contactPayload.type}nn 备注昵称:${contactPayload.alias}nn 音讯内容:${text}nn 音讯类型:${messagePayload.type}nn`);
 // 存储音讯内容
 const storeMessage = {
 category: 'room',                               // 音讯类别,room 为群聊音讯,contact 为集体音讯。isSelf: isSelf,                                 // 是否本人发送的音讯
​
 messageId: messagePayload.id,                   // 音讯 id
 messageToId: messagePayload.toId,               // 音讯接收者 id
 messageType: messagePayload.type,               // 音讯类型
 messageText: text,                              // 音讯内容
 messageTimestamp: messagePayload.timestamp,     // 音讯工夫戳
 messageTime: dayjs(messagePayload.timestamp).format('YYYY-MM-DD HH:mm:ss'), // 音讯工夫
​
 roomOwnerId: roomPayload.ownerId,               // 群聊群主 id
 roomTopic: roomPayload.topic,                   // 群聊名称
 roomId: roomPayload.id,                         // 群聊名称
​
 contactId: contactPayload.id,                   // 音讯发送者 id
 contactName: contactPayload.name,               // 音讯发送者昵称
 contactType: contactPayload.type,               // 音讯发送者类型
 contactAvatar: contactPayload.avatar,           // 音讯发送者头像
 contactAlias: contactPayload.alias,             // 音讯发送者备注
 }
 //  redis 中存储群聊音讯内容
 storageRoomMessage(roomPayload, storeMessage)
​
 // 音讯是机器人本人发的 或者 音讯发送到 wechaty 接管距离大于半个小时
 if (isSelf || message.age() > 1800) return
​
 // 判断以后机器人在群中是否能够谈话 
 if (!await isCanSay(roomPayload)) return
​
 // 有人 @我
 const isMentionSelf = await message.mentionSelf()
 // 如果有人 @我
 if (isMentionSelf) {console.log('this message were mentioned me! [You were mentioned] tip ([有人 @我]的提醒)')
 // 获取音讯内容,拿到整个音讯文本,去掉 @名字
 const sendText = text.replace("@" + botPayload.name, "")
 if (sendText == '图片') {
 // 通过不同的关键字进行业务解决逻辑
 say({
 messageType: 6,
 sender: room,
 messageInfo: {fromUrl: 'https://wework.qpic.cn/wwhead/nMl9ssowtibVGyrmvBiaibzDqfABIxIv4ic0FyQRxgQVpUIaqlePxrDW8L2qPB3WnHSZclgQ1D1QhDs/0'}
 })
 return
​
 }
​
 if (sendText == '分享') {
 // 通过不同的关键字进行业务解决逻辑
 say({
 messageType: 14,
 sender: room,
 messageInfo: {
 urlLink: {
 description: 'WeChat Bot SDK for Individual Account, Powered by TypeScript, Docker, and Love',
 thumbnailUrl: 'https://avatars0.githubusercontent.com/u/25162437?s=200&v=4',
 title: 'Welcome to Wechaty',
 url: 'https://github.com/wechaty/wechaty',
 }
 }
 })
 return
 }
 if (sendText == '名片') {
 say({
 messageType: 3,
 sender: room,
 messageInfo: {contactCard: 'contactId'}
 })
 return
 }
​
 if (sendText == '小程序') {
 say({
 messageType: 9,
 sender: room,
 messageInfo: {
 miniProgram: {
 appid: 'xxxxx',
 title: '我正在应用 Authing 认证身份,你也来试试吧',
 pagePath: 'pages/home/home.html',
 description: '身份管家',
 thumbUrl: '30590201000452305002010002041092541302033d0af802040b30feb602045df0c2c5042b777875706c6f61645f31373533353339353230344063686174726f6f6d3131355f313537363035393538390204010400030201000400',
 thumbKey: '42f8609e62817ae45cf7d8fefb532e83',
 }
 }
 })
 return
 }
​
​
 // 群里失常谈话
 } else {
 // 重构机器人功能测试群
 if (roomPayload.id !== 'R:10696051737544800') {console.log(`========================???? 不是测试群音讯,不解决群内业务逻辑 ????========================nn`)
 return
 }
​
 if (/^[a-zA-Z0-9]{17}$/.test(text)) {
 // 群聊辨认 vin 反馈
 roomIdentifyVin(room, contact, message, text)
 return
 }
​
 // 群内音讯以 [弱] 结尾的信息为反馈信息。反馈给后盾
 if (text.indexOf('[弱]') === 0) {
 // 群音讯反馈
 roomMessageFeedback(room, contact, text)
 return
 }
​
 // 如果是图片,则图片解析 vin
 if (messagePayload.type === Message.Type.Image) {
 // 群聊图片辨认 vin 反馈
 rooImageIdentifyVin(room, contact, message)
 }
 }
​
 // 私聊音讯
 } else {console.log(`========================???? 私聊音讯 ????========================nn`)
 console.log(` 音讯工夫:${dayjs(messagePayload.timestamp).format('YYYY-MM-DD HH:mm:ss')}nn 微信名称:${contactPayload.name}nn 微信类型:${contactPayload.type}nn 备注昵称:${contactPayload.alias}nn 音讯内容:${text}nn 音讯类型:${messagePayload.type}nn`);
 // 存储音讯内容
 const storeMessage = {
 category: 'contact',                            // 音讯类别,room 为群聊音讯,contact 为集体音讯。isSelf: isSelf,                                 // 是否本人发送的音讯
​
 messageId: messagePayload.id,                   // 音讯 id
 messageToId: messagePayload.toId,               // 音讯接收者 id
 messageType: messagePayload.type,               // 音讯类型
 messageText: text,                              // 音讯内容
 messageTimestamp: messagePayload.timestamp,     // 音讯工夫戳
 messageTime: dayjs(messagePayload.timestamp).format('YYYY-MM-DD HH:mm:ss'), // 音讯工夫
​
 contactId: contactPayload.id,                   // 音讯发送者 id
 contactName: contactPayload.name,               // 音讯发送者昵称
 contactType: contactPayload.type,               // 音讯发送者类型
 contactAvatar: contactPayload.avatar,           // 音讯发送者头像
 contactAlias: contactPayload.alias,             // 音讯发送者备注
 }
 //  redis 中存储私聊音讯内容
 storageContactMessage(contact, storeMessage)
 // 音讯是机器人本人发的 或者 音讯发送到 wechaty 接管距离大于半个小时
 if (isSelf || message.age() > 1800) return
​
 if (/^[a-zA-Z0-9]{17}$/.test(text)) {
 // 私聊辨认 vin 反馈
 contactIdentifyVin(contact, message, text)
 return
 }
​
 // 私聊音讯以 [弱] 结尾的信息为反馈信息。反馈给后盾
 if (text.indexOf('[弱]') === 0) {
 // 私聊音讯反馈
 contactMessageFeedback(contact, text)
 return
 }
​
 // 如果是图片,则图片解析 vin
 if (messagePayload.type === Message.Type.Image) {
 // 私聊图片解析 vin 反馈
 contactImageIdentifyVin(contact, message)
 }
 }
 } catch (error) {console.log(`onMessage:${error}`)
 }
}
​
module.exports = {onMessage}

至于其余的一些生命周期以及钩子函数。大家能够参考文档做出属于本人的利用机器人

封装 say 办法

因为 say()办法会在多处调用,并且要依据不同的音讯类型发送的内容做出不同的数据处理。大家当前也会遇到,因而这里将我封装的一个 say 办法展现给大家用于参考

const {MiniProgram, UrlLink, FileBox} = require('wechaty')
const dayjs = require('dayjs');
const {DelayQueueExector} = require('rx-queue');
const {redisHexists, redisHset, redisHget, redisSet, redisLpush} = require('../redis-service/index')
const {globalData} = require('../../store/index')
​
const delay = new DelayQueueExector(10000);
​
/**
 * @method say 机器人发送音讯
 * @param {*} messageType   音讯类型   7 文本,1 文件,6 图片,3 集体名片,14 卡片链接 9 小程序
 * @param {*} sender        起源   房间 || 集体 实例对象
 * @param {*} messageInfo 内容 
*/
/**
 * messageInfo 数据结构
 *      tetx: string        文本音讯必传
 *      fileUrl: string     文件音讯必传
 *      imageUr: string     图片音讯必传
 *      cardId: string      集体名片音讯必传
 *      linkInfo: object    卡片音讯必传
 *          description: string     形容 
 *          thumbnailUrl: string    缩略图地址
 *          title: string           题目
 *          url: string             跳转地址
 */
​
async function say({messageType, sender, messageInfo}) {// console.log(messageType);
 // console.log(sender);
 // console.log(messageInfo);
 try {return new Promise(async (resolve, reject) => {
 // 机器人信息
 const {bot} = globalData
 // 枚举音讯类型
 const MessageType = {
 text: 7,            // 文本
 fromFile: 1,        // 文件
 fromUrl: 6,         // 图片
 contactCard: 3,     // 集体名片
 urlLink: 14,        // 卡片链接
 miniProgram: 9,     // 小程序
​
 }
​
 // 内容不存在
 if (!messageInfo) {return}
 // 要发送的音讯内容
 let content
​
​
 switch (messageType) {
 // 文本 7
 case MessageType.text:
 content = messageInfo.text
 break;
 // 文件 1
 case MessageType.fromFile:
 content = FileBox.fromFile(messageInfo.fromFile)
 break;
 // 图片 6
 case MessageType.fromUrl:
 content = FileBox.fromUrl(messageInfo.fromUrl)
 break;
 // 集体名片 3
 case MessageType.contactCard:
 content = await bot.Contact.load('1688853777824721')
 break;
 // 链接 14
 case MessageType.urlLink:
 content = new UrlLink({
 description: 'WeChat Bot SDK for Individual Account, Powered by TypeScript, Docker, and Love',
 thumbnailUrl: 'https://avatars0.githubusercontent.com/u/25162437?s=200&v=4',
 title: 'Welcome to Wechaty',
 url: 'https://github.com/wechaty/wechaty',
 })
 break;
 // 小程序 9
 case MessageType.miniProgram:
 content = new MiniProgram({
 appid: 'wx60090841b63b6250',
 title: '我正在应用 Authing 认证身份,你也来试试吧',
 pagePath: 'pages/home/home.html',
 description: '身份管家',
 thumbUrl: '30590201000452305002010002041092541302033d0af802040b30feb602045df0c2c5042b777875706c6f61645f31373533353339353230344063686174726f6f6d3131355f313537363035393538390204010400030201000400',
 thumbKey: '42f8609e62817ae45cf7d8fefb532e83',
 });
 break;
 default:
 break;
 }
 delay.execute(async () => {sender.say(content)
 .then(value => {console.log(`========================???? 机器人回复 ????========================nn`)
 resolve()})
 .catch(reason => {console.log(`========================???? 机器人发送音讯失败 ????========================nn`, reason)
 })
 })
 })
 } catch (error) {console.log('error in say', error);
 }
​
}
module.exports = {say}

对了,对于 onMessage 事件中音讯格局的判断我也做了一层封装,这里给大家提供参考。/**
 * @method messageProcessing 解决音讯内容
 * @param {*} message 
 */
async function messageProcessing(message) {
 try {return new Promise(async (resolve, reject) => {console.log(`========================???? messageProcessing ????========================nn`)
 // 音讯详情
 const messagePayload = message.payload
 // 获取音讯的文本内容。let text = message.text()
​
 /** 
 *  Unknown: 0,
 Attachment: 1,
 Audio: 2,
 Contact: 3,
 ChatHistory: 4,
 Emoticon: 5,
 Image: 6,
 Text: 7,
 Location: 8,
 MiniProgram: 9,
 GroupNote: 10,
 Transfer: 11,
 RedEnvelope: 12,
 Recalled: 13,
 Url: 14,
 Video: 15
 */
 // 音讯类型
 switch (messagePayload.type) {
 // 附件 0
 case Message.Type.Unknown:
 console.log(`========================???? 音讯类型为未知音讯:${messagePayload.type} ????========================nn`)
 text = '[你收到一个未知音讯,请在手机上查看]'
 break;
 // 附件 1
 case Message.Type.Attachment:
 console.log(`========================???? 音讯类型为附件:${messagePayload.type} ????========================nn`)
 // 临时不晓得怎么解决
 text = '[你收到一个附件,请在手机上查看]'
 break;
 // 音频 2
 case Message.Type.Audio:
 console.log(`========================???? 音讯类型为音频:${messagePayload.type} ????========================nn`)
 text = '[你收到一条语音音讯,请在手机上查看]'
 break;
 // 集体名片 3
 case Message.Type.Contact:
 console.log(`========================???? 音讯类型为集体名片:${messagePayload.type} ????========================nn`)
 text = '[你收到一张集体名片,请在手机上查看]'
 break;
 // 聊天记录 4
 case Message.Type.ChatHistory:
 console.log(`========================???? 音讯类型为聊天记录:${messagePayload.type} ????========================nn`)
 text = '[你收到聊天记录,请在手机上查看]'
 break;
 // 表情符号 5
 case Message.Type.Emoticon:
 console.log(`========================???? 音讯类型为表情符号:${messagePayload.type} ????========================nn`)
 text = '[你收到表情符号,请在手机上查看]'
 // 临时不晓得怎么解决
 break;
 // 图片 6
 case Message.Type.Image:
 console.log(`========================???? 音讯类型为图片:${messagePayload.type} ????========================nn`)
 // 上传图片至阿里云获取图片地址
 text = await addImageOss(message)
 break;
 // 文本 7
 case Message.Type.Text:
 console.log(`========================???? 音讯类型为文本:${messagePayload.type} ????========================nn`)
 // 去空格换行
 text = text.replace(/s+/g, '')
 break;
 // 地位 8
 case Message.Type.Location:
 console.log(`========================???? 音讯类型为地位:${messagePayload.type} ????========================nn`)
 text = '[你收到一条图片音讯,请在手机上查看]'
 break;
 // 小程序 9
 case Message.Type.MiniProgram:
 console.log(`========================???? 音讯类型为小程序:${messagePayload.type} ????========================nn`)
 text = '[你收到一个小程序音讯,请在手机上查看]'
 break;
 // GroupNote 10
 case Message.Type.GroupNote:
 console.log(`========================???? 音讯类型为 GroupNote:${messagePayload.type} ????========================nn`)
 text = '[你收到一个 GroupNote,请在手机上查看]'
 break;
 // Transfer 11
 case Message.Type.Transfer:
 console.log(`========================???? 音讯类型为 Transfer:${messagePayload.type} ????========================nn`)
 text = '[你收到一个 Transfer,请在手机上查看]'
 break;
 // 红包 12
 case Message.Type.RedEnvelope:
 console.log(`========================???? 音讯类型为红包:${messagePayload.type} ????========================nn`)
 text = '[你收到一个红包,请在手机上查看]'
 break;
 // Recalled 13
 case Message.Type.Recalled:
 console.log(`========================???? 音讯类型为 Recalled:${messagePayload.type} ????========================nn`)
 text = '[你收到一个 Recalled,请在手机上查看]'
 break;
 // 链接地址 14
 case Message.Type.Url:
 console.log(`========================???? 音讯类型为链接地址:${messagePayload.type} ????========================nn`)
 // 临时不晓得怎么解决
 text = '[你收到一条链接音讯,请在手机上查看]'
 break;
 // 视频 15
 case Message.Type.Video:
 console.log(`========================???? 音讯类型为视频:${messagePayload.type} ????========================nn`)
 text = '[你收到一个视频音讯,请在手机上查看]'
 break;
 default:
 text = ''
 break;
 }
 resolve(text)
 })
 } catch (error) {console.log('error in messageProcessing', error);
 }
​
}

为什么这样做一层封装解决,是因为咱们的业务需要要将聊天内容进行 redis 和 mysql 数据存储。不便当前数据勘误和查问应用。

实现的性能

基于 wechaty 咱们实现的性能有那些呢?

— 依据关键词,输出车辆 VIN 对应反馈出车型配件信息,并且将公司所在群区域的店铺配件库存信息反馈进去

  • 依据图片辨认车辆 VIN,而后辨认 VIN 对应反馈出车型配件信息,并且将公司所在群区域的店铺配件库存信息反馈进去,图片解释接口采纳的百度的接口
  • 关键词指令绑定群信息。依据不同指令进行群配置。
  • redis 存储机器人信息。将群信息存储并同步在 redis 和 mysql 中。后盾配置对应群是否开启某些性能等等。
  • 每月月初定时发送每个群的洽购信息。销量信息等等。
  • 机器人登录调用钉钉接口,在钉钉群内公布机器人登录或者退出的揭示信息
  • 群邀请主动通过,入群当前做出相应数据存储逻辑判断性能设置等
  • 好友申请主动通过,关键字申请主动邀请入不同的群,性能笼罩等等
  • 等等性能。以上性能反对还在一直开发和摸索中。但曾经满足目前咱们的业务需要。

最初

你如果想用我这些货色,拉下代码 config.js 里换下 token 和一些配置信息就能够,当然我在不停更新,性能会越来越多,所以仓库中代码和文中会有些不一样,应用时简略看下代码,都写了具体正文,也很简略,然而因为代码中很多中央波及到来企业敏感信息。我只好从新写来一份最小可执行的 demo,大家仅供参考。

❤️ 看完帮个忙

如果你感觉这篇内容对你挺有启发,我想邀请你帮我个小忙:

  1. 点赞,让更多的人也能看到这篇内容(珍藏不点赞,都是耍流氓 -_-)
  2. 关注公众号「番茄学前端」,我会定时更新和公布前端相干信息和我的项目案例教训供你参考。
  3. 加个好友,尽管帮不上你大忙,然而一些业务问题大家能够探讨交换。

正文完
 0