├── .autod.conf.js ├── .eslintignore ├── .eslintrc ├── .github └── workflows │ └── nodejs.yml ├── .gitignore ├── .travis.yml ├── README.md ├── app ├── controller │ └── home.js ├── router.js ├── schedule │ └── update_cache.js └── service │ └── sendmsg.js ├── appveyor.yml ├── common └── CNDate.js ├── config ├── config.default.js └── plugin.js ├── jsconfig.json ├── package.json └── test └── app └── controller └── home.test.js /.autod.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | write: true, 5 | prefix: '^', 6 | plugin: 'autod-egg', 7 | test: [ 8 | 'test', 9 | 'benchmark', 10 | ], 11 | dep: [ 12 | 'egg', 13 | 'egg-scripts', 14 | ], 15 | devdep: [ 16 | 'egg-ci', 17 | 'egg-bin', 18 | 'egg-mock', 19 | 'autod', 20 | 'autod-egg', 21 | 'eslint', 22 | 'eslint-config-egg', 23 | ], 24 | exclude: [ 25 | './test/fixtures', 26 | './dist', 27 | ], 28 | }; 29 | 30 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | coverage 2 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint-config-egg" 3 | } 4 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Node.js CI 5 | 6 | on: 7 | push: 8 | branches: 9 | - main 10 | - master 11 | pull_request: 12 | branches: 13 | - main 14 | - master 15 | schedule: 16 | - cron: '0 2 * * *' 17 | 18 | jobs: 19 | build: 20 | runs-on: ${{ matrix.os }} 21 | 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | node-version: [10] 26 | os: [ubuntu-latest, windows-latest, macos-latest] 27 | 28 | steps: 29 | - name: Checkout Git Source 30 | uses: actions/checkout@v2 31 | 32 | - name: Use Node.js ${{ matrix.node-version }} 33 | uses: actions/setup-node@v1 34 | with: 35 | node-version: ${{ matrix.node-version }} 36 | 37 | - name: Install Dependencies 38 | run: npm i -g npminstall && npminstall 39 | 40 | - name: Continuous Integration 41 | run: npm run ci 42 | 43 | - name: Code Coverage 44 | uses: codecov/codecov-action@v1 45 | with: 46 | token: ${{ secrets.CODECOV_TOKEN }} 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | logs/ 2 | npm-debug.log 3 | yarn-error.log 4 | node_modules/ 5 | package-lock.json 6 | yarn.lock 7 | coverage/ 8 | .idea/ 9 | run/ 10 | .DS_Store 11 | *.sw* 12 | *.un~ 13 | typings/ 14 | .nyc_output/ 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | 2 | language: node_js 3 | node_js: 4 | - '10' 5 | before_install: 6 | - npm i npminstall -g 7 | install: 8 | - npminstall 9 | script: 10 | - npm run ci 11 | after_script: 12 | - npminstall codecov && codecov 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 环境准备 2 | 操作系统:支持 macOS,Linux,Windows 3 | 4 | 运行环境:建议选择 node LTS 版本,最低要求 8.x。 5 | ## 运行 6 | 7 | ### 本地开发 8 | 9 | ```bash 10 | $ npm i 11 | $ npm run dev 12 | $ open http://localhost:7001/ 13 | ``` 14 | 15 | ### 部署生产 16 | 17 | ```bash 18 | $ npm start 19 | $ npm stop 20 | ``` 21 | ### 定时任务和主动触发 22 | 23 | #### 定时任务 24 | 25 | [配置规则 请参考文档](https://eggjs.org/zh-cn/basics/schedule.html#定时方式) 26 | 27 | ``` 28 | └── app 29 | └── schedule 30 | └── update_cache.js 31 | 32 | { 33 | cron: '0 30 7 * * *', // 每天的7点30分0秒执行 34 | // interval: '1m', // 1 分钟间隔 35 | type: 'all', // 指定所有的 worker 都需要执行 36 | } 37 | ``` 38 | 39 | #### 主动发送 40 | 41 | ![image](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0ea318a4a6954c2ab76d58755be4b034~tplv-k3u1fbpfcp-watermark.image) 42 | 43 | 请求或浏览器访问 http://localhost:7001/send 44 | 45 | ## 配置文件说明 46 | 47 | ### 天气秘钥 48 | [注册地址]( https://www.tianqiapi.com/) 49 | ``` 50 | // 天气接口配置 51 | config.weather = { 52 | appid: '*******', 53 | appsecret: '*******', 54 | }; 55 | ``` 56 | ### 微信公众号 配置 57 | 因个人只能申请订阅号,而订阅号不支持发送模板消息,所以在此使用的测试的微信公众号,有微信号都可以申请,免注册,扫码登录 58 | 59 | 无需公众帐号、快速申请接口测试号 60 | 61 | 直接体验和测试公众平台所有高级接口 62 | 63 | [申请地址](https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login) 64 | 65 | ``` 66 | // 测试 微信公众号 67 | config.weChat = { 68 | appld: '**********', 69 | secret: '**********', 70 | // 用户的openid 71 | users: [ 72 | '**********************', 73 | '**********************', 74 | '**********************', 75 | '**********************' 76 | ], 77 | daily: '************', // 普通模板 78 | marry: ''************',', // 结婚纪念日模板 79 | wageDay: ''************',', // 工资日模板 80 | birthday: ''************',', // 生日模板 81 | }; 82 | ``` 83 | ### 特殊 时间点设置 84 | 下方是 birthday生日,因老家都是过阴历生日,不好处理,暂时写死的 85 | ``` 86 | // 时间 87 | config.time = { 88 | wageDay: 15, // 工资日 89 | love: '2017-06-09', // 相爱日期 90 | marry: '2021-11-27', // 结婚纪念日 91 | birthday: { 92 | 2021: '2021-04-17', 93 | 2022: '2022-04-06', 94 | 2023: '2023-04-25', 95 | 2024: '2024-04-14', 96 | 2025: '2025-04-03', 97 | 2026: '2026-04-22', 98 | }, // 每年生日 阳历 99 | birthYear: '1995-03-06', 100 | }; 101 | ``` 102 | ### 微信消息模板 103 | 104 | 这个需要在 上文提到的 微信公众平台测试账号 单独设置 105 | 106 | 以下是 我用的模板 107 | 108 | #### 正常模板 109 | 110 | ``` 111 | {{dateTime.DATA}} 112 | 今天是 我们相恋的第{{love.DATA}}天 113 | 距离上交工资还有{{wage.DATA}}天 114 | 距离你的生日还有{{birthday.DATA}}天 115 | 距离我们结婚纪念日还有{{marry.DATA}}天 116 | 今日天气 {{wea.DATA}} 117 | 当前温度 {{tem.DATA}}度 118 | 最高温度 {{tem1.DATA}}度 119 | 最低温度 {{tem2.DATA}}度 120 | 空气质量 {{airLevel.DATA}} 121 | 风向 {{win.DATA}} 122 | 每日一句 123 | {{message.DATA}} 124 | ``` 125 | #### 发工资模板 126 | 127 | 128 | ``` 129 | {{dateTime.DATA}} 130 | 老婆大人,今天要发工资了,预计晚九点前会准时上交,记得查收呦! 131 | ``` 132 | #### 生日 模板 133 | 134 | ``` 135 | {{dateTime.DATA}} 136 | 听说今天是你人生当中第 {{individual.DATA}} 个生日?天呐,我差点忘记!因为岁月没有在你脸上留下任何痕迹。尽管,日历告诉我:你又涨了一岁,但你还是那个天真可爱的小妖女,生日快乐! 137 | ``` 138 | #### 结婚纪念日 139 | * 结婚纪念日 140 | ``` 141 | {{dateTime.DATA}} 142 | 今天是结婚{{anniversary.DATA}}周年纪念日,在一起{{year.DATA}}年了,经历了风风雨雨,最终依然走在一起,很幸运,很幸福!我们的小家庭要一直幸福下去。 143 | ``` 144 | 145 | 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /app/controller/home.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // import { getMe } from '../../api/index.js' 3 | const Controller = require('egg').Controller; 4 | 5 | class HomeController extends Controller { 6 | async send() { 7 | const { ctx, app } = this; 8 | ctx.body = app.config; 9 | const result = await ctx.service.sendmsg.send(); 10 | ctx.logger.info('主动触发,发送模板消息 结果: %j', result); 11 | ctx.body = result; 12 | ctx.set('Content-Type', 'application/json'); 13 | } 14 | } 15 | 16 | module.exports = HomeController; 17 | -------------------------------------------------------------------------------- /app/router.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * @param {Egg.Application} app - egg application 5 | */ 6 | module.exports = app => { 7 | const { router, controller } = app; 8 | // 发送提醒 9 | router.get('/send', controller.home.send); 10 | }; 11 | -------------------------------------------------------------------------------- /app/schedule/update_cache.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const Subscription = require('egg').Subscription; 3 | 4 | class UpdateCache extends Subscription { 5 | // 通过 schedule 属性来设置定时任务的执行间隔等配置 6 | static get schedule() { 7 | return { 8 | cron: '0 30 7 * * *', // 每天的7点30分0秒执行 9 | // interval: '1m', // 1 分钟间隔 10 | type: 'all', // 指定所有的 worker 都需要执行 11 | }; 12 | } 13 | 14 | // subscribe 是真正定时任务执行时被运行的函数 15 | async subscribe() { 16 | const { ctx } = this; 17 | const result = await ctx.service.sendmsg.send(); 18 | // const result = cndate.solar2lunar(2021, 9, 22); 19 | ctx.logger.info('定时任务执行消息提醒 结果: %j', result); 20 | } 21 | } 22 | 23 | module.exports = UpdateCache; 24 | -------------------------------------------------------------------------------- /app/service/sendmsg.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const Service = require('egg').Service; 3 | const moment = require('moment'); 4 | class sendmsg extends Service { 5 | // 发送模板消息给媳妇儿 6 | async send() { 7 | const { ctx, app } = this; 8 | const token = await this.getToken(); 9 | const data = await this.getTemplateData(); 10 | ctx.logger.info('获取token 结果: %j', token); 11 | // 模板消息接口文档 12 | const users = app.config.weChat.users; 13 | const promise = users.map(id => { 14 | ctx.logger.info('--------------开始发送每日提醒-----------------------------------------------: %j', id); 15 | data.touser = id; 16 | return this.toWechart(token, data); 17 | }); 18 | const results = await Promise.all(promise); 19 | ctx.logger.info('--------------结束发送每日提醒->结果-----------------------------------------------: %j', results); 20 | return results; 21 | } 22 | // 通知微信接口 23 | async toWechart(token, data) { 24 | // 模板消息接口文档 25 | const url = 'https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=' + token; 26 | const result = await this.ctx.curl(url, { 27 | method: 'POST', 28 | data, 29 | dataType: 'json', 30 | headers: { 31 | 'Content-Type': 'application/json', 32 | }, 33 | }); 34 | return result; 35 | } 36 | // 获取token 37 | async getToken() { 38 | const { app } = this; 39 | const url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' + app.config.weChat.appld + '&secret=' + app.config.weChat.secret; 40 | const result = await this.ctx.curl(url, { 41 | method: 'get', 42 | dataType: 'json', 43 | }); 44 | if (result.status === 200) { 45 | return result.data.access_token; 46 | } 47 | } 48 | // 组装模板消息数据 49 | async getTemplateData() { 50 | const { app } = this; 51 | // 判断所需 模板 52 | // 发工资模板 getWageDay == 0 wageDay 53 | // 结婚纪念日模板 getMarryDay == 0 marry 54 | // 生日 模板 getbirthday == 0 birthday 55 | // 正常模板 daily 56 | 57 | const wageDay = this.getWageDay(); 58 | const marry = this.getMarryDay(); 59 | const birthday = this.getbirthday(); 60 | const data = { 61 | topcolor: '#FF0000', 62 | data: {}, 63 | }; 64 | // 发工资模板 65 | if (!wageDay) { 66 | data.template_id = app.config.weChat.wageDay; 67 | data.data = { 68 | dateTime: { 69 | value: this.getDatetime(), 70 | color: '#cc33cc', 71 | }, 72 | }; 73 | } else if (!marry) { 74 | // 结婚纪念日模板 75 | data.template_id = app.config.weChat.marry; 76 | data.data = { 77 | dateTime: { 78 | value: this.getDatetime(), 79 | color: '#cc33cc', 80 | }, 81 | anniversary: { 82 | value: this.getMarryYear(), 83 | color: '#ff3399', 84 | }, 85 | year: { 86 | value: this.getLoveYear(), 87 | color: '#ff3399', 88 | }, 89 | }; 90 | } else if (!birthday) { 91 | // 生日模板 92 | data.template_id = app.config.weChat.birthday; 93 | data.data = { 94 | dateTime: { 95 | value: this.getDatetime(), 96 | color: '#cc33cc', 97 | }, 98 | individual: { 99 | value: this.getBirthYear(), 100 | color: '#ff3399', 101 | }, 102 | }; 103 | } else { 104 | // 正常模板 105 | data.template_id = app.config.weChat.daily; 106 | // 获取天气 107 | const getWeather = await this.getWeather(); 108 | // 获取每日一句 109 | const message = await this.getOneSentence(); 110 | data.data = { 111 | dateTime: { 112 | value: this.getDatetime(), 113 | color: '#cc33cc', 114 | }, 115 | love: { 116 | value: this.getLoveDay(), 117 | color: '#ff3399', 118 | }, 119 | wage: { 120 | value: wageDay, 121 | color: '#66ff00', 122 | }, 123 | birthday: { 124 | value: birthday, 125 | color: '#ff0033', 126 | }, 127 | marry: { 128 | value: marry, 129 | color: '#ff0033', 130 | }, 131 | wea: { 132 | value: getWeather.wea, 133 | color: '#33ff33', 134 | }, 135 | tem: { 136 | value: getWeather.tem, 137 | color: '#0066ff', 138 | }, 139 | airLevel: { 140 | value: getWeather.air_level, 141 | color: '#ff0033', 142 | }, 143 | tem1: { 144 | value: getWeather.tem1, 145 | color: '#ff0000', 146 | }, 147 | tem2: { 148 | value: getWeather.tem2, 149 | color: '#33ff33', 150 | }, 151 | win: { 152 | value: getWeather.win, 153 | color: '#3399ff', 154 | }, 155 | message: { 156 | value: message, 157 | color: '#8C8C8C', 158 | }, 159 | }; 160 | } 161 | return data; 162 | } 163 | // 获取天气 164 | async getWeather(city = '深泽') { 165 | const { app } = this; 166 | const url = 'https://www.tianqiapi.com/api?unescape=1&version=v6&appid=' + app.config.weather.appid + '&appsecret=' + app.config.weather.appsecret + '&city=' + city; 167 | const result = await this.ctx.curl(url, { 168 | method: 'get', 169 | dataType: 'json', 170 | }); 171 | console.log(result.status); 172 | // "wea": "多云", 173 | // "tem": "27", 实时温度 174 | // "tem1": "27", 高温 175 | // "tem2": "17", 低温 176 | // "win": "西风", 177 | // "air_level": "优", 178 | if (result && result.status === 200) { 179 | return result.data; 180 | } 181 | return { 182 | city, 183 | wea: '未知', 184 | tem: '未知', 185 | tem1: '未知', 186 | tem2: '未知', 187 | win: '未知', 188 | win_speed: '未知', 189 | air_level: '未知', 190 | }; 191 | } 192 | // 获取 下次发工资 还有多少天 193 | getWageDay() { 194 | const { app } = this; 195 | const wage = app.config.time.wageDay; 196 | // 获取日期 day 197 | // 如果在 wage号之前或等于wage时 那么就用 wage-day 198 | // 如果在 wage号之后 那么就用 wage +(当前月总天数-day) 199 | // 当日 日期day 200 | const day = moment().date(); 201 | // 当月总天数 202 | const nowDayTotal = moment().daysInMonth(); 203 | // // 下个月总天数 204 | // const nextDayTotal = moment().month(moment().month() + 1).daysInMonth(); 205 | let resultDay = 0; 206 | if (day <= wage) { 207 | resultDay = wage - day; 208 | } else { 209 | resultDay = wage + (nowDayTotal - day); 210 | } 211 | return resultDay; 212 | } 213 | // 获取距离 下次结婚纪念日还有多少天 214 | getMarryDay() { 215 | const { app } = this; 216 | const marry = app.config.time.marry; 217 | // 获取当前时间戳 218 | const now = moment(moment().format('YYYY-MM-DD')).valueOf(); 219 | // 获取纪念日 月-日 220 | const mmdd = moment(marry).format('-MM-DD'); 221 | // 获取当年 222 | const y = moment().year(); 223 | // 获取今年结婚纪念日时间戳 224 | const nowTimeNumber = moment(y + mmdd).valueOf(); 225 | // 判断 今天的结婚纪念日 有没有过,如果已经过去(now>nowTimeNumber),resultMarry日期为明年的结婚纪念日 226 | // 如果还没到,则 结束日期为今年的结婚纪念日 227 | let resultMarry = nowTimeNumber; 228 | if (now > nowTimeNumber) { 229 | // 获取明年纪念日 230 | resultMarry = moment((y + 1) + mmdd).valueOf(); 231 | } 232 | return moment(moment(resultMarry).format()).diff(moment(now).format(), 'day'); 233 | } 234 | // 获取 距离 下次生日还有多少天 235 | getbirthday() { 236 | const { app } = this; 237 | const birthday = app.config.time.birthday[moment().year()]; 238 | // 获取当前时间戳 239 | const now = moment(moment().format('YYYY-MM-DD')).valueOf(); 240 | // 获取纪念日 月-日 241 | const mmdd = moment(birthday).format('-MM-DD'); 242 | // 获取当年 243 | const y = moment().year(); 244 | // 获取今年生日 时间戳 245 | const nowTimeNumber = moment(y + mmdd).valueOf(); 246 | // 判断 生日 有没有过,如果已经过去(now>nowTimeNumber),resultBirthday日期为明年的生日 日期 247 | // 如果还没到,则 结束日期为今年的目标日期 248 | let resultBirthday = nowTimeNumber; 249 | if (now > nowTimeNumber) { 250 | // 获取明年目标日期 251 | resultBirthday = moment(app.config.time.birthday[y + 1]).valueOf(); 252 | } 253 | return moment(moment(resultBirthday).format()).diff(moment(now).format(), 'day'); 254 | } 255 | // 获取 相恋天数 256 | getLoveDay() { 257 | const { app } = this; 258 | const loveDay = app.config.time.love; 259 | return moment(moment().format('YYYY-MM-DD')).diff(loveDay, 'day'); 260 | } 261 | // 获取 相恋几年了 262 | getLoveYear() { 263 | const { app } = this; 264 | const loveDay = app.config.time.love; 265 | return moment().year() - moment(loveDay).year(); 266 | } 267 | // 获取是第几个生日 268 | getBirthYear() { 269 | const { app } = this; 270 | const birthYear = app.config.time.birthYear; 271 | return moment().year() - birthYear; 272 | } 273 | // 获取是第几个结婚纪念日 274 | getMarryYear() { 275 | const { app } = this; 276 | const marry = app.config.time.marry; 277 | return moment().year() - moment(marry).year(); 278 | } 279 | // 获取 每日一句 280 | async getOneSentence() { 281 | const url = 'https://v1.hitokoto.cn/'; 282 | const result = await this.ctx.curl(url, { 283 | method: 'get', 284 | dataType: 'json', 285 | }); 286 | if (result && result.status === 200) { 287 | return result.data.hitokoto; 288 | } 289 | return '今日只有我爱你!'; 290 | } 291 | // 获取时间日期 292 | getDatetime() { 293 | console.log('moment().weekday()', moment().weekday()); 294 | const week = { 295 | 1: '星期一', 296 | 2: '星期二', 297 | 3: '星期三', 298 | 4: '星期四', 299 | 5: '星期五', 300 | 6: '星期六', 301 | 0: '星期日', 302 | }; 303 | return moment().format('YYYY年MM月DD日 ') + week[moment().weekday()]; 304 | } 305 | 306 | } 307 | module.exports = sendmsg; 308 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | matrix: 3 | - nodejs_version: '10' 4 | 5 | install: 6 | - ps: Install-Product node $env:nodejs_version 7 | - npm i npminstall && node_modules\.bin\npminstall 8 | 9 | test_script: 10 | - node --version 11 | - npm --version 12 | - npm run test 13 | 14 | build: off 15 | -------------------------------------------------------------------------------- /common/CNDate.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // /** 3 | // * @1900-2100区间内的公历、农历互转 4 | // * @charset UTF-8 5 | // * @Author Jea杨(JJonline@JJonline.Cn) 6 | // * @Time 2014-7-21 7 | // * @Time 2016-8-13 Fixed 2033hex、Attribution Annals 8 | // * @Time 2016-9-25 Fixed lunar LeapMonth Param Bug 9 | // * @Time 2017-7-24 Fixed use getTerm Func Param Error.use solar year,NOT lunar year 10 | // * @Version 1.0.3 11 | // * @公历转农历:calendar.solar2lunar(1987,11,01); //[you can ignore params of prefix 0] 12 | // * @农历转公历:calendar.lunar2solar(1987,09,10); //[you can ignore params of prefix 0] 13 | // */ 14 | // const calendar = { 15 | 16 | // /** 17 | // * 农历1900-2100的润大小信息表 18 | // * @Array Of Property 19 | // * @return Hex 20 | // */ 21 | // lunarInfo: [ 0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, // 1900-1909 22 | // 0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, // 1910-1919 23 | // 0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, // 1920-1929 24 | // 0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, // 1930-1939 25 | // 0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, // 1940-1949 26 | // 0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, // 1950-1959 27 | // 0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, // 1960-1969 28 | // 0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6, // 1970-1979 29 | // 0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, // 1980-1989 30 | // 0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x055c0, 0x0ab60, 0x096d5, 0x092e0, // 1990-1999 31 | // 0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, // 2000-2009 32 | // 0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, // 2010-2019 33 | // 0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, // 2020-2029 34 | // 0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, // 2030-2039 35 | // 0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, // 2040-2049 36 | // /** Add By JJonline@JJonline.Cn**/ 37 | // 0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, // 2050-2059 38 | // 0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, // 2060-2069 39 | // 0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, // 2070-2079 40 | // 0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, // 2080-2089 41 | // 0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, // 2090-2099 42 | // 0x0d520 ], // 2100 43 | 44 | // /** 45 | // * 公历每个月份的天数普通表 46 | // * @Array Of Property 47 | // * @return Number 48 | // */ 49 | // solarMonth: [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ], 50 | 51 | // /** 52 | // * 天干地支之天干速查表 53 | // * @Array Of Property trans["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"] 54 | // * @return Cn string 55 | // */ 56 | // Gan: [ '\u7532', '\u4e59', '\u4e19', '\u4e01', '\u620a', '\u5df1', '\u5e9a', '\u8f9b', '\u58ec', '\u7678' ], 57 | 58 | // /** 59 | // * 天干地支之地支速查表 60 | // * @Array Of Property 61 | // * @trans["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"] 62 | // * @return Cn string 63 | // */ 64 | // Zhi: [ '\u5b50', '\u4e11', '\u5bc5', '\u536f', '\u8fb0', '\u5df3', '\u5348', '\u672a', '\u7533', '\u9149', '\u620c', '\u4ea5' ], 65 | 66 | // /** 67 | // * 天干地支之地支速查表<=>生肖 68 | // * @Array Of Property 69 | // * @trans["鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"] 70 | // * @return Cn string 71 | // */ 72 | // Animals: [ '\u9f20', '\u725b', '\u864e', '\u5154', '\u9f99', '\u86c7', '\u9a6c', '\u7f8a', '\u7334', '\u9e21', '\u72d7', '\u732a' ], 73 | 74 | // /** 75 | // * 24节气速查表 76 | // * @Array Of Property 77 | // * @trans["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"] 78 | // * @return Cn string 79 | // */ 80 | // solarTerm: [ '\u5c0f\u5bd2', '\u5927\u5bd2', '\u7acb\u6625', '\u96e8\u6c34', '\u60ca\u86f0', '\u6625\u5206', '\u6e05\u660e', '\u8c37\u96e8', '\u7acb\u590f', '\u5c0f\u6ee1', '\u8292\u79cd', '\u590f\u81f3', '\u5c0f\u6691', '\u5927\u6691', '\u7acb\u79cb', '\u5904\u6691', '\u767d\u9732', '\u79cb\u5206', '\u5bd2\u9732', '\u971c\u964d', '\u7acb\u51ac', '\u5c0f\u96ea', '\u5927\u96ea', '\u51ac\u81f3' ], 81 | 82 | // /** 83 | // * 1900-2100各年的24节气日期速查表 84 | // * @Array Of Property 85 | // * @return 0x string For splice 86 | // */ 87 | // sTermInfo: [ '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', 88 | // '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', 89 | // '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', 90 | // '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', 91 | // 'b027097bd097c36b0b6fc9274c91aa', '9778397bd19801ec9210c965cc920e', '97b6b97bd19801ec95f8c965cc920f', 92 | // '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd197c36c9210c9274c91aa', 93 | // '97b6b97bd19801ec95f8c965cc920e', '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', 94 | // '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec95f8c965cc920e', '97bcf97c3598082c95f8e1cfcc920f', 95 | // '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', 96 | // '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', 97 | // '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', 98 | // '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', 99 | // '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', 100 | // '97bcf97c359801ec95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', 101 | // '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd097bd07f595b0b6fc920fb0722', 102 | // '9778397bd097c36b0b6fc9210c8dc2', '9778397bd19801ec9210c9274c920e', '97b6b97bd19801ec95f8c965cc920f', 103 | // '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e', 104 | // '97b6b97bd19801ec95f8c965cc920f', '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', 105 | // '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bd07f1487f595b0b0bc920fb0722', 106 | // '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', 107 | // '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', 108 | // '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', 109 | // '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f531b0b0bb0b6fb0722', 110 | // '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', 111 | // '97bcf7f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', 112 | // '97b6b97bd19801ec9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', 113 | // '9778397bd097c36b0b6fc9210c91aa', '97b6b97bd197c36c9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', 114 | // '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e', 115 | // '97b6b7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', 116 | // '9778397bd097c36b0b70c9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722', 117 | // '7f0e397bd097c35b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', 118 | // '7f0e27f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', 119 | // '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', 120 | // '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', 121 | // '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', 122 | // '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9274c91aa', 123 | // '97b6b7f0e47f531b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', 124 | // '9778397bd097c36b0b6fc9210c91aa', '97b6b7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', 125 | // '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '977837f0e37f149b0723b0787b0721', 126 | // '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c35b0b6fc9210c8dc2', 127 | // '977837f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722', 128 | // '7f0e397bd097c35b0b6fc9210c8dc2', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', 129 | // '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '977837f0e37f14998082b0787b06bd', 130 | // '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', 131 | // '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', 132 | // '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', 133 | // '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', 134 | // '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', 135 | // '977837f0e37f14998082b0723b06bd', '7f07e7f0e37f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', 136 | // '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b0721', 137 | // '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f595b0b0bb0b6fb0722', '7f0e37f0e37f14898082b0723b02d5', 138 | // '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f531b0b0bb0b6fb0722', 139 | // '7f0e37f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', 140 | // '7f0e37f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd', 141 | // '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', 142 | // '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', 143 | // '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f149b0723b0787b0721', 144 | // '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0723b06bd', 145 | // '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', '7f0e37f0e366aa89801eb072297c35', 146 | // '7ec967f0e37f14998082b0723b06bd', '7f07e7f0e37f14998083b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', 147 | // '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14898082b0723b02d5', '7f07e7f0e37f14998082b0787b0721', 148 | // '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66aa89801e9808297c35', '665f67f0e37f14898082b0723b02d5', 149 | // '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66a449801e9808297c35', 150 | // '665f67f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', 151 | // '7f0e36665b66a449801e9808297c35', '665f67f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd', 152 | // '7f07e7f0e47f531b0723b0b6fb0721', '7f0e26665b66a449801e9808297c35', '665f67f0e37f1489801eb072297c35', 153 | // '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722' ], 154 | 155 | // /** 156 | // * 数字转中文速查表 157 | // * @Array Of Property 158 | // * @trans ['日','一','二','三','四','五','六','七','八','九','十'] 159 | // * @return Cn string 160 | // */ 161 | // nStr1: [ '\u65e5', '\u4e00', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341' ], 162 | 163 | // /** 164 | // * 日期转农历称呼速查表 165 | // * @Array Of Property 166 | // * @trans ['初','十','廿','卅'] 167 | // * @return Cn string 168 | // */ 169 | // nStr2: [ '\u521d', '\u5341', '\u5eff', '\u5345' ], 170 | 171 | // /** 172 | // * 月份转农历称呼速查表 173 | // * @Array Of Property 174 | // * @trans ['正','一','二','三','四','五','六','七','八','九','十','冬','腊'] 175 | // * @return Cn string 176 | // */ 177 | // nStr3: [ '\u6b63', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341', '\u51ac', '\u814a' ], 178 | 179 | // /** 180 | // * 返回农历y年一整年的总天数 181 | // * @param lunar Year 182 | // * @return Number 183 | // * @eg:let count = calendar.lYearDays(1987) ;//count=387 184 | // */ 185 | // lYearDays(y) { 186 | // let i, 187 | // sum = 348; 188 | // for (i = 0x8000; i > 0x8; i >>= 1) { sum += (calendar.lunarInfo[y - 1900] & i) ? 1 : 0; } 189 | // return (sum + calendar.leapDays(y)); 190 | // }, 191 | 192 | // /** 193 | // * 返回农历y年闰月是哪个月;若y年没有闰月 则返回0 194 | // * @param lunar Year 195 | // * @return Number (0-12) 196 | // * @eg:let leapMonth = calendar.leapMonth(1987) ;//leapMonth=6 197 | // */ 198 | // leapMonth(y) { // 闰字编码 \u95f0 199 | // return (calendar.lunarInfo[y - 1900] & 0xf); 200 | // }, 201 | 202 | // /** 203 | // * 返回农历y年闰月的天数 若该年没有闰月则返回0 204 | // * @param lunar Year 205 | // * @return Number (0、29、30) 206 | // * @eg:let leapMonthDay = calendar.leapDays(1987) ;//leapMonthDay=29 207 | // */ 208 | // leapDays(y) { 209 | // if (calendar.leapMonth(y)) { 210 | // return ((calendar.lunarInfo[y - 1900] & 0x10000) ? 30 : 29); 211 | // } 212 | // return (0); 213 | // }, 214 | 215 | // /** 216 | // * 返回农历y年m月(非闰月)的总天数,计算m为闰月时的天数请使用leapDays方法 217 | // * @param lunar Year 218 | // * @return Number (-1、29、30) 219 | // * @eg:let MonthDay = calendar.monthDays(1987,9) ;//MonthDay=29 220 | // */ 221 | // monthDays(y, m) { 222 | // if (m > 12 || m < 1) { return -1; }// 月份参数从1至12,参数错误返回-1 223 | // return ((calendar.lunarInfo[y - 1900] & (0x10000 >> m)) ? 30 : 29); 224 | // }, 225 | 226 | // /** 227 | // * 返回公历(!)y年m月的天数 228 | // * @param solar Year 229 | // * @return Number (-1、28、29、30、31) 230 | // * @eg:let solarMonthDay = calendar.leapDays(1987) ;//solarMonthDay=30 231 | // */ 232 | // solarDays(y, m) { 233 | // if (m > 12 || m < 1) { return -1; } // 若参数错误 返回-1 234 | // const ms = m - 1; 235 | // if (ms == 1) { // 2月份的闰平规律测算后确认返回28或29 236 | // return (((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0)) ? 29 : 28); 237 | // } 238 | // return (calendar.solarMonth[ms]); 239 | 240 | // }, 241 | 242 | // /** 243 | // * 农历年份转换为干支纪年 244 | // * @param lYear 农历年的年份数 245 | // * @return Cn string 246 | // */ 247 | // toGanZhiYear(lYear) { 248 | // let ganKey = (lYear - 3) % 10; 249 | // let zhiKey = (lYear - 3) % 12; 250 | // if (ganKey == 0) ganKey = 10;// 如果余数为0则为最后一个天干 251 | // if (zhiKey == 0) zhiKey = 12;// 如果余数为0则为最后一个地支 252 | // return calendar.Gan[ganKey - 1] + calendar.Zhi[zhiKey - 1]; 253 | 254 | // }, 255 | 256 | // /** 257 | // * 公历月、日判断所属星座 258 | // * @param cMonth [description] 259 | // * @param cDay [description] 260 | // * @return Cn string 261 | // */ 262 | // toAstro(cMonth, cDay) { 263 | // const s = '\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e4\u5929\u874e\u5c04\u624b\u9b54\u7faf'; 264 | // const arr = [ 20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22 ]; 265 | // return s.substr(cMonth * 2 - (cDay < arr[cMonth - 1] ? 2 : 0), 2) + '\u5ea7';// 座 266 | // }, 267 | 268 | // /** 269 | // * 传入offset偏移量返回干支 270 | // * @param offset 相对甲子的偏移量 271 | // * @return Cn string 272 | // */ 273 | // toGanZhi(offset) { 274 | // return calendar.Gan[offset % 10] + calendar.Zhi[offset % 12]; 275 | // }, 276 | 277 | // /** 278 | // * 传入公历(!)y年获得该年第n个节气的公历日期 279 | // * @param y公历年(1900-2100);n二十四节气中的第几个节气(1~24);从n=1(小寒)算起 280 | // * @return day Number 281 | // * @eg:let _24 = calendar.getTerm(1987,3) ;//_24=4;意即1987年2月4日立春 282 | // */ 283 | // getTerm(y, n) { 284 | // if (y < 1900 || y > 2100) { return -1; } 285 | // if (n < 1 || n > 24) { return -1; } 286 | // const _table = calendar.sTermInfo[y - 1900]; 287 | // const _info = [ 288 | // parseInt('0x' + _table.substr(0, 5)).toString(), 289 | // parseInt('0x' + _table.substr(5, 5)).toString(), 290 | // parseInt('0x' + _table.substr(10, 5)).toString(), 291 | // parseInt('0x' + _table.substr(15, 5)).toString(), 292 | // parseInt('0x' + _table.substr(20, 5)).toString(), 293 | // parseInt('0x' + _table.substr(25, 5)).toString(), 294 | // ]; 295 | // const _calday = [ 296 | // _info[0].substr(0, 1), 297 | // _info[0].substr(1, 2), 298 | // _info[0].substr(3, 1), 299 | // _info[0].substr(4, 2), 300 | 301 | // _info[1].substr(0, 1), 302 | // _info[1].substr(1, 2), 303 | // _info[1].substr(3, 1), 304 | // _info[1].substr(4, 2), 305 | 306 | // _info[2].substr(0, 1), 307 | // _info[2].substr(1, 2), 308 | // _info[2].substr(3, 1), 309 | // _info[2].substr(4, 2), 310 | 311 | // _info[3].substr(0, 1), 312 | // _info[3].substr(1, 2), 313 | // _info[3].substr(3, 1), 314 | // _info[3].substr(4, 2), 315 | 316 | // _info[4].substr(0, 1), 317 | // _info[4].substr(1, 2), 318 | // _info[4].substr(3, 1), 319 | // _info[4].substr(4, 2), 320 | 321 | // _info[5].substr(0, 1), 322 | // _info[5].substr(1, 2), 323 | // _info[5].substr(3, 1), 324 | // _info[5].substr(4, 2), 325 | // ]; 326 | // return parseInt(_calday[n - 1]); 327 | // }, 328 | 329 | // /** 330 | // * 传入农历数字月份返回汉语通俗表示法 331 | // * @param lunar month 332 | // * @return Cn string 333 | // * @eg:let cnMonth = calendar.toChinaMonth(12) ;//cnMonth='腊月' 334 | // */ 335 | // toChinaMonth(m) { // 月 => \u6708 336 | // if (m > 12 || m < 1) { return -1; } // 若参数错误 返回-1 337 | // let s = calendar.nStr3[m - 1]; 338 | // s += '\u6708';// 加上月字 339 | // return s; 340 | // }, 341 | 342 | // /** 343 | // * 传入农历日期数字返回汉字表示法 344 | // * @param lunar day 345 | // * @return Cn string 346 | // * @eg:let cnDay = calendar.toChinaDay(21) ;//cnMonth='廿一' 347 | // */ 348 | // toChinaDay(d) { // 日 => \u65e5 349 | // let s; 350 | // switch (d) { 351 | // case 10: 352 | // s = '\u521d\u5341'; break; 353 | // case 20: 354 | // s = '\u4e8c\u5341'; break; 355 | // break; 356 | // case 30: 357 | // s = '\u4e09\u5341'; break; 358 | // break; 359 | // default: 360 | // s = calendar.nStr2[Math.floor(d / 10)]; 361 | // s += calendar.nStr1[d % 10]; 362 | // } 363 | // return (s); 364 | // }, 365 | 366 | // /** 367 | // * 年份转生肖[!仅能大致转换] => 精确划分生肖分界线是“立春” 368 | // * @param y year 369 | // * @return Cn string 370 | // * @eg:let animal = calendar.getAnimal(1987) ;//animal='兔' 371 | // */ 372 | // getAnimal(y) { 373 | // return calendar.Animals[(y - 4) % 12]; 374 | // }, 375 | 376 | // /** 377 | // * 传入阳历年月日获得详细的公历、农历object信息 <=>JSON 378 | // * @param y solar year 379 | // * @param m solar month 380 | // * @param d solar day 381 | // * @return JSON object 382 | // * @eg:console.log(calendar.solar2lunar(1987,11,01)); 383 | // */ 384 | // solar2lunar(y, m, d) { // 参数区间1900.1.31~2100.12.31 385 | // // 年份限定、上限 386 | // if (y < 1900 || y > 2100) { 387 | // return -1;// undefined转换为数字变为NaN 388 | // } 389 | // // 公历传参最下限 390 | // if (y == 1900 && m == 1 && d < 31) { 391 | // return -1; 392 | // } 393 | // // 未传参 获得当天 394 | // if (!y) { 395 | // let objDate = new Date(); 396 | // } else { 397 | // let objDate = new Date(y, parseInt(m) - 1, d); 398 | // } 399 | // let i, 400 | // leap = 0, 401 | // temp = 0; 402 | // // 修正ymd参数 403 | // let y = objDate.getFullYear(), 404 | // m = objDate.getMonth() + 1, 405 | // d = objDate.getDate(); 406 | // let offset = (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) - Date.UTC(1900, 0, 31)) / 86400000; 407 | // for (i = 1900; i < 2101 && offset > 0; i++) { 408 | // temp = calendar.lYearDays(i); 409 | // offset -= temp; 410 | // } 411 | // if (offset < 0) { 412 | // offset += temp; i--; 413 | // } 414 | 415 | // // 是否今天 416 | // let isTodayObj = new Date(), 417 | // isToday = false; 418 | // if (isTodayObj.getFullYear() == y && isTodayObj.getMonth() + 1 == m && isTodayObj.getDate() == d) { 419 | // isToday = true; 420 | // } 421 | // // 星期几 422 | // let nWeek = objDate.getDay(), 423 | // cWeek = calendar.nStr1[nWeek]; 424 | // // 数字表示周几顺应天朝周一开始的惯例 425 | // if (nWeek == 0) { 426 | // nWeek = 7; 427 | // } 428 | // // 农历年 429 | // const year = i; 430 | // let leap = calendar.leapMonth(i); // 闰哪个月 431 | // let isLeap = false; 432 | 433 | // // 效验闰月 434 | // for (i = 1; i < 13 && offset > 0; i++) { 435 | // // 闰月 436 | // if (leap > 0 && i == (leap + 1) && isLeap == false) { 437 | // --i; 438 | // isLeap = true; temp = calendar.leapDays(year); // 计算农历闰月天数 439 | // } else { 440 | // temp = calendar.monthDays(year, i);// 计算农历普通月天数 441 | // } 442 | // // 解除闰月 443 | // if (isLeap == true && i == (leap + 1)) { isLeap = false; } 444 | // offset -= temp; 445 | // } 446 | // // 闰月导致数组下标重叠取反 447 | // if (offset == 0 && leap > 0 && i == leap + 1) { 448 | // if (isLeap) { 449 | // isLeap = false; 450 | // } else { 451 | // isLeap = true; --i; 452 | // } 453 | // } 454 | // if (offset < 0) { 455 | // offset += temp; --i; 456 | // } 457 | // // 农历月 458 | // const month = i; 459 | // // 农历日 460 | // const day = offset + 1; 461 | // // 天干地支处理 462 | // const sm = m - 1; 463 | // const gzY = calendar.toGanZhiYear(year); 464 | 465 | // // 当月的两个节气 466 | // // bugfix-2017-7-24 11:03:38 use lunar Year Param `y` Not `year` 467 | // const firstNode = calendar.getTerm(y, (m * 2 - 1));// 返回当月「节」为几日开始 468 | // const secondNode = calendar.getTerm(y, (m * 2));// 返回当月「节」为几日开始 469 | 470 | // // 依据12节气修正干支月 471 | // let gzM = calendar.toGanZhi((y - 1900) * 12 + m + 11); 472 | // if (d >= firstNode) { 473 | // gzM = calendar.toGanZhi((y - 1900) * 12 + m + 12); 474 | // } 475 | 476 | // // 传入的日期的节气与否 477 | // let isTerm = false; 478 | // let Term = null; 479 | // if (firstNode == d) { 480 | // isTerm = true; 481 | // Term = calendar.solarTerm[m * 2 - 2]; 482 | // } 483 | // if (secondNode == d) { 484 | // isTerm = true; 485 | // Term = calendar.solarTerm[m * 2 - 1]; 486 | // } 487 | // // 日柱 当月一日与 1900/1/1 相差天数 488 | // const dayCyclical = Date.UTC(y, sm, 1, 0, 0, 0, 0) / 86400000 + 25567 + 10; 489 | // const gzD = calendar.toGanZhi(dayCyclical + d - 1); 490 | // // 该日期所属的星座 491 | // const astro = calendar.toAstro(m, d); 492 | 493 | // return { lYear: year, lMonth: month, lDay: day, Animal: calendar.getAnimal(year), IMonthCn: (isLeap ? '\u95f0' : '') + calendar.toChinaMonth(month), IDayCn: calendar.toChinaDay(day), cYear: y, cMonth: m, cDay: d, gzYear: gzY, gzMonth: gzM, gzDay: gzD, isToday, isLeap, nWeek, ncWeek: '\u661f\u671f' + cWeek, isTerm, Term, astro }; 494 | // }, 495 | 496 | // /** 497 | // * 传入农历年月日以及传入的月份是否闰月获得详细的公历、农历object信息 <=>JSON 498 | // * @param y lunar year 499 | // * @param m lunar month 500 | // * @param d lunar day 501 | // * @param isLeapMonth lunar month is leap or not.[如果是农历闰月第四个参数赋值true即可] 502 | // * @return JSON object 503 | // * @eg:console.log(calendar.lunar2solar(1987,9,10)); 504 | // */ 505 | // lunar2solar(y, m, d, isLeapMonth) { // 参数区间1900.1.31~2100.12.1 506 | // let isLeapMonth = !!isLeapMonth; 507 | // const leapOffset = 0; 508 | // const leapMonth = calendar.leapMonth(y); 509 | // const leapDay = calendar.leapDays(y); 510 | // if (isLeapMonth && (leapMonth != m)) { return -1; }// 传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同 511 | // if (y == 2100 && m == 12 && d > 1 || y == 1900 && m == 1 && d < 31) { return -1; }// 超出了最大极限值 512 | // const day = calendar.monthDays(y, m); 513 | // let _day = day; 514 | // // bugFix 2016-9-25 515 | // // if month is leap, _day use leapDays method 516 | // if (isLeapMonth) { 517 | // _day = calendar.leapDays(y, m); 518 | // } 519 | // if (y < 1900 || y > 2100 || d > _day) { return -1; }// 参数合法性效验 520 | 521 | // // 计算农历的时间差 522 | // let offset = 0; 523 | // for (let i = 1900; i < y; i++) { 524 | // offset += calendar.lYearDays(i); 525 | // } 526 | // let leap = 0, 527 | // isAdd = false; 528 | // for (let i = 1; i < m; i++) { 529 | // leap = calendar.leapMonth(y); 530 | // if (!isAdd) { // 处理闰月 531 | // if (leap <= i && leap > 0) { 532 | // offset += calendar.leapDays(y); isAdd = true; 533 | // } 534 | // } 535 | // offset += calendar.monthDays(y, i); 536 | // } 537 | // // 转换闰月农历 需补充该年闰月的前一个月的时差 538 | // if (isLeapMonth) { offset += day; } 539 | // // 1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点) 540 | // const stmap = Date.UTC(1900, 1, 30, 0, 0, 0); 541 | // const calObj = new Date((offset + d - 31) * 86400000 + stmap); 542 | // const cY = calObj.getUTCFullYear(); 543 | // const cM = calObj.getUTCMonth() + 1; 544 | // const cD = calObj.getUTCDate(); 545 | 546 | // return calendar.solar2lunar(cY, cM, cD); 547 | // }, 548 | // }; 549 | const calendar = { 550 | solar2lunar(y, m, d) { 551 | return y + m + d; 552 | }, 553 | }; 554 | module.exports = calendar; 555 | -------------------------------------------------------------------------------- /config/config.default.js: -------------------------------------------------------------------------------- 1 | /* eslint valid-jsdoc: "off" */ 2 | 3 | 'use strict'; 4 | 5 | /** 6 | * @param {Egg.EggAppInfo} appInfo app info 7 | */ 8 | module.exports = appInfo => { 9 | /** 10 | * built-in config 11 | * @type {Egg.EggAppConfig} 12 | **/ 13 | const config = exports = {}; 14 | 15 | // use for cookie sign key, should change to your own and keep security 16 | config.keys = appInfo.name + '_1632111171422_6113'; 17 | 18 | // add your middleware config here 19 | config.middleware = []; 20 | // 天气接口配置 21 | config.weather = { 22 | appid: '*****************', 23 | appsecret: '************', 24 | }; 25 | // 测试 微信公众号 26 | config.weChat = { 27 | appld: '*****', 28 | secret: '*****', 29 | // 用户的openid 30 | users: [ 31 | '******', 32 | '******', 33 | '******', 34 | ], 35 | daily: '********************', // 普通模板 36 | marry: '********************', // 结婚纪念日模板 37 | wageDay: '*****************', // 工资日模板 38 | birthday: '**************************', // 生日模板 39 | }; 40 | 41 | // 时间 42 | config.time = { 43 | wageDay: 15, // 工资日 44 | love: '2017-06-09', // 相爱日期 45 | marry: '2020-11-27', // 结婚纪念日 46 | // 生日配置 47 | // 老家过阴历生日,这里暂时写死 48 | birthday: { 49 | 2021: '2021-04-21', 50 | 2022: '2022-01-06', 51 | 2023: '2023-02-25', 52 | 2024: '2024-03-14', 53 | 2025: '2025-04-03', 54 | 2026: '2026-05-22', 55 | }, // 每年生日 阳历 56 | birthYear: 1995, 57 | }; 58 | // add your user config here 59 | const userConfig = { 60 | // myAppName: 'egg', 61 | }; 62 | 63 | return { 64 | ...config, 65 | ...userConfig, 66 | }; 67 | }; 68 | -------------------------------------------------------------------------------- /config/plugin.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** @type Egg.EggPlugin */ 4 | module.exports = { 5 | // had enabled by egg 6 | // static: { 7 | // enable: true, 8 | // } 9 | }; 10 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "**/*" 4 | ] 5 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "serves", 3 | "version": "1.0.0", 4 | "description": "wxMsg", 5 | "private": true, 6 | "egg": { 7 | "declarations": true 8 | }, 9 | "dependencies": { 10 | "axios": "^0.21.4", 11 | "egg": "^2.15.1", 12 | "egg-scripts": "^2.11.0", 13 | "moment": "^2.29.1" 14 | }, 15 | "devDependencies": { 16 | "autod": "^3.0.1", 17 | "autod-egg": "^1.1.0", 18 | "egg-bin": "^4.11.0", 19 | "egg-ci": "^1.11.0", 20 | "egg-mock": "^3.21.0", 21 | "eslint": "^5.13.0", 22 | "eslint-config-egg": "^7.1.0" 23 | }, 24 | "engines": { 25 | "node": ">=10.0.0" 26 | }, 27 | "scripts": { 28 | "start": "egg-scripts start --daemon --title=egg-server-serves", 29 | "stop": "egg-scripts stop --title=egg-server-serves", 30 | "dev": "egg-bin dev", 31 | "debug": "egg-bin debug", 32 | "test": "npm run lint -- --fix && npm run test-local", 33 | "test-local": "egg-bin test", 34 | "cov": "egg-bin cov", 35 | "lint": "eslint .", 36 | "ci": "npm run lint && npm run cov", 37 | "autod": "autod" 38 | }, 39 | "ci": { 40 | "version": "10" 41 | }, 42 | "repository": { 43 | "type": "git", 44 | "url": "" 45 | }, 46 | "author": "wanghao", 47 | "license": "MIT" 48 | } 49 | -------------------------------------------------------------------------------- /test/app/controller/home.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { app, assert } = require('egg-mock/bootstrap'); 4 | 5 | describe('test/app/controller/home.test.js', () => { 6 | it('should assert', () => { 7 | const pkg = require('../../../package.json'); 8 | assert(app.config.keys.startsWith(pkg.name)); 9 | 10 | // const ctx = app.mockContext({}); 11 | // yield ctx.service.xx(); 12 | }); 13 | 14 | it('should GET /', () => { 15 | return app.httpRequest() 16 | .get('/') 17 | .expect('hi, egg') 18 | .expect(200); 19 | }); 20 | }); 21 | --------------------------------------------------------------------------------