Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
Qiu-Jun committed Aug 19, 2022
0 parents commit 1d5dc3e
Show file tree
Hide file tree
Showing 26 changed files with 941 additions and 0 deletions.
29 changes: 29 additions & 0 deletions .autod.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use strict';

module.exports = {
write: true,
prefix: '^',
plugin: 'autod-egg',
test: [
'test',
'benchmark',
],
dep: [
'egg',
'egg-scripts',
],
devdep: [
'egg-ci',
'egg-bin',
'egg-mock',
'autod',
'autod-egg',
'eslint',
'eslint-config-egg',
],
exclude: [
'./test/fixtures',
'./dist',
],
};

1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
coverage
4 changes: 4 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "eslint-config-egg",
"root": true
}
46 changes: 46 additions & 0 deletions .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions

name: Node.js CI

on:
push:
branches:
- main
- master
pull_request:
branches:
- main
- master
schedule:
- cron: '0 2 * * *'

jobs:
build:
runs-on: ${{ matrix.os }}

strategy:
fail-fast: false
matrix:
node-version: [16]
os: [ubuntu-latest, windows-latest, macos-latest]

steps:
- name: Checkout Git Source
uses: actions/checkout@v2

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}

- name: Install Dependencies
run: npm i

- name: Continuous Integration
run: npm run ci

- name: Code Coverage
uses: codecov/codecov-action@v1
with:
token: ${{ secrets.CODECOV_TOKEN }}
14 changes: 14 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
logs/
npm-debug.log
yarn-error.log
node_modules/
package-lock.json
yarn.lock
coverage/
.idea/
run/
.DS_Store
*.sw*
*.un~
typings/
.nyc_output/
78 changes: 78 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@

> 这个项目原项目是py的,后在小红书网友想要node版本的,所以做了一个。[原项目](https://github.com/erwanjun/weixin_tuisong)
#### 准备环境
+ redis
> 解决第三方接口频繁请求次数的问题,像第三方天气接口时有次数限制的, 而且一天请求一次就好,window用户可以用phpstudy方便;linux可以用宝塔;mac的话百度也挺简单的, phpstudy也有mac版本的,但是我没用过,我mac的redis是自己手动安装的
+ 花生壳
> 为了内网穿透做域名校验,注册就送一个免费的域名,够玩. 当然内网穿透工具并不只有这个,也可以用其他的.这里用花生壳内网穿透到本地的服务端口,理论上只要你电脑不关机,花生壳不挂,那么这个服务可以一直就这么使用,可以节约成本
+ 启动项目

```javascript
// 信息配置在config/config.default.js
// 公众号配置
config.wx = {
appId: 'wx6a908ab36533ea40', // 公众号appid
appSecret: '76d09eb43886a44cf2bb993c99206934', // 公众号密钥
token: 'junetext', // 公众号接口配置token
template_id: 'Z9NaV8KlzSR8-AA7Mb22PjqI1dwq0xggxeMUEjDbhGg', // 推送的模板id
user: 'wx6a908ab36533ea40' // 公众号appid
}

config.userData = {
mineBirth: '1994-03-24', // 自己的生日
gfBirth: '1994-12-26', // 女朋友的生日
loveDay: '2007-08-11', // 在一起的日期
city: '广州' // 获取天气使用
}

// 第三方
config.apiConfig = {
tianxing: {
appKey: 'bcaddf1605dd53c3115c5a709082ac6f '
}
}
```
```bash
# 先确定你启动了redis和安装了node
# 把项目拉或者下载到本地,然后在项目目录启动终端
npm install
npm run start
```
+ 公众号配置
<p style="color: #f34250;">主要: 只有启动了服务端才可以配置这里</p>

![如图](./gitPic/wxConfig.jpg)

<p style="color: #f34250;font-size: 24px;">大家自己去申请个公众号吧,但是个人的是没办法做推送的. 可以申请测试的, 你和你对象都关注就可以了. 目前的推送是每天八点自动推送给关注的人.也有接口可以调接口推送</p>
<p style="color: #f34250;">目前的推送是每天八点自动推送给关注的人.也有接口可以调接口推送</p>

![如图](./gitPic/qrcode.jpg)

### 添加模板
<p style="color: #f34250;">这里的模板id对应的是config.wx的template_id</p>
<p style="color: #f34250;">模板的话复制下面代码,换行的话回车换行,不然推送的消息就不会换行的</p>

```
{{date.DATA}}
城市:{{city.DATA}}
天气:{{weather.DATA}}
最低气温: {{min_temperature.DATA}}
最高气温: {{max_temperature.DATA}}
降雨概率:{{pop.DATA}}
今日建议:{{tips.DATA}}
今天是我们恋爱的第{{love_day.DATA}}天
距离小宝生日还有{{gfBirthDays.DATA}}天
距离我的生日还有{{mineBirthDays.DATA}}天
寄言: {{lizhi.DATA}}
```

![如图](./gitPic/template.jpg)

## 对接api实现
> 用的和原项目一样都是[天行](第三方用的都是https://www.tianapi.com/), 具体申请看=>[原项目的md](https://github.com/erwanjun/weixin_tuisong).我原项目的基础上用redis进行了缓存减少请求次数

## 最后
部署起来也挺简单的, 不会的话可以加我微信 ***June_QIU_0324***或者提issue
<p style="color: #f34250;">有服务器和域名的我也可以帮忙部署</p>
62 changes: 62 additions & 0 deletions app/controller/wx.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
'use strict';

const Controller = require('egg').Controller;

class HomeController extends Controller {
async verify() {
const { ctx, service } = this
const { signature, echostr, timestamp, nonce } = ctx.query
const verifyRes = await service.wx.verifySignature(timestamp, nonce, signature)
if (verifyRes) {
// 这里不要返回其他任何东西过去,only echostr is 好
ctx.body = echostr
} else {
ctx.fail()
}
}

// 获取access_token
async getAccessToken() {
const { ctx, service } = this
const accessToken = await service.wx.getAccessToken()
ctx.ok({
data: accessToken
})
}

// 监听微信订阅消息
async onListen() {
const { ctx, service } = this
const message = ctx.request.body
let reply
if(message.MsgType === 'event') {
reply = await service.wxNotify.handleEvent(message)
} else {
reply = await service.wxNotify.handleMsg(message)
}
if (reply) {
const result = await service.wxNotify.replyMsg(message, reply)
ctx.body = result
}
}

// 发送订阅通知
async sendNotify() {
const { service } = this
await service.wxNotify.snedNotify()
}

test() {
const { ctx, app } = this
console.log("==================================")
ctx.ok({
code: 200,
data: {
randomHexColor: randomHexColor(),
wxASToken: app.wxASToken || null
}
})
}
}

module.exports = HomeController;
12 changes: 12 additions & 0 deletions app/extend/context.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
'use strict';

module.exports = {
ok({code = 200, data = null, msg = '请求成功', status = 200} = {}) {
this.body = { data, msg, code };
this.status = status;
},
fail({code = 400, data = null, msg = '请求失败', status = 200} = {}) {
this.body = { data, msg, code };
this.status = status;
}
};
43 changes: 43 additions & 0 deletions app/middleware/onError.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@

// /**
// * @description Controller 和 Service 抛出异常处理
// * @author ruiyong-lee
// * @return {function} function
// */
'use strict';

module.exports = () => {
return async (ctx, next) => {
const method = ctx.request.method;
// 当请求方法为OPTIONS,通常为axios做验证请求,直接响应httpStatus204 no content即可
if (method === 'OPTIONS') {
ctx.status = 204;
return;
}
try {
await next()
} catch (err) {
// 所有异常都在app上触发一个error事件,框架会自动记录一条错误日志
ctx.app.emit('error', err, ctx)

const status = err.status || 500
//生产环境时500错误的详细信息不返回给客户端
const error = status === 500 && ctx.app.config.env === 'prod' ? '服务器错误' : err.message

// 从error对象上读出各个属性,设置到响应中
if (status === 422) {
return ctx.body = {
code: status,
msg: '参数检验失败',
data: err.errors
}
}
ctx.body = {
code: status,
msg: error,
data: null
}
ctx.status = status
}
}
}
29 changes: 29 additions & 0 deletions app/middleware/xml2js.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use strict';
const { parseXml } = require('../../utils/xml2js');

module.exports = () => {
return async (ctx, next) => {
if (ctx.method === 'POST' && ctx.is('text/xml') === 'text/xml') {
const promise = new Promise((resolve, reject) => {
let data = '';
ctx.req.on('data', chunk => {
data += chunk;
});
ctx.req.on('end', () => {
parseXml(data).then(result => {
resolve(result);
}).catch(err => {
console.log(err);
reject(err);
});
});
});
await promise.then(result => {
ctx.request.body = result;
}).catch(() => {
ctx.request.body = '';
});
}
await next();
};
};
16 changes: 16 additions & 0 deletions app/router.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
'use strict';

/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller } = app;
const xml2js = app.middleware.xml2js()

router.get('/test', controller.wx.test); // 测试用

router.get('/onWx', controller.wx.verify); // 验证微信消息
router.get('/getAccessToken', controller.wx.getAccessToken) // 获取getAccessToken
router.post('/onWx', xml2js, controller.wx.onListen) //
router.post('/sendNotify', controller.wx.sendNotify)
};
17 changes: 17 additions & 0 deletions app/schedule/sendTemplate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const Subscription = require('egg').Subscription;

class SendTemplate extends Subscription {
static get schedule() {
return {
cron: '0 0 8 1/1 * ?', // cron表达式生成器 http://cron.ciding.cc/
type: 'all', // 指定所有的 worker 都需要执行
};
}

async subscribe() {
this.service.wxNotify.snedNotify()
}
}

module.exports = SendTemplate;

Loading

0 comments on commit 1d5dc3e

Please sign in to comment.