背景
我們?nèi)粘C刻於夹枰獙?xiě)日?qǐng)?bào),用來(lái)匯報(bào)今日工作內(nèi)容和明日工作計(jì)劃。日?qǐng)?bào)內(nèi)容維護(hù)在wiki里面。團(tuán)隊(duì)TL每天會(huì)去wiki上收集工作內(nèi)容;在發(fā)送到公司大群。但是每天會(huì)有小伙伴會(huì)忘記寫(xiě)。 導(dǎo)致 TL沒(méi)辦法收集今日內(nèi)容。很是苦惱。還有每次編寫(xiě)都需要去wiki挨個(gè)復(fù)制每個(gè)人的。 工作效率很低;
思考
之前也了解過(guò)wechaty,就想著是否可以做一個(gè)每天快下班提醒團(tuán)隊(duì)小伙伴,維護(hù)下工作日?qǐng)?bào)。以及團(tuán)隊(duì)TL便捷獲取團(tuán)隊(duì)所有日?qǐng)?bào)的系統(tǒng)。不需要一個(gè)個(gè)復(fù)制;
項(xiàng)目地址
github:https://github.com/zzhoouxin/wechaty-bot
基礎(chǔ)依賴
- wechaty --微信操作
- node-schedule --定時(shí)任務(wù)
- superagent --接口請(qǐng)求
- cheerio -- 抓取數(shù)據(jù)
- qrcode-terminal --終端顯示二維碼
功能
- 定時(shí)提醒組內(nèi)小伙伴填寫(xiě)工作日?qǐng)?bào)以及發(fā)送工作日?qǐng)?bào)到工作群
- 根據(jù)關(guān)鍵字自動(dòng)發(fā)送日?qǐng)?bào)內(nèi)容
- 后續(xù)功能...(等待和小組人員討論)
項(xiàng)目成果
-
日常提醒
日常提醒 -
定時(shí)發(fā)送日?qǐng)?bào)
定時(shí)發(fā)送日?qǐng)?bào) -
根據(jù)關(guān)鍵字發(fā)送日?qǐng)?bào)內(nèi)容
image.png
實(shí)現(xiàn)過(guò)程
1.項(xiàng)目結(jié)構(gòu)

- bot 存放wechaty每個(gè)狀態(tài)的回調(diào)函數(shù)
- schecdule 定時(shí)任務(wù)-獲取日?qǐng)?bào)并發(fā)送
- config 基本配置-鏈接、群號(hào)等
- tool 封裝基礎(chǔ)請(qǐng)求、公共方法
- index.js 啟動(dòng)入口
2.核心代碼
1.index.js -- wechaty啟動(dòng)入口
const {Wechaty} = require('wechaty')
const {PuppetPadplus} = require("wechaty-puppet-padplus");
const config = require('./config')
const onScan = require('./bot/onScan')
const onLogin = require('./bot/onLogin')
const onMessage = require('./bot/onMessage')
const onLogout = require('./bot/onLogout')
const bot = new Wechaty({
puppet: new PuppetPadplus({
token: config.TOKEN
}),
name: "小艾"
});
bot
.on('scan', onScan)
.on('login', onLogin(bot))
.on('logout', onLogout)
.on('message', onMessage(bot))
.start()
.then(() => console.log('開(kāi)始登陸微信'))
.catch(e => console.error(e))
這邊使用的是wechaty-puppet-padplus基于ipad協(xié)議進(jìn)行開(kāi)發(fā)的;scan login logout message這些是Wechaty的基礎(chǔ)回調(diào)事件。
2.config 基礎(chǔ)文件配置這里面都是自己基于自己業(yè)務(wù)的參數(shù)-如果您也是用confluence wiki 那可以參考下
// 配置文件
module.exports = {
// 每個(gè)人對(duì)應(yīng)頁(yè)面的ID
ALL_USER_LIST: [
{ id: 27169291, name: '小人頭'},
],
WITHDRAWA_DATE: '00 50 17 * * *', //定時(shí)任務(wù)事件
COLLOECT_DATE:'10 30 09 * * *', // 定時(shí)任務(wù)事件
WIKI_URL: 'http://wiki.xxxxx.com/pages/viewpage.action?pageId=', //wiki內(nèi)容地址
TOKEN: 'puppet_padplus_xxxxx',//token
ROOM: '22186778457@chatroom',//需要發(fā)送的群號(hào)
KEYWORDs:['本組','全部']
};

里面的wiki_url 是我們自己平常填寫(xiě)日?qǐng)?bào)的wiki地址。如果您使用其他方式-那就具體情況具體分析
3.定時(shí)任務(wù)提醒
- 在登錄后啟動(dòng)定時(shí)任務(wù)
這邊我們就使用到了- node-schedule 這個(gè)node庫(kù) 當(dāng)然可以配置他的啟動(dòng)時(shí)間??梢圆榭垂倬W(wǎng)詳細(xì)說(shuō)明。
3.1首頁(yè)我們?cè)趙echaty的onlogin事件里面加入定時(shí)任務(wù)
const dailyRemind = require('../schedule/dailyRemind')
const collectContent = require('../schedule/collectContent')
/**
* 掃碼登錄
* @param qrcode
* @param status
*/
module.exports = bot => {
return async function onLogin() {
await dailyRemind(bot);//日常提醒
await collectContent(bot);//所有匯總
}
}
3.2創(chuàng)建一個(gè)定時(shí)提醒的任務(wù)
- 通過(guò)bot.Room.find(id)找到需要提醒的群
- 在使用announce創(chuàng)建群公告 @所有人 即可做到提醒
const schedule = require('./index');
const config = require('../config');
const utils = require('../tool/utils')
module.exports =async function dailyRemind(bot) {
schedule.setSchedule(config.WITHDRAWA_DATE, async () => {
if(!utils.judgeIsJob()){ //周末的話,不做提醒
return false;
}
try {
//提醒組內(nèi)人發(fā)送日?qǐng)?bào)
const searchRoom = await bot.Room.find({ id: config.ROOM});
await searchRoom.announce("快下班了~大佬們可以更新一下日?qǐng)?bào)啦~/:@)")
} catch (e) {
console.log("error:",e.message);
}
});
}
4.根據(jù)關(guān)鍵字。發(fā)送日?qǐng)?bào)內(nèi)容
- 上圖中 機(jī)器人會(huì)自動(dòng)提示,需要回復(fù)什么關(guān)鍵字。當(dāng)然這一步是我們自己配置的。在config.js里面有關(guān)鍵字配置屬性。直接看代碼
- 機(jī)器人自動(dòng)回復(fù)-就需要在
message事件里面處理啦-message的官方文檔
// 監(jiān)聽(tīng)對(duì)話
const { Message } = require('wechaty');
const config = require('../config');
module.exports = (bot) => {
return async function onMessage(msg) {
const contact = msg.from(); // 發(fā)消息人
const content = msg.text(); //消息內(nèi)容
const room = msg.room(); //是否是群消息
if (msg.self()) {
return;
}
//如果是文本消息
if (msg.type() == Message.Type.Text) {
// await textJ(bot);
if (room) {
console.log('room===>', room);
// 如果是群消息
const topic = await room.topic();
console.log(
`群名: ${topic} 發(fā)消息人: ${contact.name()} 內(nèi)容: ${content}`
);
} else {
let info = `日?qǐng)?bào)查詢僅支持2種,回復(fù)【】?jī)?nèi)文字即可查詢~\n`;
config.KEYWORDs.map((v) => {
info += '【' + v + '】' + '\n';
});
msg.say(info);
}
}
};
};
5.獲取自己需要的信息
- 上文中提交到我們有
日?qǐng)?bào)填寫(xiě)的地址 - 以及 superagent 、cheerio 2個(gè)依賴庫(kù)-主要用到請(qǐng)求我們?nèi)請(qǐng)?bào)地址 并且獲取所需要的內(nèi)容
wiki基礎(chǔ)頁(yè)面結(jié)構(gòu)
這個(gè)是我們wiki文檔的項(xiàng)目結(jié)構(gòu)-我們首先需求通過(guò)superagent請(qǐng)求訪問(wèn)該頁(yè)面-并且通過(guò)cheero獲取內(nèi)容。當(dāng)然這2個(gè)依賴庫(kù)使用。建議先熟悉一下官方文檔。下文代碼做了一些兼容--
async function collectUserContent() {
let str = '';
for (let user of config.ALL_USER_LIST) {
const url = `${config.WIKI_URL}${user.id}`;
const res = await fetch(url);
let $ = cheerio.load(res.text);
// const data = $('.wiki-content .p1').text();
str += `\n ${user.name} \n`;
$('.wiki-content p').each(function (i, e) {
let text = $(e).text();
if (text !== '\xa0') {
str += ` ${text} \n`;
}
});
$('.wiki-content .p1pkss0x').each(function (i, e) {
let html = $(e).children();
if (html.length === 0) {
let text = $(e).text();
if (text !== '\xa0') {
str += ` ${text} \n`;
}
}
});
$('.wiki-content .pd7nslm').each(function (i, e) {
let html = $(e).children();
if (html.length === 1) {
let text = $(e).text();
if (text !== '\xa0') {
str += ` ${text} \n`;
}
}
});
}
return str;
}
獲取到自己需要的內(nèi)容,依舊可以通過(guò)room.say發(fā)送出去;
至此我們一個(gè)簡(jiǎn)單的日?qǐng)?bào)收集的系統(tǒng)機(jī)器人簡(jiǎn)單的實(shí)現(xiàn)了。
總結(jié)
相信很多公司都有發(fā)送日?qǐng)?bào)的要求。以上代碼實(shí)現(xiàn)也是依賴了自己所需業(yè)務(wù)場(chǎng)景進(jìn)行實(shí)現(xiàn)。通過(guò)wechaty改變了我們傳統(tǒng)的工作流程。大大的提高了工作效率。避免很多重復(fù)行為。當(dāng)然還有更多好玩有趣的功能區(qū)可以加入。希望自己可以和團(tuán)隊(duì)進(jìn)行溝通,提高我們流程。大家可以參考以上流程。



