最终效果 返回前端一个二维码,扫码登录后,机器人将上线,根据后端node内代码实现自动回复等功能
初始化项目
npm init -y
安装 wechaty 核心包
npm i wechaty wechaty-puppet wechaty-puppet-padlocal
安装 qrcode-terminal 用于终端输出二维码
npm i qrcode-terminal
安装 express 实现接口
npm i express
创建bot.js 实现机器人
- 注意 注释掉的 PuppetPadlocal 是可以传token的 申请地址http://pad-local.com/ 免费的7天
这里注释掉是 需要登录的微信是17年之前注册的才行
const {
dingDongBot,
getMessagePayload,
LOGPRE,
} = require("./helper");
const { log, ScanStatus, WechatyBuilder } = require("wechaty");
//const { PuppetPadlocal } = require("wechaty-puppet-padlocal");
/****************************************
* 去掉注释,可以完全打开调试日志
****************************************/
// log.level("silly");
// const puppet = new PuppetPadlocal({
// token: "自己申请的token",
// });
async function runBot() {
return new Promise((resolve, reject) => {
const bot = WechatyBuilder.build({
name: "叮当猫机器",
//puppet
});
bot.start().then(() => {
log.info(LOGPRE, "机器开始启动.");
});
bot
.on("scan", (qrcode, status) => {
if (status === ScanStatus.Waiting && qrcode) {
console.log('qrcode',qrcode)
const qrcodeImageUrl = [
"https://wechaty.js.org/qrcode/",
encodeURIComponent(qrcode),
].join("");
resolve(qrcode)
log.info(
LOGPRE,
`扫码: ${ScanStatus[status]}(${status}) - ${qrcodeImageUrl}`
);
require("qrcode-terminal").generate(qrcode, { small: true });
} else {
log.info(LOGPRE, `扫码状态: ${ScanStatus[status]}(${status})`);
}
})
.on("login", (user) => {
log.info(LOGPRE, `${user} 登录成功`);
})
.on("logout", (user, reason) => {
log.info(LOGPRE, `${user} 登出, 原因: ${reason}`);
})
.on("message", async (message) => {
log.info(LOGPRE, `收到消息: ${message.toString()}`);
await getMessagePayload(message);
await dingDongBot(message);
})
.on("room-invite", async (roomInvitation) => {
//处理邀请加入群聊
log.info(LOGPRE, `on room-invite: ${roomInvitation}`);
})
.on("room-join", (room, inviteeList, inviter, date) => {
//当有新成员加入一个群聊时,Wechaty会触发room-join事件
log.info(
LOGPRE,
`新成员加入群聊, room:${room}, inviteeList:${inviteeList}, inviter:${inviter}, date:${date}`
);
})
.on("room-leave", (room, leaverList, remover, date) => {
//当有成员离开一个群聊时,Wechaty会触发room-leave事件
log.info(
LOGPRE,
`有成员离开群聊, room:${room}, leaverList:${leaverList}, remover:${remover}, date:${date}`
);
})
.on("room-topic", (room, newTopic, oldTopic, changer, date) => {
//当一个群聊的名称发生变更时
log.info(
LOGPRE,
`群聊的名称发生变更, room:${room}, newTopic:${newTopic}, oldTopic:${oldTopic}, changer:${changer}, date:${date}`
);
})
.on("friendship", async (friendship) => {
//friendship事件用于处理好友添加请求和确认的事件
log.info(LOGPRE, `on friendship: ${friendship}`);
/* if (friendship.type() === bot.Friendship.Type.Receive) {
// 收到好友添加请求
await friendship.accept();
console.log(`接受了来自 ${friendship.contact().name()} 的好友添加请求`);
} else if (friendship.type() === bot.Friendship.Type.Confirm) {
// 好友添加请求已确认
console.log(`已成为好友:${friendship.contact().name()}`);
} */
})
.on("error", (error) => {
log.error(LOGPRE, `程序产生错误: ${error}`);
});
});
}
module.exports = {
runBot,
};
创建辅助的工具helper.js
const { log, Message } = require("wechaty");
const PUPPET = require("wechaty-puppet");
const dayjs = require("dayjs");
const fs = require("fs");
const LOGPRE = "[终端打印日志]";
async function getMessagePayload(message) {
switch (message.type()) {
case PUPPET.types.Message.Text:
log.silly(LOGPRE, `get message text: ${message.text()}`);
break;
case PUPPET.types.Message.Attachment:
case PUPPET.types.Message.Audio: {
const attachFile = await message.toFileBox();
const dataBuffer = await attachFile.toBuffer();
log.info(LOGPRE, `get message audio or attach: ${dataBuffer.length}`);
break;
}
case PUPPET.types.Message.Video: {
const videoFile = await message.toFileBox();
const videoData = await videoFile.toBuffer();
log.info(LOGPRE, `get message video: ${videoData.length}`);
break;
}
case PUPPET.types.Message.Emoticon: {
const emotionFile = await message.toFileBox();
const emotionJSON = emotionFile.toJSON();
log.info(
LOGPRE,
`get message emotion json: ${JSON.stringify(emotionJSON)}`
);
const emotionBuffer = await emotionFile.toBuffer();
log.info(LOGPRE, `get message emotion: ${emotionBuffer.length}`);
break;
}
case PUPPET.types.Message.Image: {
const messageImage = await message.toImage();
const thumbImage = await messageImage.thumbnail();
const thumbImageData = await thumbImage.toBuffer();
log.info(LOGPRE, `get message image, thumb: ${thumbImageData.length}`);
const hdImage = await messageImage.hd();
const hdImageData = await hdImage.toBuffer();
log.info(LOGPRE, `get message image, hd: ${hdImageData.length}`);
const artworkImage = await messageImage.artwork();
const artworkImageData = await artworkImage.toBuffer();
log.info(
LOGPRE,
`get message image, artwork: ${artworkImageData.length}`
);
break;
}
case PUPPET.types.Message.Url: {
const urlLink = await message.toUrlLink();
log.info(LOGPRE, `get message url: ${JSON.stringify(urlLink)}`);
const urlThumbImage = await message.toFileBox();
const urlThumbImageData = await urlThumbImage.toBuffer();
log.info(LOGPRE, `get message url thumb: ${urlThumbImageData.length}`);
break;
}
case PUPPET.types.Message.MiniProgram: {
const miniProgram = await message.toMiniProgram();
log.info(LOGPRE, `MiniProgramPayload: ${JSON.stringify(miniProgram)}`);
break;
}
}
}
async function dingDongBot(message) {
if (message.to()?.self() && message.text().indexOf("ding") !== -1) {
await message.talker().say(message.text().replace("ding", "dong"));
}
}
module.exports = {
dingDongBot,
getMessagePayload,
LOGPRE,
};
实现入口文件 app.js
const { LOGPRE } = require("./helper");
const { runBot } = require("./bot");
const express = require("express");
const app = express();
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
next();
});
let qrcode = "";
// 返回登录二维码的接口
app.get("/qrcode", (req, res) => {
if (qrcode) {
// 返回二维码地址给前端
res.json({ qrcode });
} else {
res.status(404).json({ error: "QR Code not found" });
}
});
app.listen(3000, async () => {
console.log(LOGPRE, "http://localhost:3000/qrcode");
qrcode = (await runBot()) || "";
});
启动项目
node app.js
最终目录结构
效果:
前端访问效果
前端就是拿到接口返回的url,使用QRCode插件进行生成二维码即可
前端生成二维码
插件地址 https://www.npmjs.com/package/qrcode
vue示例
<template>
<div>
<canvas id="canvas"></canvas>
</div>
</template>
<script>
import QRCode from "qrcode";
import axios from "axios";
export default {
name: "QRCode",
mounted() {
this.getQr();
},
methods: {
getQr() {
axios("http://localhost:3000/qrcode").then((res) => {
console.log(res, "res");
const canvas = document.getElementById("canvas");
QRCode.toCanvas(canvas, res.data.qrcode, function (error) {
if (error) console.error(error);
console.log("success!");
});
});
},
},
};
</script>