├── src ├── getToken │ ├── token.json │ └── index.js ├── sendMessage │ └── index.js └── config │ └── config.js ├── package.json ├── README.md └── app.js /src/getToken/token.json: -------------------------------------------------------------------------------- 1 | { 2 | "access_token": "60_RZG-Cxj9GJ6RpP5wTil6NEP0stVfWGGxDTGI9_vT72sZUJ4yg7pE1jLcdUGrVYuQPRBfirD5_4XPkaXLpKNIzHZycvChjAwO-upcNgC9pVWQkuN20xb1MH926luWbcdAttFfYG0ZYoFQOXc-PRSgABAACD", 3 | "expires_in": 1661164689 4 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "1", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node ./app.js" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "axios": "^0.27.2", 14 | "moment": "^2.29.4" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/sendMessage/index.js: -------------------------------------------------------------------------------- 1 | var axios = require('axios') 2 | 3 | function sendMessage(data) { 4 | return axios.post( 5 | 'https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=' + 6 | data.access_token, 7 | { 8 | touser: data.touser, 9 | template_id: data.template_id, 10 | data: data.data || {}, 11 | } 12 | ) 13 | } 14 | 15 | module.exports = sendMessage 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 环境说明 2 | 3 | ``` 4 | nodejs版本 v12.16.0 5 | ``` 6 | 7 | ## 运行项目 8 | 9 | ```shell 10 | npm i 11 | npm start 12 | ``` 13 | 14 | ## 其他说明 15 | 16 | #### 公众号测试地址 17 | 18 | https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login 19 | 20 | #### 模板案例 21 | 22 | ``` 23 | {{nowDate.DATA}} 城市:{{city.DATA}} 24 | 25 | 天气: 晴 26 | 27 | 最低气温: {{low.DATA}} 28 | 29 | 最高气温: {{high.DATA}} 30 | 31 | 今天是我们恋爱的 {{loveDate.DATA}} 天 32 | 33 | 34 | {{txt.DATA}} 35 | ``` 36 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | const { params, listConfig } = require('./src/config/config') 2 | const getToken = require('./src/getToken/index') 3 | const sendMessage = require('./src/sendMessage/index') 4 | 5 | async function start() { 6 | let access_token 7 | 8 | try { 9 | access_token = await getToken(params) 10 | } catch (error) { 11 | console.log(error) 12 | process.exit(0) 13 | } 14 | 15 | sendMessage({ 16 | ...params, 17 | access_token, 18 | ...listConfig, 19 | }) 20 | .then((res) => { 21 | if (res.data && res.data.errcode) { 22 | console.error('发送失败', res.data) 23 | return 24 | } 25 | console.log('发送成功-请在微信上查看对应消息') 26 | }) 27 | .catch((err) => console.error('发送失败', err)) 28 | } 29 | 30 | start() 31 | -------------------------------------------------------------------------------- /src/config/config.js: -------------------------------------------------------------------------------- 1 | const params = { 2 | appid: 'wxb98e44f5e7a956a0', 3 | secret: 'a55ef17ddaa3c5bf0cabd344e6c7d17e', 4 | touser: 'ohqRj6EBIUp4gzIQ3mUbULM9uQnQ', 5 | template_id: 'LvDuTb8njKAv-nG_2L2GT-bkZPCJi_xmmk1Zn5zRF1U', 6 | } 7 | 8 | const listConfig = { 9 | data: { 10 | nowDate: { 11 | value: '今天是 2022/08/20 周天 ', 12 | color: '#57E6E2', 13 | }, 14 | city: { 15 | value: '北京', 16 | color: '#9CA2A0', 17 | }, 18 | low: { 19 | value: '29℃', 20 | color: '#7CD47D', 21 | }, 22 | high: { 23 | value: '37℃', 24 | color: '#CBA476', 25 | }, 26 | loveDate: { 27 | value: '999', 28 | color: '#AEC5C8', 29 | }, 30 | 31 | txt: { 32 | value: '我习惯在包里藏一瓶百无聊赖,打发人间的白云和苍狗设计睡着的未来', 33 | color: '#3C4244', 34 | }, 35 | }, 36 | } 37 | 38 | /* 上述代码是需要自定义的配置项 */ 39 | function verifyEmpty() { 40 | var flag = '' 41 | for (const key in params) { 42 | if (Object.hasOwnProperty.call(params, key)) { 43 | if (!params[key]) { 44 | flag = key 45 | break 46 | } 47 | } 48 | } 49 | return flag 50 | } 51 | 52 | // 校验为空 53 | if (verifyEmpty()) { 54 | console.error( 55 | '警告:请完善 “/src/config/config.js中的配置项: ' + 56 | verifyEmpty() + 57 | '”的内容,再执行代码!' 58 | ) 59 | process.exit(0) 60 | } 61 | 62 | module.exports = { 63 | params, 64 | listConfig, 65 | } 66 | -------------------------------------------------------------------------------- /src/getToken/index.js: -------------------------------------------------------------------------------- 1 | var axios = require('axios') 2 | var path = require('path') 3 | var fs = require('fs') 4 | const moment = require('moment') 5 | 6 | function getToken(params) { 7 | return new Promise((resolve, reject) => { 8 | const tokenFile = path.join(__dirname, 'token.json') 9 | fs.readFile(tokenFile, 'utf-8', function (err, data) { 10 | if (err) { 11 | reject(err) 12 | } else { 13 | if (data) { 14 | const token = JSON.parse(data) 15 | if (token.expires_in > moment().unix()) { 16 | resolve(token.access_token) 17 | return 18 | } 19 | } 20 | const appid = params.appid 21 | const secret = params.secret 22 | axios 23 | .get( 24 | `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appid}&secret=${secret}` 25 | ) 26 | .then((res) => { 27 | if (res.data && res.data.errcode) { 28 | reject(data) 29 | return 30 | } 31 | resolve(res.data.access_token) 32 | const t = res.data 33 | t.expires_in = t.expires_in + moment().unix() - 1200 34 | fs.writeFile( 35 | tokenFile, 36 | JSON.stringify(t, '', '\t'), 37 | function (err) { 38 | if (err) { 39 | reject(err) 40 | } 41 | } 42 | ) 43 | }) 44 | .catch((err) => reject(err)) 45 | } 46 | }) 47 | }) 48 | } 49 | 50 | module.exports = getToken 51 | --------------------------------------------------------------------------------