├── .gitignore ├── imgs └── pay.png ├── README.md ├── .eslintrc.js ├── listeners ├── on-friendship.js ├── on-room-leave.js ├── on-room-join.js ├── on-scan.js ├── on-login.js └── on-message.js ├── config ├── index.js └── superagent.js ├── tsconfig.json ├── schedule └── index.js ├── app.js ├── LICENSE ├── package.json ├── utils └── index.js └── superagent └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/* -------------------------------------------------------------------------------- /imgs/pay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isnl/wechat-robot-ipad/HEAD/imgs/pay.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 基于开源仓库 `wechaty ipad` 协议实现的个人微信机器人 2 | 3 | 由于 `wechaty` 官方已废,本示例代码早已失效,如有需要请尝试寻找其他方案。 4 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | 2 | const rules = { 3 | } 4 | 5 | module.exports = { 6 | extends: '@chatie', 7 | rules, 8 | } 9 | -------------------------------------------------------------------------------- /listeners/on-friendship.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 处理好友关系模块 3 | * by: Peanut 4 | */ 5 | const { 6 | Friendship 7 | } = require("wechaty"); 8 | /** 9 | * 自动同意好友请求 10 | */ 11 | async function onFriendship(friendship) { 12 | if (friendship.type() === Friendship.Type.Receive) { 13 | await friendship.accept(); 14 | } 15 | } 16 | module.exports = onFriendship 17 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Peanut 3 | * @Description: 全局配置config 4 | * @Date: 2020-05-20 22:36:09 5 | * @Last Modified by: Peanut 6 | * @Last Modified time: 2020-05-24 00:11:23 7 | */ 8 | module.exports = { 9 | TOKEN: "", 10 | IGNORE: ["www.iiter.cn"], //忽略某个用户的消息,填写用户昵称即可 11 | WEBROOM: "技术交流群", //要管理的群名称 12 | MYSELF: "Peanut" //大号的备注!!!备注不是昵称!防止其他人冒充你哦 13 | }; 14 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@chatie/tsconfig", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | }, 6 | "exclude": [ 7 | "node_modules/", 8 | "dist/", 9 | "tests/fixtures/", 10 | ], 11 | "include": [ 12 | "app/**/*.ts", 13 | "bin/*.ts", 14 | "bot/**/*.ts", 15 | "examples/**/*.ts", 16 | "scripts/**/*.ts", 17 | "src/**/*.ts", 18 | "tests/**/*.spec.ts", 19 | ], 20 | } 21 | -------------------------------------------------------------------------------- /listeners/on-room-leave.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Peanut 3 | * @Description: 离开群聊 - 机器人主动踢出才会触发此事件 4 | * @Date: 2020-05-21 22:36:41 5 | * @Last Modified by: Peanut 6 | * @Last Modified time: 2020-05-23 23:21:20 7 | */ 8 | async function onRoomLeave(room, leaverList) { 9 | const nameList = leaverList.map(c => c.name()).join(","); 10 | console.log(`Room ${room.topic()} lost member ${nameList}`); 11 | } 12 | 13 | module.exports = onRoomLeave; 14 | -------------------------------------------------------------------------------- /listeners/on-room-join.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Peanut 3 | * @Description: 加入群聊 4 | * @Date: 2020-05-21 14:11:35 5 | * @Last Modified by: Peanut 6 | * @Last Modified time: 2020-05-21 22:39:37 7 | */ 8 | async function onRoomJoin(room, inviteeList, inviter) { 9 | const nameList = inviteeList.map(c => c.name()).join(","); 10 | console.log( 11 | `Room ${room.topic()} got new member ${nameList}, invited by ${inviter}` 12 | ); 13 | } 14 | 15 | module.exports = onRoomJoin; 16 | -------------------------------------------------------------------------------- /listeners/on-scan.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Peanut 3 | * @Description: 登录 4 | * @Date: 2020-05-21 14:11:28 5 | * @Last Modified by: Peanut 6 | * @Last Modified time: 2020-05-21 14:11:28 7 | */ 8 | async function onScan (qrcode, status) { 9 | require('qrcode-terminal').generate(qrcode, {small: true}) 10 | 11 | const qrcodeImageUrl = [ 12 | 'https://api.qrserver.com/v1/create-qr-code/?data=', 13 | encodeURIComponent(qrcode), 14 | ].join('') 15 | 16 | console.log(status, qrcodeImageUrl) 17 | } 18 | 19 | module.exports = onScan -------------------------------------------------------------------------------- /config/superagent.js: -------------------------------------------------------------------------------- 1 | const superagent = require('superagent') 2 | 3 | /** 4 | * 接口请求封装 使用superagent发送请求 5 | * @param {*} url 6 | * @param {*} method 7 | * @param {*} params 8 | * @param {*} data 9 | * @param {*} cookies 10 | */ 11 | function req(url, method, params, data, cookies) { 12 | return new Promise(function (resolve, reject) { 13 | superagent(method, url) 14 | .query(params) 15 | .send(data) 16 | .set('Content-Type', 'application/x-www-form-urlencoded') 17 | .end(function (err, response) { 18 | if (err) { 19 | reject(err) 20 | } 21 | resolve(response) 22 | }) 23 | }) 24 | } 25 | module.exports = { 26 | req 27 | } -------------------------------------------------------------------------------- /schedule/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 定时任务 接口封装 3 | */ 4 | const schedule = require('node-schedule') 5 | //其他规则见 https://www.npmjs.com/package/node-schedule 6 | // 规则参数讲解 *代表通配符 7 | // 8 | // * * * * * * 9 | // ┬ ┬ ┬ ┬ ┬ ┬ 10 | // │ │ │ │ │ | 11 | // │ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun) 12 | // │ │ │ │ └───── month (1 - 12) 13 | // │ │ │ └────────── day of month (1 - 31) 14 | // │ │ └─────────────── hour (0 - 23) 15 | // │ └──────────────────── minute (0 - 59) 16 | // └───────────────────────── second (0 - 59, OPTIONAL) 17 | 18 | // 每分钟的第30秒触发: '30 * * * * *' 19 | // 20 | // 每小时的1分30秒触发 :'30 1 * * * *' 21 | // 22 | // 每天的凌晨1点1分30秒触发 :'30 1 1 * * *' 23 | // 24 | // 每月的1日1点1分30秒触发 :'30 1 1 1 * *' 25 | // 26 | // 每周1的1点1分30秒触发 :'30 1 1 * * 1' 27 | 28 | function setSchedule(date, callback) { 29 | schedule.scheduleJob(date, callback) 30 | } 31 | module.exports = { 32 | setSchedule 33 | } 34 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Peanut 3 | * @Description: 实例化 - 入口文件 4 | * @Date: 2020-05-19 21:55:04 5 | * @Last Modified by: Peanut 6 | * @Last Modified time: 2020-05-24 00:12:54 7 | */ 8 | const { Wechaty } = require("wechaty"); 9 | const { PuppetPadplus } = require("wechaty-puppet-padplus"); 10 | const config = require("./config"); 11 | //ipad协议 12 | const bot = new Wechaty({ 13 | puppet: new PuppetPadplus({ 14 | token: config.TOKEN 15 | }), 16 | name: "WeChat-Robot" 17 | }); 18 | //web协议 19 | // const bot = new Wechaty({ 20 | // name: "WeChat-Robot" 21 | // }); 22 | bot.on("login", "./listeners/on-login.js"); 23 | bot.on("message", "./listeners/on-message"); 24 | bot.on("scan", "./listeners/on-scan"); 25 | bot.on("friendship", "./listeners/on-friendship"); 26 | bot.on("room-join", "./listeners/on-room-join"); 27 | bot.on("room-leave", "./listeners/on-room-leave"); 28 | bot 29 | .start() 30 | .then(() => console.log("开始登陆微信")) 31 | .catch(e => console.error(e)); 32 | module.exports = bot; 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Peanut 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wechat-robot", 3 | "version": "1.0.0", 4 | "description": "一款nodejs版微信机器人,群聊小助手", 5 | "author": "Peanut ", 6 | "website": "https://iiter.cn", 7 | "license": "MIT", 8 | "keywords": [ 9 | "微信机器人", 10 | "微信小助手", 11 | "微信群聊机器人", 12 | "微信小秘书", 13 | "微信每日说", 14 | "wechaty", 15 | "微信助手" 16 | ], 17 | "main": "app.js", 18 | "engines": { 19 | "node": ">= 10" 20 | }, 21 | "scripts": { 22 | "start": "node app.js" 23 | }, 24 | "dependencies": { 25 | "cheerio": "^1.0.0-rc.2", 26 | "is-pr": "^1.1.0", 27 | "node-schedule": "^1.3.2", 28 | "qrcode-terminal": "^0.12.0", 29 | "request": "^2.88.0", 30 | "superagent": "^4.1.0", 31 | "wechaty": "^0.38.4", 32 | "wechaty-puppet": "^0.24.0", 33 | "wechaty-puppet-padplus": "^0.6.3" 34 | }, 35 | "devDependencies": { 36 | "@chatie/eslint-config": "^0.6.17", 37 | "@chatie/git-scripts": "^0.2.5", 38 | "@chatie/tsconfig": "^0.6.1", 39 | "check-node-version": "^3.2.0" 40 | }, 41 | "git": { 42 | "scripts": { 43 | "pre-push": "npx git-scripts-pre-push" 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /listeners/on-login.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Peanut 3 | * @Description: 登录 4 | * @Date: 2020-05-20 23:21:06 5 | * @Last Modified by: Peanut 6 | * @Last Modified time: 2020-05-20 23:21:42 7 | */ 8 | const schedule = require("../schedule"); 9 | const config = require("../config"); 10 | const untils = require("../utils"); 11 | const superagent = require("../superagent"); 12 | const bot = require("../app"); 13 | /** 14 | * @description 您的机器人上线啦 15 | * @param {} user 16 | */ 17 | async function onLogin(user) { 18 | console.log(`贴心小助理${user}登录了`); 19 | //创建定时发送群消息任务 20 | await onRoom(); 21 | } 22 | /** 23 | * 9点定时给指定群发送消息 24 | */ 25 | async function onRoom() { 26 | //匹配规则可参考 schedule/index.js 27 | const time = "0 0 9 * * *"; 28 | schedule.setSchedule(time, async () => { 29 | const room = await bot.Room.find({ 30 | topic: config.WEBROOM 31 | }); 32 | let today = await untils.formatDate(new Date()); //获取今天的日期 33 | let one = await superagent.getOne(); //获取每日一句 34 | const englishData = await superagent.getEnglishOne(); //英语一句话 35 | let english = `en:${englishData.en}\nzh:${englishData.zh}`; 36 | let poison = await superagent.getPoison(); //毒鸡汤 37 | const str = `${today}\n元气满满的一天开始啦,要加油噢^_^\n\n每日一句:\n${one}\n\n英语一句话:\n${english}\n\n毒鸡汤:\n${poison}`; 38 | await room.say(str); 39 | }); 40 | } 41 | module.exports = onLogin; 42 | -------------------------------------------------------------------------------- /utils/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * utils工具 3 | * by: Peanut 4 | */ 5 | 6 | 7 | /** 8 | * 获取当前日期 9 | * @param {*} date 10 | */ 11 | function getDay(date) { 12 | var date2 = new Date(); 13 | var date1 = new Date(date); 14 | var iDays = parseInt(Math.abs(date2.getTime() - date1.getTime()) / 1000 / 60 / 60 / 24); 15 | return iDays; 16 | } 17 | /** 18 | * 获取当前具体时间 19 | * @param {*} date 20 | */ 21 | function formatDate(date) { 22 | var tempDate = new Date(date); 23 | var year = tempDate.getFullYear(); 24 | var month = tempDate.getMonth() + 1; 25 | var day = tempDate.getDate(); 26 | var hour = tempDate.getHours(); 27 | var min = tempDate.getMinutes(); 28 | var second = tempDate.getSeconds(); 29 | var week = tempDate.getDay(); 30 | var str = '' 31 | if (week === 0) { 32 | str = '星期日' 33 | } else if (week === 1) { 34 | str = "星期一"; 35 | } else if (week === 2) { 36 | str = "星期二"; 37 | } else if (week === 3) { 38 | str = "星期三"; 39 | } else if (week === 4) { 40 | str = "星期四"; 41 | } else if (week === 5) { 42 | str = "星期五"; 43 | } else if (week === 6) { 44 | str = "星期六"; 45 | } 46 | if (hour < 10) { 47 | hour = "0" + hour; 48 | } 49 | if (min < 10) { 50 | min = "0" + min; 51 | } 52 | if (second < 10) { 53 | second = "0" + second; 54 | } 55 | return year + "-" + month + "-" + day + "日 " + hour + ":" + min + ' ' + str; 56 | } 57 | /** 58 | * rgb转base64 59 | * @param {*} color 60 | */ 61 | function colorRGBtoHex(color) { 62 | var rgb = color.split(','); 63 | var r = parseInt(rgb[0].split('(')[1]); 64 | var g = parseInt(rgb[1]); 65 | var b = parseInt(rgb[2].split(')')[0]); 66 | var hex = "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); 67 | return hex; 68 | } 69 | /** 70 | * base64转rgb 71 | * @param {*} color 72 | */ 73 | function colorHex(color) { 74 | // 16进制颜色值的正则 75 | var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/; 76 | // 把颜色值变成小写 77 | if (reg.test(color)) { 78 | // 如果只有三位的值,需变成六位,如:#fff => #ffffff 79 | if (color.length === 4) { 80 | var colorNew = "#"; 81 | for (var i = 1; i < 4; i += 1) { 82 | colorNew += color.slice(i, i + 1).concat(color.slice(i, i + 1)); 83 | } 84 | color = colorNew; 85 | } 86 | // 处理六位的颜色值,转为RGB 87 | var colorChange = []; 88 | for (var i = 1; i < 7; i += 2) { 89 | colorChange.push(parseInt("0x" + color.slice(i, i + 2))); 90 | } 91 | return "rgb(" + colorChange.join(",") + ")"; 92 | } else { 93 | return color; 94 | } 95 | }; 96 | 97 | module.exports = { 98 | getDay, formatDate, colorRGBtoHex, colorHex 99 | } 100 | -------------------------------------------------------------------------------- /superagent/index.js: -------------------------------------------------------------------------------- 1 | const superagent = require("../config/superagent"); 2 | const cheerio = require("cheerio"); 3 | const request = require("request"); 4 | const ONE = "http://wufazhuce.com/"; // ONE的web版网站 5 | const POISON = "https://8zt.cc/"; //毒鸡汤网站 6 | const TXHOST = "https://api.tianapi.com/txapi/"; // 天行host 官网:tianapi.com 7 | const APIKEY = ""; // 天行key,请先去网站注册填写key 注册免费 注册后申请下面的接口即可。 8 | /** 9 | * 获取每日一句 10 | */ 11 | async function getOne() { 12 | try { 13 | let res = await superagent.req(ONE, "GET"); 14 | let $ = cheerio.load(res.text); 15 | let todayOneList = $("#carousel-one .carousel-inner .item"); 16 | let todayOne = $(todayOneList[0]) 17 | .find(".fp-one-cita") 18 | .text() 19 | .replace(/(^\s*)|(\s*$)/g, ""); 20 | return todayOne; 21 | } catch (err) { 22 | console.log("错误", err); 23 | return err; 24 | } 25 | } 26 | 27 | /** 28 | * 获取每日毒鸡汤 29 | */ 30 | async function getSoup() { 31 | try { 32 | let res = await superagent.req(POISON, "GET"); 33 | let $ = cheerio.load(res.text); 34 | const content = $("#sentence").text(); 35 | return content; 36 | } catch (err) { 37 | console.error("err"); 38 | return err; 39 | } 40 | } 41 | 42 | /** 43 | * 获取全国肺炎数据 44 | */ 45 | function getChinaFeiyan() { 46 | return new Promise((resolve, reject) => { 47 | request.get( 48 | { 49 | url: `https://c.m.163.com/ug/api/wuhan/app/data/list-total?t=${new Date().getTime()}` 50 | }, 51 | function (err, response) { 52 | if (err) { 53 | reject(err); 54 | } 55 | const res = JSON.parse(response.body); 56 | resolve(res); 57 | } 58 | ); 59 | }); 60 | } 61 | /** 62 | * 获取省份肺炎数据 63 | */ 64 | async function getProvinceFeiyan(name) { 65 | return new Promise((resolve, reject) => { 66 | request.get( 67 | { 68 | url: `https://gwpre.sina.cn/interface/fymap2020_data.json?t=${new Date().getTime()}` 69 | }, 70 | function (err, response) { 71 | if (err) { 72 | reject(err); 73 | } 74 | try { 75 | const res = JSON.parse(response.body); 76 | res.data.list.forEach(item => { 77 | if (name === item.name) { 78 | resolve(item); 79 | return; 80 | } 81 | }); 82 | } catch (error) { 83 | reject(err); 84 | } 85 | } 86 | ); 87 | }); 88 | } 89 | /** 90 | * 获取神回复 91 | */ 92 | async function getGodReply() { 93 | const url = TXHOST + "godreply/index"; 94 | try { 95 | let res = await superagent.req(url, "GET", { 96 | key: APIKEY 97 | }); 98 | let content = JSON.parse(res.text); 99 | if (content.code === 200) { 100 | return content.newslist[0]; 101 | } else { 102 | console.log("获取接口失败", content.msg); 103 | } 104 | } catch (err) { 105 | console.log("获取接口失败", err); 106 | } 107 | } 108 | /** 109 | * 每日英语一句话 110 | */ 111 | async function getEnglishOne() { 112 | const url = TXHOST + "ensentence/index"; 113 | try { 114 | let res = await superagent.req(url, "GET", { 115 | key: APIKEY 116 | }); 117 | let content = JSON.parse(res.text); 118 | if (content.code === 200) { 119 | return content.newslist[0]; //en英文 zh中文 120 | } else { 121 | console.log("获取接口失败", content.msg); 122 | } 123 | } catch (err) { 124 | console.log("获取接口失败", err); 125 | } 126 | } 127 | module.exports = { 128 | getOne, 129 | getSoup, 130 | getChinaFeiyan, 131 | getProvinceFeiyan, 132 | getGodReply, 133 | getEnglishOne 134 | }; 135 | -------------------------------------------------------------------------------- /listeners/on-message.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: Peanut 3 | * @Description: 处理用户消息 4 | * @Date: 2020-05-20 22:36:28 5 | * @Last Modified by: Peanut 6 | * @Last Modified time: 2020-05-23 23:20:36 7 | */ 8 | const bot = require("../app.js"); 9 | const { UrlLink } = require("wechaty"); 10 | const path = require("path"); 11 | const { FileBox } = require("file-box"); 12 | const superagent = require("../superagent"); 13 | const config = require("../config"); 14 | const { colorRGBtoHex, colorHex } = require("../utils"); 15 | 16 | const allKeywords = `回复序号或关键字获取对应服务 17 | 1.${config.WEBROOM} 18 | 2.毒鸡汤 19 | 3.神回复(略微开车) 20 | 4.英语一句话 21 | 转小写(例:转小写PEANUT) 22 | 转大写(例:转大写peanut) 23 | 转rgb(例:转rgb#cccccc) 24 | 转16进制(例:转16进制rgb(255,255,255)) 25 | 天气 城市名(例:天气 西安) 26 | 全国肺炎(实时肺炎数据) 27 | 省份/自治区 肺炎(例:河南肺炎)`; 28 | /** 29 | * sleep 30 | * @param {*} ms 31 | */ 32 | const delay = ms => new Promise(resolve => setTimeout(resolve, ms)); 33 | /** 34 | * 处理消息 35 | */ 36 | async function onMessage(msg) { 37 | //防止自己和自己对话 38 | if (msg.self()) return; 39 | const room = msg.room(); // 是否是群消息 40 | if (room) { 41 | //处理群消息 42 | await onWebRoomMessage(msg); 43 | } else { 44 | //处理用户消息 用户消息暂时只处理文本消息。后续考虑其他 45 | const isText = msg.type() === bot.Message.Type.Text; 46 | if (isText) { 47 | await onPeopleMessage(msg); 48 | } 49 | } 50 | } 51 | /** 52 | * 处理用户消息 53 | */ 54 | async function onPeopleMessage(msg) { 55 | //获取发消息人 56 | const contact = msg.from(); 57 | //对config配置文件中 ignore的用户消息不必处理 58 | if (config.IGNORE.includes(contact.payload.name)) return; 59 | let content = msg.text().trim(); // 消息内容 使用trim()去除前后空格 60 | 61 | if (content === "菜单") { 62 | await delay(200); 63 | await msg.say(allKeywords); 64 | } else if (content === "打赏") { 65 | //这里换成自己的赞赏二维码 66 | const fileBox = FileBox.fromFile(path.join(__dirname, "../imgs/pay.png")); 67 | await msg.say("我是秦始皇,打钱!!!!!"); 68 | await delay(200); 69 | await msg.say(fileBox); 70 | } else if (content === config.WEBROOM || parseInt(content) === 1) { 71 | const webRoom = await bot.Room.find({ 72 | topic: config.WEBROOM 73 | }); 74 | if (webRoom) { 75 | try { 76 | await delay(200); 77 | await webRoom.add(contact); 78 | } catch (e) { 79 | console.error(e); 80 | } 81 | } 82 | } else if (content === "毒鸡汤" || parseInt(content) === 2) { 83 | let soup = await superagent.getSoup(); 84 | await delay(200); 85 | await msg.say(soup); 86 | } else if (content === "神回复" || parseInt(content) === 3) { 87 | const { title, content } = await superagent.getGodReply(); 88 | await delay(200); 89 | await msg.say(`标题:${title}

神回复:${content}`); 90 | } else if (content === "英语一句话" || parseInt(content) === 4) { 91 | const { en, zh } = await superagent.getEnglishOne(); 92 | await delay(200); 93 | await msg.say(`en:${en}

zh:${zh}`); 94 | } else if (content === "艾特网" || content === "导航站") { 95 | //发送链接卡片 web版协议不可用。 96 | const urlLink = new UrlLink({ 97 | description: "来了来了,专为程序员量身定做的导航站来了!", 98 | thumbnailUrl: "https://www.iiter.cn/_nuxt/img/f996b71.png", 99 | title: "艾特网 - 程序员专用导航站", 100 | url: "https://iiter.cn" 101 | }); 102 | await msg.say(urlLink); 103 | } else if (content === "客服") { 104 | const contactCard = await bot.Contact.find({ alias: config.MYSELF }); // change 'lijiarui' to any of the room member 105 | await msg.say(contactCard); 106 | } else { 107 | const noUtils = await onUtilsMessage(msg); 108 | if (noUtils) { 109 | await delay(200); 110 | await msg.say(allKeywords); 111 | } 112 | } 113 | } 114 | /** 115 | * 处理群消息 116 | */ 117 | async function onWebRoomMessage(msg) { 118 | const isText = msg.type() === bot.Message.Type.Text; 119 | if (isText) { 120 | const content = msg.text().trim(); // 消息内容 121 | if (content === "毒鸡汤") { 122 | let poison = await superagent.getSoup(); 123 | await delay(200); 124 | await msg.say(poison); 125 | } else if (content === "英语一句话") { 126 | const res = await superagent.getEnglishOne(); 127 | await delay(200); 128 | await msg.say(`en:${res.en}

zh:${res.zh}`); 129 | } else if (content.includes("踢@")) { 130 | // 踢人功能 群里发送 踢@某某某 即可 131 | const room = msg.room(); 132 | //获取发消息人 133 | const contact = msg.from(); 134 | const alias = await contact.alias(); 135 | //如果是机器人好友且备注是自己的大号备注 才执行踢人操作 136 | if (contact.friend() && alias === config.MYSELF) { 137 | const delName = content.replace("踢@", "").trim(); 138 | const delContact = await room.member({ name: delName }); 139 | await room.del(delContact); 140 | await msg.say(delName + "已被移除群聊。且聊且珍惜啊!"); 141 | } 142 | // @用户 143 | // const room = msg.room(); 144 | // const members = await room.memberAll(); //获取所有群成员 145 | // const someMembers = members.slice(0, 3); 146 | // await room.say("Hello world!", ...someMembers); //@这仨人 并说 hello world 147 | } else { 148 | await onUtilsMessage(msg); 149 | } 150 | } 151 | } 152 | 153 | /** 154 | * utils消息处理 155 | */ 156 | async function onUtilsMessage(msg) { 157 | const contact = msg.from(); // 发消息人 158 | const isText = msg.type() === bot.Message.Type.Text; 159 | if (isText) { 160 | let content = msg.text().trim(); // 消息内容 161 | if (content.indexOf("转大写") === 0) { 162 | try { 163 | const str = content.replace("转大写", "").trim().toUpperCase(); 164 | await msg.say(str); 165 | } catch (error) { 166 | await msg.say("转换失败,请检查"); 167 | } 168 | } else if (content.indexOf("转小写") === 0) { 169 | try { 170 | const str = content.replace("转小写", "").trim().toLowerCase(); 171 | await msg.say(str); 172 | } catch (error) { 173 | await msg.say("转换失败,请检查"); 174 | } 175 | } else if (content.indexOf("转16进制") === 0) { 176 | try { 177 | const color = colorRGBtoHex(content.replace("转16进制", "").trim()); 178 | await msg.say(color); 179 | } catch (error) { 180 | console.error(error); 181 | await msg.say("转换失败,请检查"); 182 | } 183 | } else if (content.indexOf("转rgb") === 0) { 184 | try { 185 | const color = colorHex(content.replace("转rgb", "").trim()); 186 | await msg.say(color); 187 | } catch (error) { 188 | console.error(error); 189 | await msg.say("转换失败,请检查"); 190 | } 191 | } else if (content === "全国肺炎") { 192 | try { 193 | const res = await superagent.getChinaFeiyan(); 194 | const chinaTotal = res.data.chinaTotal.total; 195 | const chinaToday = res.data.chinaTotal.today; 196 | const str = `全国新冠肺炎实时数据:
确诊:${ 197 | chinaTotal.confirm 198 | }
较昨日:${ 199 | chinaToday.confirm > 0 ? "+" + chinaToday.confirm : chinaToday.confirm 200 | }
疑似:${chinaTotal.suspect}
较昨日:${ 201 | chinaToday.suspect > 0 ? "+" + chinaToday.suspect : chinaToday.suspect 202 | }
死亡:${chinaTotal.dead}
较昨日:${ 203 | chinaToday.dead > 0 ? "+" + chinaToday.dead : chinaToday.dead 204 | }
治愈:${chinaTotal.heal}
较昨日:${ 205 | chinaToday.heal > 0 ? "+" + chinaToday.heal : chinaToday.heal 206 | }
------------------
数据采集于网易,如有问题,请及时联系`; 207 | msg.say(str); 208 | } catch (error) { 209 | msg.say("接口错误"); 210 | } 211 | } else if (content.includes("肺炎")) { 212 | const config = [ 213 | "北京", 214 | "湖北", 215 | "广东", 216 | "浙江", 217 | "河南", 218 | "湖南", 219 | "重庆", 220 | "安徽", 221 | "四川", 222 | "山东", 223 | "吉林", 224 | "福建", 225 | "江西", 226 | "江苏", 227 | "上海", 228 | "广西", 229 | "海南", 230 | "陕西", 231 | "河北", 232 | "黑龙江", 233 | "辽宁", 234 | "云南", 235 | "天津", 236 | "山西", 237 | "甘肃", 238 | "内蒙古", 239 | "台湾", 240 | "澳门", 241 | "香港", 242 | "贵州", 243 | "西藏", 244 | "青海", 245 | "新疆", 246 | "宁夏" 247 | ]; 248 | let newContent = content.replace("肺炎", "").trim(); 249 | if (config.includes(newContent)) { 250 | const data = await superagent.getProvinceFeiyan(newContent); 251 | let citystr = "名称 确诊 治愈 死亡
"; 252 | data.city.forEach(item => { 253 | citystr = 254 | citystr + 255 | `${item.name} ${item.conNum} ${item.cureNum} ${item.deathNum}
`; 256 | }); 257 | const str = `${newContent}新冠肺炎实时数据:
确诊:${data.value}
较昨日:${data.adddaily.conadd}
死亡:${data.deathNum}
较昨日:${data.adddaily.deathadd}
治愈:${data.cureNum}
较昨日:${data.adddaily.cureadd}
------------------
各地市实时数据:
${citystr}------------------
数据采集于新浪,如有问题,请及时联系`; 258 | msg.say(str); 259 | } 260 | } else { 261 | return true; 262 | } 263 | } else { 264 | return true; 265 | } 266 | } 267 | module.exports = onMessage; 268 | --------------------------------------------------------------------------------