├── .gitignore ├── README.md ├── config ├── default.js └── info.js ├── index.js ├── lib └── mysql.js ├── middlewares └── check.js ├── package-lock.json ├── package.json ├── public ├── avatar.jpg ├── custom.css ├── favicon.ico ├── images │ ├── article.PNG │ ├── home.PNG │ ├── login.PNG │ └── photo.png ├── jquery.min.js ├── normalize.css ├── pagination.js ├── pictureHandle.js ├── skeleton.css └── tools.js ├── routers ├── comments.js ├── pages.js ├── posts.js ├── signin.js ├── signout.js └── upload.js ├── setup.js └── views ├── comment.ejs ├── create.ejs ├── createpage.ejs ├── edit.ejs ├── editpage.ejs ├── footer.ejs ├── header.ejs ├── img.ejs ├── photo.ejs ├── posts.ejs ├── sPage.ejs ├── sPost.ejs ├── signin.ejs ├── uploadimg.ejs └── uploadphoto.ejs /.gitignore: -------------------------------------------------------------------------------- 1 | .deploy_git/ 2 | node_modules/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Koa2 + MySQL Blog 2 | 3 | 实现了Markdown语法,相册,图床,验证码登陆,IP请求次数限制,邮件提醒,评论敏感词过滤等功能。 4 | 5 | ## 主要功能 6 | 7 | * 文章发布/修改/删除 8 | * 单页新建/修改/删除 9 | * 相册上传/图片自动压缩优化 10 | * 评论/回复/敏感词过滤/邮件提醒 11 | * 后台登陆/验证码 12 | * IP请求次数限制 13 | 14 | ## 2018.04.26 更新 - 修改界面 15 | 16 | 重新设计了页面,更加简洁大气。 17 | 18 | ## 安装说明 19 | 20 | 修改 config 文件夹下的 default.js 与 info.js 的相关配置。 21 | 22 | 第一次使用请先创建数据库 23 | 24 | 进入登录mysql输入命令: 25 | 26 | ``` 27 | create database `najeh` default character set utf8 collate utf8_general_ci; 28 | ``` 29 | 30 | 修改 setup.js 里面的默认管理员用户名和密码。 31 | 32 | 创建完数据库以后进入此目录 `node setup.js` 后即可根据下面信息创建管理员用户。 33 | 34 | ## 运行 35 | 36 | ``` 37 | node index.js 38 | ``` 39 | 后台地址:http://localhost:3000/signin 40 | 41 | 默认账号:admin 42 | 默认密码:123456 43 | 44 | ## 截图 45 | 46 | ![](https://github.com/imNajeh/Koa2-Blog/blob/master/public/images/home.PNG) 47 | ![](https://github.com/imNajeh/Koa2-Blog/blob/master/public/images/login.PNG) 48 | ![](https://github.com/imNajeh/Koa2-Blog/blob/master/public/images/article.PNG) 49 | ![](https://github.com/imNajeh/Koa2-Blog/blob/master/public/images/photo.PNG) 50 | 51 | ## 部分功能使用到的模块 52 | 53 | * EJS模板引擎 54 | * koa2-ratelimit 防止恶意多次登陆请求 55 | * markdown-it Markdown解析器 56 | * nodemailer 邮件提醒 57 | * text-censor 评论敏感词过滤 58 | * trek-captcha 验证码生成 -------------------------------------------------------------------------------- /config/default.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | // 启动端口 3 | port: 3000, 4 | // 数据库配置 5 | database: { 6 | DATABASE: 'najeh', 7 | USERNAME: 'root', 8 | PASSWORD: '123456', 9 | PORT: '3306', 10 | HOST: 'localhost' 11 | } 12 | } 13 | 14 | module.exports = config -------------------------------------------------------------------------------- /config/info.js: -------------------------------------------------------------------------------- 1 | const info = { 2 | //域名 3 | domain: "https://", 4 | //博客名称 5 | websiteTitle: "小骆博客", 6 | //首页名称 7 | websiteIndexTitle: "小骆博客 - 记录生活与成长", 8 | //显示在首页html的meta简介 9 | websiteDescription: "Luo's Blog , 记录成长,分享生活与技术的点滴!", 10 | //头像地址 11 | avator: "/avatar.jpg", 12 | //显示在头部的简介 13 | indexDescription: "记录生活与成长", 14 | //博主昵称 15 | myUsername: "小骆", 16 | //邮箱 17 | myEmail: "xxx@qq.com", 18 | //发件邮箱 19 | stmpEmail: "i@xxx.cn", 20 | //发件邮箱密码 21 | stmpEmailPass: "123456", 22 | //邮箱port 23 | stmpPort: 465, 24 | //邮箱host 25 | stmpHost: "smtp.exmail.qq.com", 26 | //统计代码 27 | statistics: ` 28 | 29 | ` 30 | } 31 | 32 | module.exports = info -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const Koa=require('koa'); 2 | const convert = require('koa-convert') 3 | const path=require('path') 4 | const bodyParser = require('koa-bodyparser'); 5 | const ejs=require('ejs'); 6 | const session = require('koa-session-minimal'); 7 | const MysqlStore = require('koa-mysql-session'); 8 | const config = require('./config/default.js'); 9 | const info = require('./config/info.js'); 10 | const router=require('koa-router') 11 | const views = require('koa-views') 12 | // const koaStatic = require('koa-static') 13 | const staticCache = require('koa-static-cache') 14 | const app = new Koa() 15 | 16 | //全局函数 17 | app.use(convert(function* (next){ 18 | this.state = info 19 | yield *next 20 | })) 21 | 22 | // session存储配置 23 | const sessionMysqlConfig= { 24 | user: config.database.USERNAME, 25 | password: config.database.PASSWORD, 26 | database: config.database.DATABASE, 27 | host: config.database.HOST, 28 | } 29 | 30 | // 配置session中间件 31 | app.use(session({ 32 | key: 'USER_SID', 33 | store: new MysqlStore(sessionMysqlConfig) 34 | })) 35 | 36 | // 配置静态资源加载中间件 37 | // app.use(koaStatic( 38 | // path.join(__dirname , './public') 39 | // )) 40 | 41 | // 缓存 42 | app.use(staticCache(path.join(__dirname, './public'), { dynamic: true }, { 43 | maxAge: 365 * 24 * 60 * 60 44 | })) 45 | app.use(staticCache(path.join(__dirname, './images'), { dynamic: true }, { 46 | maxAge: 365 * 24 * 60 * 60 47 | })) 48 | 49 | // 配置服务端模板渲染引擎中间件 50 | app.use(views(path.join(__dirname, './views'), { 51 | extension: 'ejs' 52 | })) 53 | app.use(bodyParser({ 54 | formLimit: '1mb' 55 | })) 56 | 57 | // 路由 58 | app.use(require('./routers/signin.js').routes()) 59 | app.use(require('./routers/posts.js').routes()) 60 | app.use(require('./routers/signout.js').routes()) 61 | app.use(require('./routers/pages.js').routes()) 62 | app.use(require('./routers/upload.js').routes()) 63 | app.use(require('./routers/comments.js').routes()) 64 | 65 | 66 | app.listen(config.port) 67 | 68 | console.log(`listening on port ${config.port}`) 69 | -------------------------------------------------------------------------------- /lib/mysql.js: -------------------------------------------------------------------------------- 1 | var mysql = require('mysql'); 2 | var config = require('../config/default.js') 3 | 4 | var pool = mysql.createPool({ 5 | host : config.database.HOST, 6 | user : config.database.USERNAME, 7 | password : config.database.PASSWORD, 8 | database : config.database.DATABASE 9 | }); 10 | 11 | let query = ( sql, values ) => { 12 | 13 | return new Promise(( resolve, reject ) => { 14 | pool.getConnection( (err, connection) => { 15 | if (err) { 16 | reject( err ) 17 | } else { 18 | connection.query(sql, values, ( err, rows) => { 19 | if ( err ) { 20 | reject( err ) 21 | } else { 22 | resolve( rows ) 23 | } 24 | connection.release() 25 | }) 26 | } 27 | }) 28 | }) 29 | 30 | } 31 | 32 | 33 | // let query = function( sql, values ) { 34 | // pool.getConnection(function(err, connection) { 35 | // // 使用连接 36 | // connection.query( sql,values, function(err, rows) { 37 | // // 使用连接执行查询 38 | // console.log(rows) 39 | // connection.release(); 40 | // //连接不再使用,返回到连接池 41 | // }); 42 | // }); 43 | // } 44 | 45 | let users = 46 | `create table if not exists users( 47 | id INT NOT NULL AUTO_INCREMENT, 48 | name VARCHAR(100) NOT NULL, 49 | pass VARCHAR(100) NOT NULL, 50 | PRIMARY KEY ( id ) 51 | );` 52 | 53 | let posts = 54 | `create table if not exists posts( 55 | id INT NOT NULL AUTO_INCREMENT, 56 | title TEXT(0) NOT NULL, 57 | content TEXT(0) NOT NULL, 58 | md TEXT(0) NOT NULL, 59 | moment VARCHAR(100) NOT NULL, 60 | pv VARCHAR(40) NOT NULL DEFAULT '0', 61 | PRIMARY KEY ( id ) 62 | );` 63 | 64 | let pages = 65 | `create table if not exists pages( 66 | id INT NOT NULL AUTO_INCREMENT, 67 | linkname VARCHAR(100) NOT NULL, 68 | title TEXT(0) NOT NULL, 69 | content TEXT(0) NOT NULL, 70 | md TEXT(0) NOT NULL, 71 | hascom VARCHAR(40) NOT NULL, 72 | PRIMARY KEY ( id ) 73 | );` 74 | 75 | let comments = 76 | `create table if not exists comments( 77 | id INT NOT NULL AUTO_INCREMENT, 78 | name VARCHAR(100) NOT NULL, 79 | email VARCHAR(100) NOT NULL, 80 | website VARCHAR(100) NOT NULL, 81 | content VARCHAR(140) NOT NULL, 82 | link VARCHAR(100) NOT NULL, 83 | reply INT NOT NULL, 84 | replyuser VARCHAR(100) NOT NULL, 85 | moment VARCHAR(100) NOT NULL, 86 | PRIMARY KEY ( id ) 87 | );` 88 | 89 | let photos = 90 | `create table if not exists photos( 91 | id INT NOT NULL AUTO_INCREMENT, 92 | name VARCHAR(100) NOT NULL, 93 | title VARCHAR(100) NOT NULL, 94 | moment VARCHAR(100) NOT NULL, 95 | PRIMARY KEY ( id ) 96 | );` 97 | 98 | let imgs = 99 | `create table if not exists imgs( 100 | id INT NOT NULL AUTO_INCREMENT, 101 | name VARCHAR(100) NOT NULL, 102 | moment VARCHAR(100) NOT NULL, 103 | PRIMARY KEY ( id ) 104 | );` 105 | 106 | let createTable = ( sql ) => { 107 | return query( sql, [] ) 108 | } 109 | 110 | // 建表 111 | createTable(users) 112 | createTable(posts) 113 | createTable(pages) 114 | createTable(comments) 115 | createTable(photos) 116 | createTable(imgs) 117 | 118 | // 创建用户 119 | let insertData = ( value ) => { 120 | let _sql = "insert into users set name=?,pass=?;" 121 | return query( _sql, value ) 122 | } 123 | 124 | // 删除用户 125 | let deleteData = ( value ) => { 126 | let _sql = `delete from users where name = "${value}"` 127 | return query(_sql) 128 | } 129 | 130 | // 查找用户 131 | let findDataByName = ( name ) => { 132 | let _sql = `select * from users where name="${name}";` 133 | return query( _sql ) 134 | } 135 | // 发表文章 136 | let insertPost = ( value ) => { 137 | let _sql = "insert into posts set title=?,content=?,md=?,moment=?;" 138 | return query( _sql, value ) 139 | } 140 | 141 | // 更新浏览数 142 | let updatePostPv = ( value ) => { 143 | let _sql = "update posts set pv=? where id=?" 144 | return query( _sql, value ) 145 | } 146 | 147 | // 通过文章id查找 148 | let findDataById = ( id ) => { 149 | let _sql = `select * from posts where id="${id}";` 150 | return query( _sql) 151 | } 152 | // 查询所有文章 153 | let findAllPost = () => { 154 | let _sql = ` select * FROM posts;` 155 | return query( _sql) 156 | } 157 | // 查询分页文章 158 | let findPostByPage = ( page ) => { 159 | let _sql = ` select * FROM posts order by id desc limit ${(page-1)*5},5;` 160 | return query( _sql) 161 | } 162 | // 更新修改文章 163 | let updatePost = (values) => { 164 | let _sql = `update posts set title=?,content=?,md=? where id=?` 165 | return query(_sql,values) 166 | } 167 | // 删除文章 168 | let deletePost = (id) => { 169 | let _sql = `delete from posts where id = ${id}` 170 | return query(_sql) 171 | } 172 | 173 | // 创建新页面 174 | let insertPage = ( value ) => { 175 | let _sql = "insert into pages set linkname=?,title=?,md=?,content=?,hascom=?;" 176 | return query( _sql, value ) 177 | } 178 | 179 | // 更新单页面 180 | let updatePage = (values) => { 181 | let _sql = `update pages set linkname=?, title=?,content=?,md=?,hascom=? where id=?` 182 | return query(_sql,values) 183 | } 184 | 185 | // 删除单页面 186 | let deletePage = (linkname) => { 187 | let _sql = `delete from pages where linkname ="${linkname}"` 188 | return query(_sql) 189 | } 190 | 191 | // 通过页面链接查找 192 | let findPageDataByLink = ( linkname ) => { 193 | let _sql = `select * from pages where linkname="${linkname}";` 194 | return query( _sql) 195 | } 196 | 197 | // 查找全部单页面标题和链接 198 | let findPageInfoById = () => { 199 | let _sql = `select title,linkname from pages;` 200 | return query( _sql) 201 | } 202 | 203 | // 新增评论 204 | let createComment = ( value ) => { 205 | let _sql = "insert into comments set name=?,email=?,website=?,content=?,link=?,reply=?,replyuser=?,moment=?;" 206 | return query( _sql, value ) 207 | } 208 | 209 | // 获取评论人 210 | let findCommentInfo = (id,link) => { 211 | let _sql = `select name,email from comments where id="${id}" and link="${link}";` 212 | return query( _sql) 213 | } 214 | 215 | // 获取页面评论 216 | let findComments = (link) => { 217 | let _sql = `select * from comments where link="${link}" order by id desc;` 218 | return query( _sql) 219 | } 220 | 221 | // 删除评论 222 | let deleteComments = (id) => { 223 | let _sql = `delete from comments where id = ${id}` 224 | return query(_sql) 225 | } 226 | 227 | // 删除某页评论 228 | let deleteCommentsByLink = (link) => { 229 | let _sql = `delete from comments where link = "${link}"` 230 | return query(_sql) 231 | } 232 | 233 | // 新增图片 234 | let uploadImg = ( value ) => { 235 | let _sql = "insert into imgs set name=?,moment=?;" 236 | return query( _sql, value ) 237 | } 238 | 239 | // 查询全部图片 240 | let findAllImgs = () => { 241 | let _sql = `select * from imgs;` 242 | return query( _sql) 243 | } 244 | 245 | // 查询分页图片 246 | let findImgByPage = ( page ) => { 247 | let _sql = ` select * FROM imgs order by id desc limit ${(page-1)*10},10;` 248 | return query( _sql) 249 | } 250 | 251 | // 删除图片 252 | let deleteImg = (id) => { 253 | let _sql = `delete from imgs where id = ${id}` 254 | return query(_sql) 255 | } 256 | 257 | // 新增相册图片 258 | let uploadPhoto = ( value ) => { 259 | let _sql = "insert into photos set name=?,title=?,moment=?;" 260 | return query( _sql, value ) 261 | } 262 | 263 | // 查询全部相册图片 264 | let findAllPhotos = () => { 265 | let _sql = `select * from photos;` 266 | return query( _sql) 267 | } 268 | 269 | // 查询分页相册图片 270 | let findPhotoByPage = ( page ) => { 271 | let _sql = ` select * FROM photos order by id desc limit ${(page-1)*5},5;` 272 | return query( _sql) 273 | } 274 | 275 | // 删除相册图片 276 | let deletePhoto = (id) => { 277 | let _sql = `delete from photos where id = ${id}` 278 | return query(_sql) 279 | } 280 | 281 | module.exports = { 282 | insertData, 283 | deleteData, 284 | query, 285 | createTable, 286 | findDataByName, 287 | insertPost, 288 | findAllPost, 289 | findPostByPage, 290 | findDataById, 291 | updatePost, 292 | deletePost, 293 | updatePostPv, 294 | insertPage, 295 | updatePage, 296 | deletePage, 297 | findPageDataByLink, 298 | findPageInfoById, 299 | createComment, 300 | findComments, 301 | deleteComments, 302 | deleteCommentsByLink, 303 | findCommentInfo, 304 | uploadImg, 305 | findAllImgs, 306 | findImgByPage, 307 | deleteImg, 308 | uploadPhoto, 309 | findAllPhotos, 310 | findPhotoByPage, 311 | deletePhoto 312 | } 313 | 314 | -------------------------------------------------------------------------------- /middlewares/check.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | // 已经登录了 4 | checkNotLogin: (ctx) => { 5 | if (ctx.session && ctx.session.user) { 6 | ctx.redirect('/'); 7 | return false; 8 | } 9 | return true; 10 | }, 11 | //没有登录 12 | checkLogin: (ctx) => { 13 | if (!ctx.session || !ctx.session.user) { 14 | ctx.redirect('/'); 15 | return false; 16 | } 17 | return true; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Luog", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/geojson": { 8 | "version": "1.0.6", 9 | "resolved": "http://registry.npm.taobao.org/@types/geojson/download/@types/geojson-1.0.6.tgz", 10 | "integrity": "sha1-PgKXJyjGkkjCrwjWCkjLuGgP/98=" 11 | }, 12 | "@types/node": { 13 | "version": "9.3.0", 14 | "resolved": "http://registry.npm.taobao.org/@types/node/download/@types/node-9.3.0.tgz", 15 | "integrity": "sha1-OhKc2nxOXfJAlwJiaJLLS5ZUbdU=" 16 | }, 17 | "abbrev": { 18 | "version": "1.1.1", 19 | "resolved": "http://registry.npm.taobao.org/abbrev/download/abbrev-1.1.1.tgz", 20 | "integrity": "sha1-+PLIh60Qv2f2NPAFtph/7TF5qsg=" 21 | }, 22 | "accepts": { 23 | "version": "1.3.4", 24 | "resolved": "http://registry.npm.taobao.org/accepts/download/accepts-1.3.4.tgz", 25 | "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=", 26 | "requires": { 27 | "mime-types": "2.1.17", 28 | "negotiator": "0.6.1" 29 | } 30 | }, 31 | "ansi-styles": { 32 | "version": "3.2.0", 33 | "resolved": "http://registry.npm.taobao.org/ansi-styles/download/ansi-styles-3.2.0.tgz", 34 | "integrity": "sha1-wVm41b4PnlpvNG2rlPFs4CIWG4g=", 35 | "requires": { 36 | "color-convert": "1.9.1" 37 | } 38 | }, 39 | "any-promise": { 40 | "version": "1.3.0", 41 | "resolved": "http://registry.npm.taobao.org/any-promise/download/any-promise-1.3.0.tgz", 42 | "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" 43 | }, 44 | "argparse": { 45 | "version": "1.0.9", 46 | "resolved": "http://registry.npm.taobao.org/argparse/download/argparse-1.0.9.tgz", 47 | "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", 48 | "requires": { 49 | "sprintf-js": "1.0.3" 50 | } 51 | }, 52 | "assertion-error": { 53 | "version": "1.1.0", 54 | "resolved": "http://registry.npm.taobao.org/assertion-error/download/assertion-error-1.1.0.tgz", 55 | "integrity": "sha1-5gtrDo8wG9l+U3UhW9pAbIURjAs=", 56 | "dev": true 57 | }, 58 | "balanced-match": { 59 | "version": "1.0.0", 60 | "resolved": "http://registry.npm.taobao.org/balanced-match/download/balanced-match-1.0.0.tgz", 61 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 62 | "dev": true 63 | }, 64 | "bignumber.js": { 65 | "version": "4.0.4", 66 | "resolved": "http://registry.npm.taobao.org/bignumber.js/download/bignumber.js-4.0.4.tgz", 67 | "integrity": "sha1-fED1q80tZiOre5loLufbgbEYiaQ=" 68 | }, 69 | "bluebird": { 70 | "version": "3.5.1", 71 | "resolved": "http://registry.npm.taobao.org/bluebird/download/bluebird-3.5.1.tgz", 72 | "integrity": "sha1-2VUfnemPH82h5oPRfukaBgLuLrk=" 73 | }, 74 | "brace-expansion": { 75 | "version": "1.1.8", 76 | "resolved": "http://registry.npm.taobao.org/brace-expansion/download/brace-expansion-1.1.8.tgz", 77 | "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", 78 | "dev": true, 79 | "requires": { 80 | "balanced-match": "1.0.0", 81 | "concat-map": "0.0.1" 82 | } 83 | }, 84 | "browser-stdout": { 85 | "version": "1.3.0", 86 | "resolved": "http://registry.npm.taobao.org/browser-stdout/download/browser-stdout-1.3.0.tgz", 87 | "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", 88 | "dev": true 89 | }, 90 | "bytes": { 91 | "version": "3.0.0", 92 | "resolved": "http://registry.npm.taobao.org/bytes/download/bytes-3.0.0.tgz", 93 | "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" 94 | }, 95 | "chai": { 96 | "version": "4.1.2", 97 | "resolved": "http://registry.npm.taobao.org/chai/download/chai-4.1.2.tgz", 98 | "integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=", 99 | "dev": true, 100 | "requires": { 101 | "assertion-error": "1.1.0", 102 | "check-error": "1.0.2", 103 | "deep-eql": "3.0.1", 104 | "get-func-name": "2.0.0", 105 | "pathval": "1.1.0", 106 | "type-detect": "4.0.5" 107 | } 108 | }, 109 | "chalk": { 110 | "version": "2.1.0", 111 | "resolved": "http://registry.npm.taobao.org/chalk/download/chalk-2.1.0.tgz", 112 | "integrity": "sha1-rFvs8U+iG5nGySynp9fP1bF+dD4=", 113 | "requires": { 114 | "ansi-styles": "3.2.0", 115 | "escape-string-regexp": "1.0.5", 116 | "supports-color": "4.5.0" 117 | } 118 | }, 119 | "charenc": { 120 | "version": "0.0.2", 121 | "resolved": "http://registry.npm.taobao.org/charenc/download/charenc-0.0.2.tgz", 122 | "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" 123 | }, 124 | "check-error": { 125 | "version": "1.0.2", 126 | "resolved": "http://registry.npm.taobao.org/check-error/download/check-error-1.0.2.tgz", 127 | "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", 128 | "dev": true 129 | }, 130 | "cls-bluebird": { 131 | "version": "2.1.0", 132 | "resolved": "http://registry.npm.taobao.org/cls-bluebird/download/cls-bluebird-2.1.0.tgz", 133 | "integrity": "sha1-N+8eCAqP+1XC9BZPU28ZGeeWiu4=", 134 | "requires": { 135 | "is-bluebird": "1.0.2", 136 | "shimmer": "1.2.0" 137 | } 138 | }, 139 | "co": { 140 | "version": "4.6.0", 141 | "resolved": "http://registry.npm.taobao.org/co/download/co-4.6.0.tgz", 142 | "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" 143 | }, 144 | "co-body": { 145 | "version": "5.1.1", 146 | "resolved": "http://registry.npm.taobao.org/co-body/download/co-body-5.1.1.tgz", 147 | "integrity": "sha1-2XeB0eM0S6SoIP0YBr3fg0FQUjY=", 148 | "requires": { 149 | "inflation": "2.0.0", 150 | "qs": "6.5.1", 151 | "raw-body": "2.3.2", 152 | "type-is": "1.6.15" 153 | } 154 | }, 155 | "co-mysql": { 156 | "version": "0.4.1", 157 | "resolved": "http://registry.npm.taobao.org/co-mysql/download/co-mysql-0.4.1.tgz", 158 | "integrity": "sha1-cnPr/ydoHAPDivmAvH4o94p7GTk=", 159 | "requires": { 160 | "mysql": "2.15.0" 161 | } 162 | }, 163 | "color-convert": { 164 | "version": "1.9.1", 165 | "resolved": "http://registry.npm.taobao.org/color-convert/download/color-convert-1.9.1.tgz", 166 | "integrity": "sha1-wSYRB66y8pTr/+ye2eytUppgl+0=", 167 | "requires": { 168 | "color-name": "1.1.3" 169 | } 170 | }, 171 | "color-name": { 172 | "version": "1.1.3", 173 | "resolved": "http://registry.npm.taobao.org/color-name/download/color-name-1.1.3.tgz", 174 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" 175 | }, 176 | "commander": { 177 | "version": "2.13.0", 178 | "resolved": "http://registry.npm.taobao.org/commander/download/commander-2.13.0.tgz", 179 | "integrity": "sha1-aWS8pnaF33wfFDDFhPB9dZeIW5w=" 180 | }, 181 | "compressible": { 182 | "version": "2.0.12", 183 | "resolved": "http://registry.npm.taobao.org/compressible/download/compressible-2.0.12.tgz", 184 | "integrity": "sha1-xZpcmdt2dn6YdlAOJx72OzSTvWY=", 185 | "requires": { 186 | "mime-db": "1.30.0" 187 | } 188 | }, 189 | "concat-map": { 190 | "version": "0.0.1", 191 | "resolved": "http://registry.npm.taobao.org/concat-map/download/concat-map-0.0.1.tgz", 192 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 193 | "dev": true 194 | }, 195 | "condense-newlines": { 196 | "version": "0.2.1", 197 | "resolved": "http://registry.npm.taobao.org/condense-newlines/download/condense-newlines-0.2.1.tgz", 198 | "integrity": "sha1-PemFVTE5R10yUCyDsC9gaE0kxV8=", 199 | "requires": { 200 | "extend-shallow": "2.0.1", 201 | "is-whitespace": "0.3.0", 202 | "kind-of": "3.2.2" 203 | } 204 | }, 205 | "config-chain": { 206 | "version": "1.1.11", 207 | "resolved": "http://registry.npm.taobao.org/config-chain/download/config-chain-1.1.11.tgz", 208 | "integrity": "sha1-q6CXR9++TD5w52am5BWG4YWfxvI=", 209 | "requires": { 210 | "ini": "1.3.5", 211 | "proto-list": "1.2.4" 212 | } 213 | }, 214 | "config-lite": { 215 | "version": "2.1.0", 216 | "resolved": "http://registry.npm.taobao.org/config-lite/download/config-lite-2.1.0.tgz", 217 | "integrity": "sha1-TeOPEGADKldT8Gr1j18Tgqzsbcg=", 218 | "requires": { 219 | "chalk": "2.1.0", 220 | "js-yaml": "3.9.1", 221 | "lodash": "4.17.4", 222 | "optimist": "0.6.1", 223 | "resolve": "1.4.0", 224 | "toml": "2.3.2" 225 | } 226 | }, 227 | "consolidate": { 228 | "version": "0.15.0", 229 | "resolved": "http://registry.npm.taobao.org/consolidate/download/consolidate-0.15.0.tgz", 230 | "integrity": "sha1-OXkYkBKX1fZX0KZRSjBQIkWiCYA=", 231 | "requires": { 232 | "bluebird": "3.5.1" 233 | } 234 | }, 235 | "content-disposition": { 236 | "version": "0.5.2", 237 | "resolved": "http://registry.npm.taobao.org/content-disposition/download/content-disposition-0.5.2.tgz", 238 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" 239 | }, 240 | "content-type": { 241 | "version": "1.0.4", 242 | "resolved": "http://registry.npm.taobao.org/content-type/download/content-type-1.0.4.tgz", 243 | "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=" 244 | }, 245 | "cookies": { 246 | "version": "0.7.1", 247 | "resolved": "http://registry.npm.taobao.org/cookies/download/cookies-0.7.1.tgz", 248 | "integrity": "sha1-fIphX1SBxhq58WyDNzG8uPZjuZs=", 249 | "requires": { 250 | "depd": "1.1.2", 251 | "keygrip": "1.0.2" 252 | } 253 | }, 254 | "copy-to": { 255 | "version": "2.0.1", 256 | "resolved": "http://registry.npm.taobao.org/copy-to/download/copy-to-2.0.1.tgz", 257 | "integrity": "sha1-JoD7uAaKSNCGVrYJgJK9r8kG9KU=" 258 | }, 259 | "core-util-is": { 260 | "version": "1.0.2", 261 | "resolved": "http://registry.npm.taobao.org/core-util-is/download/core-util-is-1.0.2.tgz", 262 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 263 | }, 264 | "crypt": { 265 | "version": "0.0.2", 266 | "resolved": "http://registry.npm.taobao.org/crypt/download/crypt-0.0.2.tgz", 267 | "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=" 268 | }, 269 | "debug": { 270 | "version": "3.1.0", 271 | "resolved": "http://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz", 272 | "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", 273 | "requires": { 274 | "ms": "2.0.0" 275 | } 276 | }, 277 | "deep-eql": { 278 | "version": "3.0.1", 279 | "resolved": "http://registry.npm.taobao.org/deep-eql/download/deep-eql-3.0.1.tgz", 280 | "integrity": "sha1-38lARACtHI/gI+faHfHBR8S0RN8=", 281 | "dev": true, 282 | "requires": { 283 | "type-detect": "4.0.5" 284 | } 285 | }, 286 | "deep-equal": { 287 | "version": "1.0.1", 288 | "resolved": "http://registry.npm.taobao.org/deep-equal/download/deep-equal-1.0.1.tgz", 289 | "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=" 290 | }, 291 | "delegates": { 292 | "version": "1.0.0", 293 | "resolved": "http://registry.npm.taobao.org/delegates/download/delegates-1.0.0.tgz", 294 | "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" 295 | }, 296 | "depd": { 297 | "version": "1.1.2", 298 | "resolved": "http://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz", 299 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 300 | }, 301 | "destroy": { 302 | "version": "1.0.4", 303 | "resolved": "http://registry.npm.taobao.org/destroy/download/destroy-1.0.4.tgz", 304 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 305 | }, 306 | "diff": { 307 | "version": "3.3.1", 308 | "resolved": "http://registry.npm.taobao.org/diff/download/diff-3.3.1.tgz", 309 | "integrity": "sha1-qoVnpu7QPFMfyJ0/cRzQ5SWd7HU=", 310 | "dev": true 311 | }, 312 | "dottie": { 313 | "version": "2.0.0", 314 | "resolved": "http://registry.npm.taobao.org/dottie/download/dottie-2.0.0.tgz", 315 | "integrity": "sha1-2hkZgci41xPKARXViYzzl8Lw3dA=" 316 | }, 317 | "editorconfig": { 318 | "version": "0.13.3", 319 | "resolved": "http://registry.npm.taobao.org/editorconfig/download/editorconfig-0.13.3.tgz", 320 | "integrity": "sha1-5SGeWHlR1glY/ZTqmpoAjN7/GzQ=", 321 | "requires": { 322 | "bluebird": "3.5.1", 323 | "commander": "2.13.0", 324 | "lru-cache": "3.2.0", 325 | "semver": "5.4.1", 326 | "sigmund": "1.0.1" 327 | } 328 | }, 329 | "ee-first": { 330 | "version": "1.1.1", 331 | "resolved": "http://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz", 332 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 333 | }, 334 | "ejs": { 335 | "version": "2.5.7", 336 | "resolved": "http://registry.npm.taobao.org/ejs/download/ejs-2.5.7.tgz", 337 | "integrity": "sha1-zIcsFoiArjxxiXYv1f/ACJbJUYo=" 338 | }, 339 | "entities": { 340 | "version": "1.1.1", 341 | "resolved": "http://registry.npm.taobao.org/entities/download/entities-1.1.1.tgz", 342 | "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=" 343 | }, 344 | "error-inject": { 345 | "version": "1.0.0", 346 | "resolved": "http://registry.npm.taobao.org/error-inject/download/error-inject-1.0.0.tgz", 347 | "integrity": "sha1-4rPZG1Su1nLzCdlQ0VSFD6EdTzc=" 348 | }, 349 | "escape-html": { 350 | "version": "1.0.3", 351 | "resolved": "http://registry.npm.taobao.org/escape-html/download/escape-html-1.0.3.tgz", 352 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 353 | }, 354 | "escape-string-regexp": { 355 | "version": "1.0.5", 356 | "resolved": "http://registry.npm.taobao.org/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz", 357 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" 358 | }, 359 | "esprima": { 360 | "version": "4.0.0", 361 | "resolved": "http://registry.npm.taobao.org/esprima/download/esprima-4.0.0.tgz", 362 | "integrity": "sha1-RJnt3NERDgshi6zy+n9/WfVcqAQ=" 363 | }, 364 | "extend-shallow": { 365 | "version": "2.0.1", 366 | "resolved": "http://registry.npm.taobao.org/extend-shallow/download/extend-shallow-2.0.1.tgz", 367 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 368 | "requires": { 369 | "is-extendable": "0.1.1" 370 | } 371 | }, 372 | "fresh": { 373 | "version": "0.5.2", 374 | "resolved": "http://registry.npm.taobao.org/fresh/download/fresh-0.5.2.tgz", 375 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 376 | }, 377 | "fs-extra": { 378 | "version": "4.0.3", 379 | "resolved": "http://registry.npm.taobao.org/fs-extra/download/fs-extra-4.0.3.tgz", 380 | "integrity": "sha1-DYUhIuW8W+tFP7Ao6cDJvzY0DJQ=", 381 | "requires": { 382 | "graceful-fs": "4.1.11", 383 | "jsonfile": "4.0.0", 384 | "universalify": "0.1.1" 385 | } 386 | }, 387 | "fs-readdir-recursive": { 388 | "version": "1.0.0", 389 | "resolved": "http://registry.npm.taobao.org/fs-readdir-recursive/download/fs-readdir-recursive-1.0.0.tgz", 390 | "integrity": "sha1-jNF0XItPiinIyuw5JHaSG6GV9WA=" 391 | }, 392 | "fs.realpath": { 393 | "version": "1.0.0", 394 | "resolved": "http://registry.npm.taobao.org/fs.realpath/download/fs.realpath-1.0.0.tgz", 395 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 396 | "dev": true 397 | }, 398 | "generic-pool": { 399 | "version": "3.4.0", 400 | "resolved": "http://registry.npm.taobao.org/generic-pool/download/generic-pool-3.4.0.tgz", 401 | "integrity": "sha1-a3b8IBu0mg/zgUUPWFNSN4+xwI8=" 402 | }, 403 | "get-func-name": { 404 | "version": "2.0.0", 405 | "resolved": "http://registry.npm.taobao.org/get-func-name/download/get-func-name-2.0.0.tgz", 406 | "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", 407 | "dev": true 408 | }, 409 | "get-paths": { 410 | "version": "0.0.2", 411 | "resolved": "http://registry.npm.taobao.org/get-paths/download/get-paths-0.0.2.tgz", 412 | "integrity": "sha1-qcJ7Go0AbJMaTyb899FUbjrXG+o=", 413 | "requires": { 414 | "fs-extra": "4.0.3" 415 | } 416 | }, 417 | "glob": { 418 | "version": "7.1.2", 419 | "resolved": "http://registry.npm.taobao.org/glob/download/glob-7.1.2.tgz", 420 | "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", 421 | "dev": true, 422 | "requires": { 423 | "fs.realpath": "1.0.0", 424 | "inflight": "1.0.6", 425 | "inherits": "2.0.3", 426 | "minimatch": "3.0.4", 427 | "once": "1.4.0", 428 | "path-is-absolute": "1.0.1" 429 | } 430 | }, 431 | "graceful-fs": { 432 | "version": "4.1.11", 433 | "resolved": "http://registry.npm.taobao.org/graceful-fs/download/graceful-fs-4.1.11.tgz", 434 | "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" 435 | }, 436 | "growl": { 437 | "version": "1.10.3", 438 | "resolved": "http://registry.npm.taobao.org/growl/download/growl-1.10.3.tgz", 439 | "integrity": "sha1-GSa6kM8+3+KttJJ/WIC8IsZseQ8=", 440 | "dev": true 441 | }, 442 | "has-flag": { 443 | "version": "2.0.0", 444 | "resolved": "http://registry.npm.taobao.org/has-flag/download/has-flag-2.0.0.tgz", 445 | "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" 446 | }, 447 | "he": { 448 | "version": "1.1.1", 449 | "resolved": "http://registry.npm.taobao.org/he/download/he-1.1.1.tgz", 450 | "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", 451 | "dev": true 452 | }, 453 | "http-assert": { 454 | "version": "1.3.0", 455 | "resolved": "http://registry.npm.taobao.org/http-assert/download/http-assert-1.3.0.tgz", 456 | "integrity": "sha1-oxpc+IyHPsu1eWkH1NbxMujAHko=", 457 | "requires": { 458 | "deep-equal": "1.0.1", 459 | "http-errors": "1.6.2" 460 | } 461 | }, 462 | "http-errors": { 463 | "version": "1.6.2", 464 | "resolved": "http://registry.npm.taobao.org/http-errors/download/http-errors-1.6.2.tgz", 465 | "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", 466 | "requires": { 467 | "depd": "1.1.1", 468 | "inherits": "2.0.3", 469 | "setprototypeof": "1.0.3", 470 | "statuses": "1.4.0" 471 | }, 472 | "dependencies": { 473 | "depd": { 474 | "version": "1.1.1", 475 | "resolved": "http://registry.npm.taobao.org/depd/download/depd-1.1.1.tgz", 476 | "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" 477 | } 478 | } 479 | }, 480 | "iconv-lite": { 481 | "version": "0.4.19", 482 | "resolved": "http://registry.npm.taobao.org/iconv-lite/download/iconv-lite-0.4.19.tgz", 483 | "integrity": "sha1-90aPYBNfXl2tM5nAqBvpoWA6CCs=" 484 | }, 485 | "inflation": { 486 | "version": "2.0.0", 487 | "resolved": "http://registry.npm.taobao.org/inflation/download/inflation-2.0.0.tgz", 488 | "integrity": "sha1-i0F+R8KPklpFEz2RTKH9OJEH8w8=" 489 | }, 490 | "inflection": { 491 | "version": "1.12.0", 492 | "resolved": "http://registry.npm.taobao.org/inflection/download/inflection-1.12.0.tgz", 493 | "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=" 494 | }, 495 | "inflight": { 496 | "version": "1.0.6", 497 | "resolved": "http://registry.npm.taobao.org/inflight/download/inflight-1.0.6.tgz", 498 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 499 | "dev": true, 500 | "requires": { 501 | "once": "1.4.0", 502 | "wrappy": "1.0.2" 503 | } 504 | }, 505 | "inherits": { 506 | "version": "2.0.3", 507 | "resolved": "http://registry.npm.taobao.org/inherits/download/inherits-2.0.3.tgz", 508 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 509 | }, 510 | "ini": { 511 | "version": "1.3.5", 512 | "resolved": "http://registry.npm.taobao.org/ini/download/ini-1.3.5.tgz", 513 | "integrity": "sha1-7uJfVtscnsYIXgwid4CD9Zar+Sc=" 514 | }, 515 | "is-bluebird": { 516 | "version": "1.0.2", 517 | "resolved": "http://registry.npm.taobao.org/is-bluebird/download/is-bluebird-1.0.2.tgz", 518 | "integrity": "sha1-CWQ5Bg9KpBGr7hkUOoTWpVNG1uI=" 519 | }, 520 | "is-buffer": { 521 | "version": "1.1.6", 522 | "resolved": "http://registry.npm.taobao.org/is-buffer/download/is-buffer-1.1.6.tgz", 523 | "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=" 524 | }, 525 | "is-extendable": { 526 | "version": "0.1.1", 527 | "resolved": "http://registry.npm.taobao.org/is-extendable/download/is-extendable-0.1.1.tgz", 528 | "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" 529 | }, 530 | "is-generator-function": { 531 | "version": "1.0.7", 532 | "resolved": "http://registry.npm.taobao.org/is-generator-function/download/is-generator-function-1.0.7.tgz", 533 | "integrity": "sha1-0hMuUpuwAAp/gHlNS99c1eWBNSI=" 534 | }, 535 | "is-whitespace": { 536 | "version": "0.3.0", 537 | "resolved": "http://registry.npm.taobao.org/is-whitespace/download/is-whitespace-0.3.0.tgz", 538 | "integrity": "sha1-Fjnssb4DauxppUy7QBz77XEUq38=" 539 | }, 540 | "isarray": { 541 | "version": "1.0.0", 542 | "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz", 543 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 544 | }, 545 | "js-beautify": { 546 | "version": "1.7.5", 547 | "resolved": "http://registry.npm.taobao.org/js-beautify/download/js-beautify-1.7.5.tgz", 548 | "integrity": "sha1-adllHvYNu2SfZVJ7U2dJUBOKeRk=", 549 | "requires": { 550 | "config-chain": "1.1.11", 551 | "editorconfig": "0.13.3", 552 | "mkdirp": "0.5.1", 553 | "nopt": "3.0.6" 554 | } 555 | }, 556 | "js-yaml": { 557 | "version": "3.9.1", 558 | "resolved": "http://registry.npm.taobao.org/js-yaml/download/js-yaml-3.9.1.tgz", 559 | "integrity": "sha1-CHdc69/dNZIJ8NKs04PI+GppBKA=", 560 | "requires": { 561 | "argparse": "1.0.9", 562 | "esprima": "4.0.0" 563 | } 564 | }, 565 | "jsonfile": { 566 | "version": "4.0.0", 567 | "resolved": "http://registry.npm.taobao.org/jsonfile/download/jsonfile-4.0.0.tgz", 568 | "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", 569 | "requires": { 570 | "graceful-fs": "4.1.11" 571 | } 572 | }, 573 | "keygrip": { 574 | "version": "1.0.2", 575 | "resolved": "http://registry.npm.taobao.org/keygrip/download/keygrip-1.0.2.tgz", 576 | "integrity": "sha1-rTKXxVcGneqLz+ek+kkbdcXd65E=" 577 | }, 578 | "kind-of": { 579 | "version": "3.2.2", 580 | "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", 581 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 582 | "requires": { 583 | "is-buffer": "1.1.6" 584 | } 585 | }, 586 | "koa": { 587 | "version": "2.4.1", 588 | "resolved": "http://registry.npm.taobao.org/koa/download/koa-2.4.1.tgz", 589 | "integrity": "sha1-1EnPuXCn6dpXH2me2kC7njLrFIQ=", 590 | "requires": { 591 | "accepts": "1.3.4", 592 | "content-disposition": "0.5.2", 593 | "content-type": "1.0.4", 594 | "cookies": "0.7.1", 595 | "debug": "3.1.0", 596 | "delegates": "1.0.0", 597 | "depd": "1.1.2", 598 | "destroy": "1.0.4", 599 | "error-inject": "1.0.0", 600 | "escape-html": "1.0.3", 601 | "fresh": "0.5.2", 602 | "http-assert": "1.3.0", 603 | "http-errors": "1.6.2", 604 | "is-generator-function": "1.0.7", 605 | "koa-compose": "4.0.0", 606 | "koa-convert": "1.2.0", 607 | "koa-is-json": "1.0.0", 608 | "mime-types": "2.1.17", 609 | "on-finished": "2.3.0", 610 | "only": "0.0.2", 611 | "parseurl": "1.3.2", 612 | "statuses": "1.4.0", 613 | "type-is": "1.6.15", 614 | "vary": "1.1.2" 615 | } 616 | }, 617 | "koa-bodyparser": { 618 | "version": "4.2.0", 619 | "resolved": "http://registry.npm.taobao.org/koa-bodyparser/download/koa-bodyparser-4.2.0.tgz", 620 | "integrity": "sha1-vObgi8Zfhwm20fqpQRx/DYk4qlQ=", 621 | "requires": { 622 | "co-body": "5.1.1", 623 | "copy-to": "2.0.1" 624 | } 625 | }, 626 | "koa-compose": { 627 | "version": "4.0.0", 628 | "resolved": "http://registry.npm.taobao.org/koa-compose/download/koa-compose-4.0.0.tgz", 629 | "integrity": "sha1-KAClE9nDYe8NY4UrA45Pby1adzw=" 630 | }, 631 | "koa-convert": { 632 | "version": "1.2.0", 633 | "resolved": "http://registry.npm.taobao.org/koa-convert/download/koa-convert-1.2.0.tgz", 634 | "integrity": "sha1-2kCHXfSd4FOQmNFwC1CCDOvNIdA=", 635 | "requires": { 636 | "co": "4.6.0", 637 | "koa-compose": "3.2.1" 638 | }, 639 | "dependencies": { 640 | "koa-compose": { 641 | "version": "3.2.1", 642 | "resolved": "http://registry.npm.taobao.org/koa-compose/download/koa-compose-3.2.1.tgz", 643 | "integrity": "sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec=", 644 | "requires": { 645 | "any-promise": "1.3.0" 646 | } 647 | } 648 | } 649 | }, 650 | "koa-is-json": { 651 | "version": "1.0.0", 652 | "resolved": "http://registry.npm.taobao.org/koa-is-json/download/koa-is-json-1.0.0.tgz", 653 | "integrity": "sha1-JzwH7c3Ljfaiwat9We52SRRR7BQ=" 654 | }, 655 | "koa-mysql-session": { 656 | "version": "0.0.2", 657 | "resolved": "http://registry.npm.taobao.org/koa-mysql-session/download/koa-mysql-session-0.0.2.tgz", 658 | "integrity": "sha1-t/MvTdLDel95kiYXl8WTc3BO3Ik=", 659 | "requires": { 660 | "co": "3.1.0", 661 | "co-mysql": "0.4.1" 662 | }, 663 | "dependencies": { 664 | "co": { 665 | "version": "3.1.0", 666 | "resolved": "http://registry.npm.taobao.org/co/download/co-3.1.0.tgz", 667 | "integrity": "sha1-TqVOpaCJOBUxheFSEMaNkJK8G3g=" 668 | } 669 | } 670 | }, 671 | "koa-router": { 672 | "version": "7.3.0", 673 | "resolved": "http://registry.npm.taobao.org/koa-router/download/koa-router-7.3.0.tgz", 674 | "integrity": "sha1-JB8ESaxc0QcYMamj2AtSH6+2uqE=", 675 | "requires": { 676 | "debug": "3.1.0", 677 | "http-errors": "1.6.2", 678 | "koa-compose": "3.2.1", 679 | "methods": "1.1.2", 680 | "path-to-regexp": "1.7.0", 681 | "urijs": "1.19.0" 682 | }, 683 | "dependencies": { 684 | "koa-compose": { 685 | "version": "3.2.1", 686 | "resolved": "http://registry.npm.taobao.org/koa-compose/download/koa-compose-3.2.1.tgz", 687 | "integrity": "sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec=", 688 | "requires": { 689 | "any-promise": "1.3.0" 690 | } 691 | } 692 | } 693 | }, 694 | "koa-send": { 695 | "version": "4.1.2", 696 | "resolved": "http://registry.npm.taobao.org/koa-send/download/koa-send-4.1.2.tgz", 697 | "integrity": "sha1-koYdGExNhFilT5LmcI4JsU1kERw=", 698 | "requires": { 699 | "debug": "2.6.9", 700 | "http-errors": "1.6.2", 701 | "mz": "2.7.0", 702 | "resolve-path": "1.3.3" 703 | }, 704 | "dependencies": { 705 | "debug": { 706 | "version": "2.6.9", 707 | "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz", 708 | "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", 709 | "requires": { 710 | "ms": "2.0.0" 711 | } 712 | } 713 | } 714 | }, 715 | "koa-session-minimal": { 716 | "version": "3.0.4", 717 | "resolved": "http://registry.npm.taobao.org/koa-session-minimal/download/koa-session-minimal-3.0.4.tgz", 718 | "integrity": "sha1-1qFb7u131dPiakIdu5imH2Oor80=", 719 | "requires": { 720 | "co": "4.6.0", 721 | "deep-equal": "1.0.1", 722 | "uid-safe": "2.1.5" 723 | } 724 | }, 725 | "koa-static": { 726 | "version": "4.0.2", 727 | "resolved": "http://registry.npm.taobao.org/koa-static/download/koa-static-4.0.2.tgz", 728 | "integrity": "sha1-bNqS2I13Hcqtnw2CXNlKYxyGGho=", 729 | "requires": { 730 | "debug": "2.6.9", 731 | "koa-send": "4.1.2" 732 | }, 733 | "dependencies": { 734 | "debug": { 735 | "version": "2.6.9", 736 | "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz", 737 | "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", 738 | "requires": { 739 | "ms": "2.0.0" 740 | } 741 | } 742 | } 743 | }, 744 | "koa-static-cache": { 745 | "version": "5.1.1", 746 | "resolved": "http://registry.npm.taobao.org/koa-static-cache/download/koa-static-cache-5.1.1.tgz", 747 | "integrity": "sha1-1z3HkYP9BS+GpHoLZAgNhnDeijg=", 748 | "requires": { 749 | "compressible": "2.0.12", 750 | "debug": "3.1.0", 751 | "fs-readdir-recursive": "1.0.0", 752 | "mime-types": "2.1.17", 753 | "mz": "2.6.0" 754 | }, 755 | "dependencies": { 756 | "mz": { 757 | "version": "2.6.0", 758 | "resolved": "http://registry.npm.taobao.org/mz/download/mz-2.6.0.tgz", 759 | "integrity": "sha1-yLhSHZWN8KTydoAl22nHGe5O8c4=", 760 | "requires": { 761 | "any-promise": "1.3.0", 762 | "object-assign": "4.1.1", 763 | "thenify-all": "1.6.0" 764 | } 765 | } 766 | } 767 | }, 768 | "koa-views": { 769 | "version": "6.1.3", 770 | "resolved": "http://registry.npm.taobao.org/koa-views/download/koa-views-6.1.3.tgz", 771 | "integrity": "sha1-ZusEpgKMaG0bvu32uo+QaaG6QEo=", 772 | "requires": { 773 | "consolidate": "0.15.0", 774 | "debug": "3.1.0", 775 | "get-paths": "0.0.2", 776 | "koa-send": "4.1.2", 777 | "mz": "2.7.0", 778 | "pretty": "2.0.0" 779 | } 780 | }, 781 | "koa2-ratelimit": { 782 | "version": "0.4.3", 783 | "resolved": "http://registry.npm.taobao.org/koa2-ratelimit/download/koa2-ratelimit-0.4.3.tgz", 784 | "integrity": "sha1-UR0c8w8fknf0bpD0wroQz5GcItA=", 785 | "requires": { 786 | "moment": "2.20.1", 787 | "sequelize": "4.31.2" 788 | } 789 | }, 790 | "linkify-it": { 791 | "version": "2.0.3", 792 | "resolved": "http://registry.npm.taobao.org/linkify-it/download/linkify-it-2.0.3.tgz", 793 | "integrity": "sha1-2UpGSPmxwXnWT6lykSaL22zpQ08=", 794 | "requires": { 795 | "uc.micro": "1.0.3" 796 | } 797 | }, 798 | "lodash": { 799 | "version": "4.17.4", 800 | "resolved": "http://registry.npm.taobao.org/lodash/download/lodash-4.17.4.tgz", 801 | "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" 802 | }, 803 | "lru-cache": { 804 | "version": "3.2.0", 805 | "resolved": "http://registry.npm.taobao.org/lru-cache/download/lru-cache-3.2.0.tgz", 806 | "integrity": "sha1-cXibO39Tmb7IVl3aOKow0qCX7+4=", 807 | "requires": { 808 | "pseudomap": "1.0.2" 809 | } 810 | }, 811 | "markdown-it": { 812 | "version": "8.4.0", 813 | "resolved": "http://registry.npm.taobao.org/markdown-it/download/markdown-it-8.4.0.tgz", 814 | "integrity": "sha1-4kAIgb8XH3AY7RvZ2kQdrIr2MG0=", 815 | "requires": { 816 | "argparse": "1.0.9", 817 | "entities": "1.1.1", 818 | "linkify-it": "2.0.3", 819 | "mdurl": "1.0.1", 820 | "uc.micro": "1.0.3" 821 | } 822 | }, 823 | "md5": { 824 | "version": "2.2.1", 825 | "resolved": "http://registry.npm.taobao.org/md5/download/md5-2.2.1.tgz", 826 | "integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=", 827 | "requires": { 828 | "charenc": "0.0.2", 829 | "crypt": "0.0.2", 830 | "is-buffer": "1.1.6" 831 | } 832 | }, 833 | "mdurl": { 834 | "version": "1.0.1", 835 | "resolved": "http://registry.npm.taobao.org/mdurl/download/mdurl-1.0.1.tgz", 836 | "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" 837 | }, 838 | "media-typer": { 839 | "version": "0.3.0", 840 | "resolved": "http://registry.npm.taobao.org/media-typer/download/media-typer-0.3.0.tgz", 841 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 842 | }, 843 | "methods": { 844 | "version": "1.1.2", 845 | "resolved": "http://registry.npm.taobao.org/methods/download/methods-1.1.2.tgz", 846 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 847 | }, 848 | "mime-db": { 849 | "version": "1.30.0", 850 | "resolved": "http://registry.npm.taobao.org/mime-db/download/mime-db-1.30.0.tgz", 851 | "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" 852 | }, 853 | "mime-types": { 854 | "version": "2.1.17", 855 | "resolved": "http://registry.npm.taobao.org/mime-types/download/mime-types-2.1.17.tgz", 856 | "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", 857 | "requires": { 858 | "mime-db": "1.30.0" 859 | } 860 | }, 861 | "minimatch": { 862 | "version": "3.0.4", 863 | "resolved": "http://registry.npm.taobao.org/minimatch/download/minimatch-3.0.4.tgz", 864 | "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", 865 | "dev": true, 866 | "requires": { 867 | "brace-expansion": "1.1.8" 868 | } 869 | }, 870 | "minimist": { 871 | "version": "0.0.10", 872 | "resolved": "http://registry.npm.taobao.org/minimist/download/minimist-0.0.10.tgz", 873 | "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" 874 | }, 875 | "mkdirp": { 876 | "version": "0.5.1", 877 | "resolved": "http://registry.npm.taobao.org/mkdirp/download/mkdirp-0.5.1.tgz", 878 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 879 | "requires": { 880 | "minimist": "0.0.8" 881 | }, 882 | "dependencies": { 883 | "minimist": { 884 | "version": "0.0.8", 885 | "resolved": "http://registry.npm.taobao.org/minimist/download/minimist-0.0.8.tgz", 886 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" 887 | } 888 | } 889 | }, 890 | "mocha": { 891 | "version": "4.1.0", 892 | "resolved": "http://registry.npm.taobao.org/mocha/download/mocha-4.1.0.tgz", 893 | "integrity": "sha1-fYbPvPNcuCnidUwy4XNV7AUzh5Q=", 894 | "dev": true, 895 | "requires": { 896 | "browser-stdout": "1.3.0", 897 | "commander": "2.11.0", 898 | "debug": "3.1.0", 899 | "diff": "3.3.1", 900 | "escape-string-regexp": "1.0.5", 901 | "glob": "7.1.2", 902 | "growl": "1.10.3", 903 | "he": "1.1.1", 904 | "mkdirp": "0.5.1", 905 | "supports-color": "4.4.0" 906 | }, 907 | "dependencies": { 908 | "commander": { 909 | "version": "2.11.0", 910 | "resolved": "http://registry.npm.taobao.org/commander/download/commander-2.11.0.tgz", 911 | "integrity": "sha1-FXFS/R56bI2YpbcVzzdt+SgARWM=", 912 | "dev": true 913 | }, 914 | "supports-color": { 915 | "version": "4.4.0", 916 | "resolved": "http://registry.npm.taobao.org/supports-color/download/supports-color-4.4.0.tgz", 917 | "integrity": "sha1-iD992rwWUUKyphQn8zUt7RldGj4=", 918 | "dev": true, 919 | "requires": { 920 | "has-flag": "2.0.0" 921 | } 922 | } 923 | } 924 | }, 925 | "moment": { 926 | "version": "2.20.1", 927 | "resolved": "http://registry.npm.taobao.org/moment/download/moment-2.20.1.tgz", 928 | "integrity": "sha1-1usaRsvMFKKy+UNBEsH/iQfzE/0=" 929 | }, 930 | "moment-timezone": { 931 | "version": "0.5.14", 932 | "resolved": "http://registry.npm.taobao.org/moment-timezone/download/moment-timezone-0.5.14.tgz", 933 | "integrity": "sha1-TrOP+VOLgBCLpGekWPPtQmjM/LE=", 934 | "requires": { 935 | "moment": "2.20.1" 936 | } 937 | }, 938 | "ms": { 939 | "version": "2.0.0", 940 | "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", 941 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 942 | }, 943 | "mysql": { 944 | "version": "2.15.0", 945 | "resolved": "http://registry.npm.taobao.org/mysql/download/mysql-2.15.0.tgz", 946 | "integrity": "sha1-6haEEVY0Po8uR/yJhexBzdlXO1w=", 947 | "requires": { 948 | "bignumber.js": "4.0.4", 949 | "readable-stream": "2.3.3", 950 | "safe-buffer": "5.1.1", 951 | "sqlstring": "2.3.0" 952 | } 953 | }, 954 | "mz": { 955 | "version": "2.7.0", 956 | "resolved": "http://registry.npm.taobao.org/mz/download/mz-2.7.0.tgz", 957 | "integrity": "sha1-lQCAV6Vsr63CvGPd5/n/aVWUjjI=", 958 | "requires": { 959 | "any-promise": "1.3.0", 960 | "object-assign": "4.1.1", 961 | "thenify-all": "1.6.0" 962 | } 963 | }, 964 | "negotiator": { 965 | "version": "0.6.1", 966 | "resolved": "http://registry.npm.taobao.org/negotiator/download/negotiator-0.6.1.tgz", 967 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" 968 | }, 969 | "nodemailer": { 970 | "version": "4.4.2", 971 | "resolved": "http://registry.npm.taobao.org/nodemailer/download/nodemailer-4.4.2.tgz", 972 | "integrity": "sha1-8hX7iOihBS+fkwg5CeEW0refyN4=" 973 | }, 974 | "nopt": { 975 | "version": "3.0.6", 976 | "resolved": "http://registry.npm.taobao.org/nopt/download/nopt-3.0.6.tgz", 977 | "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", 978 | "requires": { 979 | "abbrev": "1.1.1" 980 | } 981 | }, 982 | "object-assign": { 983 | "version": "4.1.1", 984 | "resolved": "http://registry.npm.taobao.org/object-assign/download/object-assign-4.1.1.tgz", 985 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" 986 | }, 987 | "on-finished": { 988 | "version": "2.3.0", 989 | "resolved": "http://registry.npm.taobao.org/on-finished/download/on-finished-2.3.0.tgz", 990 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 991 | "requires": { 992 | "ee-first": "1.1.1" 993 | } 994 | }, 995 | "once": { 996 | "version": "1.4.0", 997 | "resolved": "http://registry.npm.taobao.org/once/download/once-1.4.0.tgz", 998 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 999 | "dev": true, 1000 | "requires": { 1001 | "wrappy": "1.0.2" 1002 | } 1003 | }, 1004 | "only": { 1005 | "version": "0.0.2", 1006 | "resolved": "http://registry.npm.taobao.org/only/download/only-0.0.2.tgz", 1007 | "integrity": "sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q=" 1008 | }, 1009 | "optimist": { 1010 | "version": "0.6.1", 1011 | "resolved": "http://registry.npm.taobao.org/optimist/download/optimist-0.6.1.tgz", 1012 | "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", 1013 | "requires": { 1014 | "minimist": "0.0.10", 1015 | "wordwrap": "0.0.3" 1016 | } 1017 | }, 1018 | "parseurl": { 1019 | "version": "1.3.2", 1020 | "resolved": "http://registry.npm.taobao.org/parseurl/download/parseurl-1.3.2.tgz", 1021 | "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" 1022 | }, 1023 | "path-is-absolute": { 1024 | "version": "1.0.1", 1025 | "resolved": "http://registry.npm.taobao.org/path-is-absolute/download/path-is-absolute-1.0.1.tgz", 1026 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 1027 | }, 1028 | "path-parse": { 1029 | "version": "1.0.5", 1030 | "resolved": "http://registry.npm.taobao.org/path-parse/download/path-parse-1.0.5.tgz", 1031 | "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=" 1032 | }, 1033 | "path-to-regexp": { 1034 | "version": "1.7.0", 1035 | "resolved": "http://registry.npm.taobao.org/path-to-regexp/download/path-to-regexp-1.7.0.tgz", 1036 | "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", 1037 | "requires": { 1038 | "isarray": "0.0.1" 1039 | }, 1040 | "dependencies": { 1041 | "isarray": { 1042 | "version": "0.0.1", 1043 | "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-0.0.1.tgz", 1044 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" 1045 | } 1046 | } 1047 | }, 1048 | "pathval": { 1049 | "version": "1.1.0", 1050 | "resolved": "http://registry.npm.taobao.org/pathval/download/pathval-1.1.0.tgz", 1051 | "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", 1052 | "dev": true 1053 | }, 1054 | "pretty": { 1055 | "version": "2.0.0", 1056 | "resolved": "http://registry.npm.taobao.org/pretty/download/pretty-2.0.0.tgz", 1057 | "integrity": "sha1-rbx5YLe7/iiaVX3F9zdhmiINBqU=", 1058 | "requires": { 1059 | "condense-newlines": "0.2.1", 1060 | "extend-shallow": "2.0.1", 1061 | "js-beautify": "1.7.5" 1062 | } 1063 | }, 1064 | "process-nextick-args": { 1065 | "version": "1.0.7", 1066 | "resolved": "http://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-1.0.7.tgz", 1067 | "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" 1068 | }, 1069 | "proto-list": { 1070 | "version": "1.2.4", 1071 | "resolved": "http://registry.npm.taobao.org/proto-list/download/proto-list-1.2.4.tgz", 1072 | "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" 1073 | }, 1074 | "pseudomap": { 1075 | "version": "1.0.2", 1076 | "resolved": "http://registry.npm.taobao.org/pseudomap/download/pseudomap-1.0.2.tgz", 1077 | "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" 1078 | }, 1079 | "qs": { 1080 | "version": "6.5.1", 1081 | "resolved": "http://registry.npm.taobao.org/qs/download/qs-6.5.1.tgz", 1082 | "integrity": "sha1-NJzfbu+J7EXBLX1es/wMhwNDptg=" 1083 | }, 1084 | "random-bytes": { 1085 | "version": "1.0.0", 1086 | "resolved": "http://registry.npm.taobao.org/random-bytes/download/random-bytes-1.0.0.tgz", 1087 | "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=" 1088 | }, 1089 | "raw-body": { 1090 | "version": "2.3.2", 1091 | "resolved": "http://registry.npm.taobao.org/raw-body/download/raw-body-2.3.2.tgz", 1092 | "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", 1093 | "requires": { 1094 | "bytes": "3.0.0", 1095 | "http-errors": "1.6.2", 1096 | "iconv-lite": "0.4.19", 1097 | "unpipe": "1.0.0" 1098 | } 1099 | }, 1100 | "readable-stream": { 1101 | "version": "2.3.3", 1102 | "resolved": "http://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.3.tgz", 1103 | "integrity": "sha1-No8lEtefnUb9/HE0mueHi7weuVw=", 1104 | "requires": { 1105 | "core-util-is": "1.0.2", 1106 | "inherits": "2.0.3", 1107 | "isarray": "1.0.0", 1108 | "process-nextick-args": "1.0.7", 1109 | "safe-buffer": "5.1.1", 1110 | "string_decoder": "1.0.3", 1111 | "util-deprecate": "1.0.2" 1112 | } 1113 | }, 1114 | "resolve": { 1115 | "version": "1.4.0", 1116 | "resolved": "http://registry.npm.taobao.org/resolve/download/resolve-1.4.0.tgz", 1117 | "integrity": "sha1-p1vgHFPaJdk0qY69DkxKcxL5KoY=", 1118 | "requires": { 1119 | "path-parse": "1.0.5" 1120 | } 1121 | }, 1122 | "resolve-path": { 1123 | "version": "1.3.3", 1124 | "resolved": "http://registry.npm.taobao.org/resolve-path/download/resolve-path-1.3.3.tgz", 1125 | "integrity": "sha1-TYOrpkaMK45jKldeP1Kw+g2+Glw=", 1126 | "requires": { 1127 | "http-errors": "1.5.1", 1128 | "path-is-absolute": "1.0.1" 1129 | }, 1130 | "dependencies": { 1131 | "http-errors": { 1132 | "version": "1.5.1", 1133 | "resolved": "http://registry.npm.taobao.org/http-errors/download/http-errors-1.5.1.tgz", 1134 | "integrity": "sha1-eIwNLB3iyBuebowBhDtrl+uSB1A=", 1135 | "requires": { 1136 | "inherits": "2.0.3", 1137 | "setprototypeof": "1.0.2", 1138 | "statuses": "1.4.0" 1139 | } 1140 | }, 1141 | "setprototypeof": { 1142 | "version": "1.0.2", 1143 | "resolved": "http://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.0.2.tgz", 1144 | "integrity": "sha1-gaVSFB7BBLiOic44MQOtXGZWTQg=" 1145 | } 1146 | } 1147 | }, 1148 | "retry-as-promised": { 1149 | "version": "2.3.2", 1150 | "resolved": "http://registry.npm.taobao.org/retry-as-promised/download/retry-as-promised-2.3.2.tgz", 1151 | "integrity": "sha1-zZdO5P2bX+A8vzGHHuSCIcB3N7c=", 1152 | "requires": { 1153 | "bluebird": "3.5.1", 1154 | "debug": "2.6.9" 1155 | }, 1156 | "dependencies": { 1157 | "debug": { 1158 | "version": "2.6.9", 1159 | "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz", 1160 | "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", 1161 | "requires": { 1162 | "ms": "2.0.0" 1163 | } 1164 | } 1165 | } 1166 | }, 1167 | "safe-buffer": { 1168 | "version": "5.1.1", 1169 | "resolved": "http://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.1.tgz", 1170 | "integrity": "sha1-iTMSr2myEj3vcfV4iQAWce6yyFM=" 1171 | }, 1172 | "semver": { 1173 | "version": "5.4.1", 1174 | "resolved": "http://registry.npm.taobao.org/semver/download/semver-5.4.1.tgz", 1175 | "integrity": "sha1-4FnAnYVx8FQII3M0M1BdOi8AsY4=" 1176 | }, 1177 | "sequelize": { 1178 | "version": "4.31.2", 1179 | "resolved": "http://registry.npm.taobao.org/sequelize/download/sequelize-4.31.2.tgz", 1180 | "integrity": "sha1-S0FMObrBiudJRu1JswD1vH5CNGI=", 1181 | "requires": { 1182 | "bluebird": "3.5.1", 1183 | "cls-bluebird": "2.1.0", 1184 | "debug": "3.1.0", 1185 | "depd": "1.1.2", 1186 | "dottie": "2.0.0", 1187 | "generic-pool": "3.4.0", 1188 | "inflection": "1.12.0", 1189 | "lodash": "4.17.4", 1190 | "moment": "2.20.1", 1191 | "moment-timezone": "0.5.14", 1192 | "retry-as-promised": "2.3.2", 1193 | "semver": "5.4.1", 1194 | "terraformer-wkt-parser": "1.1.2", 1195 | "toposort-class": "1.0.1", 1196 | "uuid": "3.1.0", 1197 | "validator": "9.2.0", 1198 | "wkx": "0.4.2" 1199 | } 1200 | }, 1201 | "setprototypeof": { 1202 | "version": "1.0.3", 1203 | "resolved": "http://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.0.3.tgz", 1204 | "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" 1205 | }, 1206 | "shimmer": { 1207 | "version": "1.2.0", 1208 | "resolved": "http://registry.npm.taobao.org/shimmer/download/shimmer-1.2.0.tgz", 1209 | "integrity": "sha1-+Wb3VVeJdj502IQRk2haXnhzZmU=" 1210 | }, 1211 | "sigmund": { 1212 | "version": "1.0.1", 1213 | "resolved": "http://registry.npm.taobao.org/sigmund/download/sigmund-1.0.1.tgz", 1214 | "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=" 1215 | }, 1216 | "sprintf-js": { 1217 | "version": "1.0.3", 1218 | "resolved": "http://registry.npm.taobao.org/sprintf-js/download/sprintf-js-1.0.3.tgz", 1219 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" 1220 | }, 1221 | "sqlstring": { 1222 | "version": "2.3.0", 1223 | "resolved": "http://registry.npm.taobao.org/sqlstring/download/sqlstring-2.3.0.tgz", 1224 | "integrity": "sha1-UluKT9Jtb3GqYegipsr5dtMa0qg=" 1225 | }, 1226 | "statuses": { 1227 | "version": "1.4.0", 1228 | "resolved": "http://registry.npm.taobao.org/statuses/download/statuses-1.4.0.tgz", 1229 | "integrity": "sha1-u3PURtonlhBu/MG2AaJT1sRr0Ic=" 1230 | }, 1231 | "string_decoder": { 1232 | "version": "1.0.3", 1233 | "resolved": "http://registry.npm.taobao.org/string_decoder/download/string_decoder-1.0.3.tgz", 1234 | "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", 1235 | "requires": { 1236 | "safe-buffer": "5.1.1" 1237 | } 1238 | }, 1239 | "supports-color": { 1240 | "version": "4.5.0", 1241 | "resolved": "http://registry.npm.taobao.org/supports-color/download/supports-color-4.5.0.tgz", 1242 | "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", 1243 | "requires": { 1244 | "has-flag": "2.0.0" 1245 | } 1246 | }, 1247 | "terraformer": { 1248 | "version": "1.0.8", 1249 | "resolved": "http://registry.npm.taobao.org/terraformer/download/terraformer-1.0.8.tgz", 1250 | "integrity": "sha1-UeCtiXRvzyFh3G9lqnDkI3fItZM=", 1251 | "requires": { 1252 | "@types/geojson": "1.0.6" 1253 | } 1254 | }, 1255 | "terraformer-wkt-parser": { 1256 | "version": "1.1.2", 1257 | "resolved": "http://registry.npm.taobao.org/terraformer-wkt-parser/download/terraformer-wkt-parser-1.1.2.tgz", 1258 | "integrity": "sha1-M2oMj8gglKWv+DKI9prt7NNpvww=", 1259 | "requires": { 1260 | "terraformer": "1.0.8" 1261 | } 1262 | }, 1263 | "text-censor": { 1264 | "version": "1.0.2", 1265 | "resolved": "http://registry.npm.taobao.org/text-censor/download/text-censor-1.0.2.tgz", 1266 | "integrity": "sha1-Z6ftmukXSVlhOqHyufabZrkIokk=" 1267 | }, 1268 | "thenify": { 1269 | "version": "3.3.0", 1270 | "resolved": "http://registry.npm.taobao.org/thenify/download/thenify-3.3.0.tgz", 1271 | "integrity": "sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=", 1272 | "requires": { 1273 | "any-promise": "1.3.0" 1274 | } 1275 | }, 1276 | "thenify-all": { 1277 | "version": "1.6.0", 1278 | "resolved": "http://registry.npm.taobao.org/thenify-all/download/thenify-all-1.6.0.tgz", 1279 | "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", 1280 | "requires": { 1281 | "thenify": "3.3.0" 1282 | } 1283 | }, 1284 | "toml": { 1285 | "version": "2.3.2", 1286 | "resolved": "http://registry.npm.taobao.org/toml/download/toml-2.3.2.tgz", 1287 | "integrity": "sha1-Xt7VykKIeSSUn9BusOlVZWAB6DQ=" 1288 | }, 1289 | "toposort-class": { 1290 | "version": "1.0.1", 1291 | "resolved": "http://registry.npm.taobao.org/toposort-class/download/toposort-class-1.0.1.tgz", 1292 | "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" 1293 | }, 1294 | "trek-captcha": { 1295 | "version": "0.4.0", 1296 | "resolved": "http://registry.npm.taobao.org/trek-captcha/download/trek-captcha-0.4.0.tgz", 1297 | "integrity": "sha1-IbV8SeLUMcJmr/IQDMqzO24TwMA=" 1298 | }, 1299 | "type-detect": { 1300 | "version": "4.0.5", 1301 | "resolved": "http://registry.npm.taobao.org/type-detect/download/type-detect-4.0.5.tgz", 1302 | "integrity": "sha1-1w5byB223io4G8rKDG4MvcdjXeI=", 1303 | "dev": true 1304 | }, 1305 | "type-is": { 1306 | "version": "1.6.15", 1307 | "resolved": "http://registry.npm.taobao.org/type-is/download/type-is-1.6.15.tgz", 1308 | "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", 1309 | "requires": { 1310 | "media-typer": "0.3.0", 1311 | "mime-types": "2.1.17" 1312 | } 1313 | }, 1314 | "uc.micro": { 1315 | "version": "1.0.3", 1316 | "resolved": "http://registry.npm.taobao.org/uc.micro/download/uc.micro-1.0.3.tgz", 1317 | "integrity": "sha1-ftUNXg+an7ClczeSWfKndFjVAZI=" 1318 | }, 1319 | "uid-safe": { 1320 | "version": "2.1.5", 1321 | "resolved": "http://registry.npm.taobao.org/uid-safe/download/uid-safe-2.1.5.tgz", 1322 | "integrity": "sha1-Kz1cckDo/C5Y+Komnl7knAhXvTo=", 1323 | "requires": { 1324 | "random-bytes": "1.0.0" 1325 | } 1326 | }, 1327 | "universalify": { 1328 | "version": "0.1.1", 1329 | "resolved": "http://registry.npm.taobao.org/universalify/download/universalify-0.1.1.tgz", 1330 | "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=" 1331 | }, 1332 | "unpipe": { 1333 | "version": "1.0.0", 1334 | "resolved": "http://registry.npm.taobao.org/unpipe/download/unpipe-1.0.0.tgz", 1335 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 1336 | }, 1337 | "urijs": { 1338 | "version": "1.19.0", 1339 | "resolved": "http://registry.npm.taobao.org/urijs/download/urijs-1.19.0.tgz", 1340 | "integrity": "sha1-2KooTQ50aXA6aYitBFxMv98IraA=" 1341 | }, 1342 | "util-deprecate": { 1343 | "version": "1.0.2", 1344 | "resolved": "http://registry.npm.taobao.org/util-deprecate/download/util-deprecate-1.0.2.tgz", 1345 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 1346 | }, 1347 | "uuid": { 1348 | "version": "3.1.0", 1349 | "resolved": "http://registry.npm.taobao.org/uuid/download/uuid-3.1.0.tgz", 1350 | "integrity": "sha1-PdPT55Crwk17DToDT/q6vijrvAQ=" 1351 | }, 1352 | "validator": { 1353 | "version": "9.2.0", 1354 | "resolved": "http://registry.npm.taobao.org/validator/download/validator-9.2.0.tgz", 1355 | "integrity": "sha1-rSFu7V83ysMab+AM6rH2uIve0D4=" 1356 | }, 1357 | "vary": { 1358 | "version": "1.1.2", 1359 | "resolved": "http://registry.npm.taobao.org/vary/download/vary-1.1.2.tgz", 1360 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 1361 | }, 1362 | "wkx": { 1363 | "version": "0.4.2", 1364 | "resolved": "http://registry.npm.taobao.org/wkx/download/wkx-0.4.2.tgz", 1365 | "integrity": "sha1-d201pjSlwi5lbkdEvetU+D/Szo0=", 1366 | "requires": { 1367 | "@types/node": "9.3.0" 1368 | } 1369 | }, 1370 | "wordwrap": { 1371 | "version": "0.0.3", 1372 | "resolved": "http://registry.npm.taobao.org/wordwrap/download/wordwrap-0.0.3.tgz", 1373 | "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" 1374 | }, 1375 | "wrappy": { 1376 | "version": "1.0.2", 1377 | "resolved": "http://registry.npm.taobao.org/wrappy/download/wrappy-1.0.2.tgz", 1378 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1379 | "dev": true 1380 | } 1381 | } 1382 | } 1383 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Koa2 blog", 3 | "version": "1.0.0", 4 | "description": "A simple blog system.", 5 | "main": "index.js", 6 | "directories": { 7 | "lib": "lib" 8 | }, 9 | "scripts": { 10 | "start": "node index.js" 11 | }, 12 | "author": "Najeh Luo", 13 | "license": "MIT", 14 | "dependencies": { 15 | "config-lite": "^2.0.0", 16 | "ejs": "^2.5.6", 17 | "koa": "^2.3.0", 18 | "koa-bodyparser": "^4.2.0", 19 | "koa-convert": "^1.2.0", 20 | "koa-mysql-session": "^0.0.2", 21 | "koa-router": "^7.2.1", 22 | "koa-session-minimal": "^3.0.4", 23 | "koa-static": "^4.0.0", 24 | "koa-static-cache": "^5.1.1", 25 | "koa-views": "^6.0.2", 26 | "koa2-ratelimit": "^0.4.3", 27 | "markdown-it": "^8.4.0", 28 | "md5": "^2.2.1", 29 | "moment": "^2.18.1", 30 | "mysql": "^2.13.0", 31 | "nodemailer": "^4.4.2", 32 | "text-censor": "^1.0.2", 33 | "trek-captcha": "^0.4.0" 34 | }, 35 | "devDependencies": { 36 | "chai": "^4.1.2", 37 | "mocha": "^4.0.1" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /public/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakholuo/Koa2-Blog/ffa9694f9c7e76a2e7007ab945b72ff069db5610/public/avatar.jpg -------------------------------------------------------------------------------- /public/custom.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: Cairo,PingHei,'PingFang SC',Helvetica Neue,'Work Sans','Hiragino Sans GB','Microsoft YaHei',SimSun,sans-serif; 3 | background-color: #FCFCFC; 4 | } 5 | 6 | h1 { font-size: 2.1rem; } 7 | h2 { font-size: 1.9rem; } 8 | h3 { font-size: 1.7rem; } 9 | h4, 10 | h5, 11 | h6 { font-size: 1.5rem; } 12 | 13 | img { 14 | max-width: 100%; 15 | height: auto; 16 | vertical-align: middle; 17 | border: 0; 18 | } 19 | 20 | header, 21 | footer { 22 | margin: 4rem 0; 23 | text-align: center; 24 | } 25 | 26 | main { 27 | margin: 4rem 0; 28 | } 29 | 30 | .container { 31 | width: 90%; 32 | max-width: 700px; 33 | } 34 | 35 | .header-logo img { 36 | width: 80px; 37 | height: 80px; 38 | border-radius: 50%; 39 | border: 1px solid #E1E1E1; 40 | box-shadow: 0 0 0 3px #fff, 0 0 0 4px #eee; 41 | } 42 | 43 | .header-logo img:hover { 44 | border-color: #F1F1F1; 45 | } 46 | 47 | nav { 48 | text-align: right; 49 | padding: 20px 20px 0; 50 | } 51 | 52 | nav a { 53 | padding: 8px 6px 8px 0; 54 | color: #333; 55 | font-weight: 300; 56 | font-size: 1.4rem; 57 | text-decoration: none; 58 | } 59 | 60 | .site-title { 61 | margin-top: 2rem; 62 | color: #444; 63 | font-weight: 400; 64 | font-size: 2.4rem; 65 | } 66 | 67 | .site-second-title { 68 | font-size: 1.4rem; 69 | font-weight: 300; 70 | font-style: normal; 71 | margin-top: 10px; 72 | text-transform: uppercase; 73 | color: #aaa; 74 | /* letter-spacing: .5rem; */ 75 | word-spacing: .5rem; 76 | } 77 | 78 | .article { 79 | padding: 20px 0; 80 | border-top: 1px solid #eee; 81 | } 82 | 83 | .article:last-child { 84 | border-bottom: 1px solid #eee; 85 | } 86 | 87 | .entry-title { 88 | margin-bottom: 0; 89 | position: relative; 90 | } 91 | 92 | .entry-title a { 93 | text-decoration: none; 94 | color: #333; 95 | font: 300 19px/1.7 Cairo,PingHei,'PingFang SC',Helvetica Neue,'Work Sans','Hiragino Sans GB','Microsoft YaHei',SimSun,sans-serif; 96 | display: block; 97 | text-transform: uppercase; 98 | } 99 | 100 | .entry-meta { 101 | display: inline-block; 102 | margin-bottom: 2rem; 103 | font-size: 1.7rem; 104 | color: #888; 105 | float: right; 106 | } 107 | 108 | @media screen and (max-width: 500px) { 109 | .entry-meta { 110 | display: none; 111 | } 112 | } 113 | 114 | .article-title { 115 | text-align: center; 116 | margin-bottom: 1rem; 117 | font-size: 2.8rem; 118 | color: #222; 119 | } 120 | 121 | .article-meta { 122 | text-align: center; 123 | margin-bottom: 2rem; 124 | font-size: 1.7rem; 125 | color: #888; 126 | } 127 | 128 | .article h1, .article h2, .article h3, .article h4, .article h5, .article h6{ 129 | font-weight: 400; 130 | } 131 | 132 | .footer-link { 133 | margin: 2rem 0; 134 | } 135 | .footer-link a { 136 | text-decoration: none; 137 | } 138 | .iconfont { 139 | font-size: 3rem; 140 | color: #cdd4da; 141 | } 142 | /* .icon-qq { 143 | color: rgb(0, 108, 226); 144 | } 145 | .icon-weibo { 146 | color: rgb(230, 22, 45); 147 | } 148 | .icon-github { 149 | color: #333; 150 | } 151 | .icon-zhihu { 152 | color: rgb(94, 170, 222); 153 | } */ 154 | 155 | .copyright { 156 | color: #222; 157 | } 158 | .copyright a { 159 | color: #5694f1; 160 | text-decoration: none; 161 | } 162 | .hr { 163 | height: 1px; 164 | margin: 2rem 0; 165 | background: #E1E1E1; 166 | background: -webkit-gradient(linear, left top, right top, from(white), color-stop(#E1E1E1), to(white)); 167 | background: -webkit-linear-gradient(left, white, #E1E1E1, white); 168 | background: linear-gradient(to right, white, #E1E1E1, white); 169 | } 170 | 171 | .message { 172 | position: fixed; 173 | top: -100%; 174 | left: 50%; 175 | transform: translateX(-50%); 176 | padding: 1em 1em; 177 | background: rgba(0, 0, 0, 0.7); 178 | color: #fff; 179 | border-bottom-left-radius: .4em; 180 | border-bottom-right-radius: .4em; 181 | z-index: 99999; 182 | } 183 | 184 | .submit { 185 | background-color: #8796a3; 186 | border-radius: 5px; 187 | color: #fff; 188 | text-align: center; 189 | } 190 | 191 | .signout, .submit, .delete_post, .submit_comment { 192 | cursor: pointer; 193 | } 194 | 195 | .signout { 196 | padding: 8px 6px 8px 0; 197 | color: #333; 198 | font-weight: 300; 199 | font-size: 1.4rem; 200 | text-decoration: none; 201 | } 202 | 203 | .pagenav a { 204 | padding: 0 5px 205 | } 206 | 207 | .pagenav a:hover { 208 | background-color: #32393f; 209 | color: #fff 210 | } 211 | 212 | .photo_item { 213 | width: 100%; 214 | } 215 | 216 | .photo_wrap { 217 | display: inline-block; 218 | margin: 0.625em; 219 | } -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakholuo/Koa2-Blog/ffa9694f9c7e76a2e7007ab945b72ff069db5610/public/favicon.ico -------------------------------------------------------------------------------- /public/images/article.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakholuo/Koa2-Blog/ffa9694f9c7e76a2e7007ab945b72ff069db5610/public/images/article.PNG -------------------------------------------------------------------------------- /public/images/home.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakholuo/Koa2-Blog/ffa9694f9c7e76a2e7007ab945b72ff069db5610/public/images/home.PNG -------------------------------------------------------------------------------- /public/images/login.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakholuo/Koa2-Blog/ffa9694f9c7e76a2e7007ab945b72ff069db5610/public/images/login.PNG -------------------------------------------------------------------------------- /public/images/photo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakholuo/Koa2-Blog/ffa9694f9c7e76a2e7007ab945b72ff069db5610/public/images/photo.png -------------------------------------------------------------------------------- /public/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */ 2 | 3 | /** 4 | * 1. Set default font family to sans-serif. 5 | * 2. Prevent iOS text size adjust after orientation change, without disabling 6 | * user zoom. 7 | */ 8 | 9 | html { 10 | font-family: sans-serif; /* 1 */ 11 | -ms-text-size-adjust: 100%; /* 2 */ 12 | -webkit-text-size-adjust: 100%; /* 2 */ 13 | } 14 | 15 | /** 16 | * Remove default margin. 17 | */ 18 | 19 | body { 20 | margin: 0; 21 | } 22 | 23 | /* HTML5 display definitions 24 | ========================================================================== */ 25 | 26 | /** 27 | * Correct `block` display not defined for any HTML5 element in IE 8/9. 28 | * Correct `block` display not defined for `details` or `summary` in IE 10/11 29 | * and Firefox. 30 | * Correct `block` display not defined for `main` in IE 11. 31 | */ 32 | 33 | article, 34 | aside, 35 | details, 36 | figcaption, 37 | figure, 38 | footer, 39 | header, 40 | hgroup, 41 | main, 42 | menu, 43 | nav, 44 | section, 45 | summary { 46 | display: block; 47 | } 48 | 49 | /** 50 | * 1. Correct `inline-block` display not defined in IE 8/9. 51 | * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. 52 | */ 53 | 54 | audio, 55 | canvas, 56 | progress, 57 | video { 58 | display: inline-block; /* 1 */ 59 | vertical-align: baseline; /* 2 */ 60 | } 61 | 62 | /** 63 | * Prevent modern browsers from displaying `audio` without controls. 64 | * Remove excess height in iOS 5 devices. 65 | */ 66 | 67 | audio:not([controls]) { 68 | display: none; 69 | height: 0; 70 | } 71 | 72 | /** 73 | * Address `[hidden]` styling not present in IE 8/9/10. 74 | * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. 75 | */ 76 | 77 | [hidden], 78 | template { 79 | display: none; 80 | } 81 | 82 | /* Links 83 | ========================================================================== */ 84 | 85 | /** 86 | * Remove the gray background color from active links in IE 10. 87 | */ 88 | 89 | a { 90 | background-color: transparent; 91 | } 92 | 93 | /** 94 | * Improve readability when focused and also mouse hovered in all browsers. 95 | */ 96 | 97 | a:active, 98 | a:hover { 99 | outline: 0; 100 | } 101 | 102 | /* Text-level semantics 103 | ========================================================================== */ 104 | 105 | /** 106 | * Address styling not present in IE 8/9/10/11, Safari, and Chrome. 107 | */ 108 | 109 | abbr[title] { 110 | border-bottom: 1px dotted; 111 | } 112 | 113 | /** 114 | * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. 115 | */ 116 | 117 | b, 118 | strong { 119 | font-weight: bold; 120 | } 121 | 122 | /** 123 | * Address styling not present in Safari and Chrome. 124 | */ 125 | 126 | dfn { 127 | font-style: italic; 128 | } 129 | 130 | /** 131 | * Address variable `h1` font-size and margin within `section` and `article` 132 | * contexts in Firefox 4+, Safari, and Chrome. 133 | */ 134 | 135 | h1 { 136 | font-size: 2em; 137 | margin: 0.67em 0; 138 | } 139 | 140 | /** 141 | * Address styling not present in IE 8/9. 142 | */ 143 | 144 | mark { 145 | background: #ff0; 146 | color: #000; 147 | } 148 | 149 | /** 150 | * Address inconsistent and variable font size in all browsers. 151 | */ 152 | 153 | small { 154 | font-size: 80%; 155 | } 156 | 157 | /** 158 | * Prevent `sub` and `sup` affecting `line-height` in all browsers. 159 | */ 160 | 161 | sub, 162 | sup { 163 | font-size: 75%; 164 | line-height: 0; 165 | position: relative; 166 | vertical-align: baseline; 167 | } 168 | 169 | sup { 170 | top: -0.5em; 171 | } 172 | 173 | sub { 174 | bottom: -0.25em; 175 | } 176 | 177 | /* Embedded content 178 | ========================================================================== */ 179 | 180 | /** 181 | * Remove border when inside `a` element in IE 8/9/10. 182 | */ 183 | 184 | img { 185 | border: 0; 186 | } 187 | 188 | /** 189 | * Correct overflow not hidden in IE 9/10/11. 190 | */ 191 | 192 | svg:not(:root) { 193 | overflow: hidden; 194 | } 195 | 196 | /* Grouping content 197 | ========================================================================== */ 198 | 199 | /** 200 | * Address margin not present in IE 8/9 and Safari. 201 | */ 202 | 203 | figure { 204 | margin: 1em 40px; 205 | } 206 | 207 | /** 208 | * Address differences between Firefox and other browsers. 209 | */ 210 | 211 | hr { 212 | -moz-box-sizing: content-box; 213 | box-sizing: content-box; 214 | height: 0; 215 | } 216 | 217 | /** 218 | * Contain overflow in all browsers. 219 | */ 220 | 221 | pre { 222 | overflow: auto; 223 | } 224 | 225 | /** 226 | * Address odd `em`-unit font size rendering in all browsers. 227 | */ 228 | 229 | code, 230 | kbd, 231 | pre, 232 | samp { 233 | font-family: monospace, monospace; 234 | font-size: 1em; 235 | } 236 | 237 | /* Forms 238 | ========================================================================== */ 239 | 240 | /** 241 | * Known limitation: by default, Chrome and Safari on OS X allow very limited 242 | * styling of `select`, unless a `border` property is set. 243 | */ 244 | 245 | /** 246 | * 1. Correct color not being inherited. 247 | * Known issue: affects color of disabled elements. 248 | * 2. Correct font properties not being inherited. 249 | * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. 250 | */ 251 | 252 | button, 253 | input, 254 | optgroup, 255 | select, 256 | textarea { 257 | color: inherit; /* 1 */ 258 | font: inherit; /* 2 */ 259 | margin: 0; /* 3 */ 260 | } 261 | 262 | /** 263 | * Address `overflow` set to `hidden` in IE 8/9/10/11. 264 | */ 265 | 266 | button { 267 | overflow: visible; 268 | } 269 | 270 | /** 271 | * Address inconsistent `text-transform` inheritance for `button` and `select`. 272 | * All other form control elements do not inherit `text-transform` values. 273 | * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. 274 | * Correct `select` style inheritance in Firefox. 275 | */ 276 | 277 | button, 278 | select { 279 | text-transform: none; 280 | } 281 | 282 | /** 283 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 284 | * and `video` controls. 285 | * 2. Correct inability to style clickable `input` types in iOS. 286 | * 3. Improve usability and consistency of cursor style between image-type 287 | * `input` and others. 288 | */ 289 | 290 | button, 291 | html input[type="button"], /* 1 */ 292 | input[type="reset"], 293 | input[type="submit"] { 294 | -webkit-appearance: button; /* 2 */ 295 | cursor: pointer; /* 3 */ 296 | } 297 | 298 | /** 299 | * Re-set default cursor for disabled elements. 300 | */ 301 | 302 | button[disabled], 303 | html input[disabled] { 304 | cursor: default; 305 | } 306 | 307 | /** 308 | * Remove inner padding and border in Firefox 4+. 309 | */ 310 | 311 | button::-moz-focus-inner, 312 | input::-moz-focus-inner { 313 | border: 0; 314 | padding: 0; 315 | } 316 | 317 | /** 318 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in 319 | * the UA stylesheet. 320 | */ 321 | 322 | input { 323 | line-height: normal; 324 | } 325 | 326 | /** 327 | * It's recommended that you don't attempt to style these elements. 328 | * Firefox's implementation doesn't respect box-sizing, padding, or width. 329 | * 330 | * 1. Address box sizing set to `content-box` in IE 8/9/10. 331 | * 2. Remove excess padding in IE 8/9/10. 332 | */ 333 | 334 | input[type="checkbox"], 335 | input[type="radio"] { 336 | box-sizing: border-box; /* 1 */ 337 | padding: 0; /* 2 */ 338 | } 339 | 340 | /** 341 | * Fix the cursor style for Chrome's increment/decrement buttons. For certain 342 | * `font-size` values of the `input`, it causes the cursor style of the 343 | * decrement button to change from `default` to `text`. 344 | */ 345 | 346 | input[type="number"]::-webkit-inner-spin-button, 347 | input[type="number"]::-webkit-outer-spin-button { 348 | height: auto; 349 | } 350 | 351 | /** 352 | * 1. Address `appearance` set to `searchfield` in Safari and Chrome. 353 | * 2. Address `box-sizing` set to `border-box` in Safari and Chrome 354 | * (include `-moz` to future-proof). 355 | */ 356 | 357 | input[type="search"] { 358 | -webkit-appearance: textfield; /* 1 */ 359 | -moz-box-sizing: content-box; 360 | -webkit-box-sizing: content-box; /* 2 */ 361 | box-sizing: content-box; 362 | } 363 | 364 | /** 365 | * Remove inner padding and search cancel button in Safari and Chrome on OS X. 366 | * Safari (but not Chrome) clips the cancel button when the search input has 367 | * padding (and `textfield` appearance). 368 | */ 369 | 370 | input[type="search"]::-webkit-search-cancel-button, 371 | input[type="search"]::-webkit-search-decoration { 372 | -webkit-appearance: none; 373 | } 374 | 375 | /** 376 | * Define consistent border, margin, and padding. 377 | */ 378 | 379 | fieldset { 380 | border: 1px solid #c0c0c0; 381 | margin: 0 2px; 382 | padding: 0.35em 0.625em 0.75em; 383 | } 384 | 385 | /** 386 | * 1. Correct `color` not being inherited in IE 8/9/10/11. 387 | * 2. Remove padding so people aren't caught out if they zero out fieldsets. 388 | */ 389 | 390 | legend { 391 | border: 0; /* 1 */ 392 | padding: 0; /* 2 */ 393 | } 394 | 395 | /** 396 | * Remove default vertical scrollbar in IE 8/9/10/11. 397 | */ 398 | 399 | textarea { 400 | overflow: auto; 401 | } 402 | 403 | /** 404 | * Don't inherit the `font-weight` (applied by a rule above). 405 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. 406 | */ 407 | 408 | optgroup { 409 | font-weight: bold; 410 | } 411 | 412 | /* Tables 413 | ========================================================================== */ 414 | 415 | /** 416 | * Remove most spacing between table cells. 417 | */ 418 | 419 | table { 420 | border-collapse: collapse; 421 | border-spacing: 0; 422 | } 423 | 424 | td, 425 | th { 426 | padding: 0; 427 | } -------------------------------------------------------------------------------- /public/pagination.js: -------------------------------------------------------------------------------- 1 | function pagination(data,callback){ 2 | // css鏍峰紡 3 | if(!document.getElementById('pageStyle')){ 4 | var style = document.createElement('style') 5 | style.id = 'pageStyle' 6 | style.innerHTML='.pagination{text-align:center;}.pagination a,.pagination span{margin:0 .1em;color:#39434d;background:#fff;text-decoration:none;border-radius:4px;user-select:none;cursor:pointer}.pagination a:hover,.pagination span:hover{color:#fff;background:#8796a3}.pagination .active{color:#fff;background:#8796a3;cursor:default;}.pagination input{width:40px;padding:7px 0;border:none;outline:0;border:1px solid #ddd;border-radius:4px;text-align:center;margin:0 5px}.pagination i{font-style: normal;margin:0 5px;color:#999}.pagination input:focus{border:1px solid #428bca}' 7 | document.getElementsByTagName('head')[0].appendChild(style) 8 | } 9 | var page = document.getElementById(data.selector.slice(1)), 10 | nextPage = document.getElementById('nextPage'), 11 | // prevPage = document.getElementById('prevPage'), 12 | inputGo = document.getElementById('inputGo'), 13 | currentPage = data.currentPage, 14 | nowPage = currentPage ? currentPage : 1, 15 | visiblePage = Math.ceil(data.visiblePage / 2), 16 | i_html = '', 17 | pageOneLoad = data.pageOneLoad ? false : true; 18 | // 鍒濆鍖� 19 | pageAction(nowPage) 20 | function pageAction(dataPage){ 21 | nowPage = dataPage; 22 | i_html = ''; 23 | var count = data.count <= 1 ? 1 : data.count ? data.count : 2 24 | startPage = dataPage - data.count <= 1 ? 1 : dataPage - data.count, 25 | endPage = dataPage + data.count >= data.totalPage ? data.totalPage : dataPage + data.count, 26 | prevPage = data.prev ? data.prev : '<', 27 | nextPage = data.next ? data.next : '>'; 28 | // if (dataPage > 1) { 29 | // i_html += ''+ prevPage +'' 30 | // if (data.first) { 31 | // i_html += '首页' 32 | // } 33 | // } 34 | if (dataPage >= 5) { 35 | for (var i = 1 ; i <= 2; i++) { 36 | i_html += ''+ i +'' 37 | } 38 | i_html += '...' 39 | } 40 | for (var j = startPage; j <= endPage ; j++) { 41 | i_html += ''+ j +'' 42 | } 43 | if (endPage + 1 < data.totalPage) { 44 | i_html += '...' 45 | for (var i = (endPage > data.totalPage - 2 ? data.totalPage : data.totalPage - 1 ); i <= data.totalPage; i++) { 46 | i_html += ''+ i +'' 47 | } 48 | if (data.last) { 49 | i_html += '灏鹃〉' 50 | } 51 | i_html += ''+ nextPage +'' 52 | } 53 | if (data.showTotalPage && data.totalPage >= 1) { 54 | i_html += ''+ nowPage+'/'+data.totalPage +'' 55 | } 56 | if (data.jumpBtn && data.totalPage >= 1) { 57 | i_html += '鍓嶅線椤� 纭畾' 58 | } 59 | page.innerHTML = i_html; 60 | var pageA = page.getElementsByTagName('a'); 61 | for (var i = 0,pageALength = pageA.length; i < pageALength; i++) { 62 | pageA[i].className = '' 63 | if (pageA[i].getAttribute('data-page') == dataPage ) { 64 | pageA[i].className = "active" 65 | } 66 | } 67 | // 绗竴椤典笉璇锋眰 68 | if (!pageOneLoad) { 69 | callback && callback.call(null,dataPage) 70 | } 71 | } 72 | page.onclick = function(event){ 73 | var event = event || window.event, 74 | target = event.target || event.srcElement, 75 | dataPage = parseInt(target.getAttribute('data-page')); 76 | pageOneLoad = false; 77 | if (target.className == 'active') return 78 | if (target.nodeName.toLowerCase() == 'a') { 79 | pageAction(dataPage) 80 | } 81 | if (target.id == 'nextPage') { 82 | nowPage++ 83 | pageAction(nowPage) 84 | } 85 | if (target.id == 'prevPage') { 86 | nowPage-- 87 | pageAction(nowPage) 88 | } 89 | if (target.id == 'inputGo') { 90 | var pageInput = document.getElementById('pageInput'), 91 | goPage = pageInput.value > data.totalPage ? 1 : /[1-9]+/g.test(pageInput.value) ? pageInput.value : 1; 92 | pageAction(parseInt(goPage)) 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /public/pictureHandle.js: -------------------------------------------------------------------------------- 1 | $(function(){ 2 | var _upFile=document.getElementById("upFile"); 3 | 4 | _upFile.addEventListener("change",function(){ 5 | 6 | if (_upFile.files.length === 0) { 7 | // alert("璇烽€夋嫨鍥剧墖"); 8 | return; } 9 | var oFile = _upFile.files[0]; 10 | //if (!rFilter.test(oFile.type)) { alert("You must select a valid image file!"); return; } 11 | 12 | /* if(oFile.size>5*1024*1024){ 13 | message(myCache.par.lang,{cn:"鐓х墖涓婁紶锛氭枃浠朵笉鑳借秴杩�5MB!璇蜂娇鐢ㄥ閲忔洿灏忕殑鐓х墖銆�",en:"璇佷功涓婁紶锛氭枃浠朵笉鑳借秴杩�100K!"}) 14 | 15 | return; 16 | }*/ 17 | if(!new RegExp("(jpg|jpeg|png)+","gi").test(oFile.type)){ 18 | // alert("鐓х墖涓婁紶锛氭枃浠剁被鍨嬪繀椤绘槸JPG銆丣PEG銆丳NG"); 19 | return; 20 | } 21 | 22 | var reader = new FileReader(); 23 | reader.onload = function(e) { 24 | var base64Img= e.target.result; 25 | //鍘嬬缉鍓嶉瑙� 26 | // $("#preview").attr("src",base64Img); 27 | 28 | //--鎵цresize銆� 29 | var _ir=ImageResizer({ 30 | resizeMode:"auto" 31 | ,dataSource:base64Img 32 | ,dataSourceType:"base64" 33 | ,maxWidth:1200 //鍏佽鐨勬渶澶у搴� 34 | ,maxHeight:600 //鍏佽鐨勬渶澶ч珮搴︺€� 35 | ,onTmpImgGenerate:function(img){ 36 | 37 | } 38 | ,success:function(resizeImgBase64,canvas){ 39 | //鍘嬬缉鍚庨瑙� 40 | $("#nextview").attr("src",resizeImgBase64); 41 | 42 | //璧嬪€煎埌闅愯棌鍩熶紶缁欏悗鍙� 43 | $('#img').val(resizeImgBase64.substr(23)); 44 | 45 | 46 | 47 | } 48 | ,debug:true 49 | }); 50 | 51 | }; 52 | reader.readAsDataURL(oFile); 53 | 54 | },false); 55 | 56 | }); -------------------------------------------------------------------------------- /public/skeleton.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Skeleton V2.0.4 3 | * Copyright 2014, Dave Gamache 4 | * www.getskeleton.com 5 | * Free to use under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 12/29/2014 8 | */ 9 | 10 | 11 | /* Table of contents 12 | –––––––––––––––––––––––––––––––––––––––––––––––––– 13 | - Grid 14 | - Base Styles 15 | - Typography 16 | - Links 17 | - Buttons 18 | - Forms 19 | - Lists 20 | - Code 21 | - Tables 22 | - Spacing 23 | - Utilities 24 | - Clearing 25 | - Media Queries 26 | */ 27 | 28 | 29 | /* Grid 30 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 31 | .container { 32 | position: relative; 33 | width: 100%; 34 | max-width: 960px; 35 | margin: 0 auto; 36 | /* padding: 0 20px; */ 37 | box-sizing: border-box; } 38 | .column, 39 | .columns { 40 | width: 100%; 41 | float: left; 42 | box-sizing: border-box; } 43 | 44 | /* For devices larger than 400px */ 45 | @media (min-width: 400px) { 46 | .container { 47 | width: 85%; 48 | padding: 0; } 49 | } 50 | 51 | /* For devices larger than 550px */ 52 | @media (min-width: 550px) { 53 | .container { 54 | width: 80%; } 55 | .column, 56 | .columns { 57 | margin-left: 4%; } 58 | .column:first-child, 59 | .columns:first-child { 60 | margin-left: 0; } 61 | 62 | .one.column, 63 | .one.columns { width: 4.66666666667%; } 64 | .two.columns { width: 13.3333333333%; } 65 | .three.columns { width: 22%; } 66 | .four.columns { width: 30.6666666667%; } 67 | .five.columns { width: 39.3333333333%; } 68 | .six.columns { width: 48%; } 69 | .seven.columns { width: 56.6666666667%; } 70 | .eight.columns { width: 65.3333333333%; } 71 | .nine.columns { width: 74.0%; } 72 | .ten.columns { width: 82.6666666667%; } 73 | .eleven.columns { width: 91.3333333333%; } 74 | .twelve.columns { width: 100%; margin-left: 0; } 75 | 76 | .one-third.column { width: 30.6666666667%; } 77 | .two-thirds.column { width: 65.3333333333%; } 78 | 79 | .one-half.column { width: 48%; } 80 | 81 | /* Offsets */ 82 | .offset-by-one.column, 83 | .offset-by-one.columns { margin-left: 8.66666666667%; } 84 | .offset-by-two.column, 85 | .offset-by-two.columns { margin-left: 17.3333333333%; } 86 | .offset-by-three.column, 87 | .offset-by-three.columns { margin-left: 26%; } 88 | .offset-by-four.column, 89 | .offset-by-four.columns { margin-left: 34.6666666667%; } 90 | .offset-by-five.column, 91 | .offset-by-five.columns { margin-left: 43.3333333333%; } 92 | .offset-by-six.column, 93 | .offset-by-six.columns { margin-left: 52%; } 94 | .offset-by-seven.column, 95 | .offset-by-seven.columns { margin-left: 60.6666666667%; } 96 | .offset-by-eight.column, 97 | .offset-by-eight.columns { margin-left: 69.3333333333%; } 98 | .offset-by-nine.column, 99 | .offset-by-nine.columns { margin-left: 78.0%; } 100 | .offset-by-ten.column, 101 | .offset-by-ten.columns { margin-left: 86.6666666667%; } 102 | .offset-by-eleven.column, 103 | .offset-by-eleven.columns { margin-left: 95.3333333333%; } 104 | 105 | .offset-by-one-third.column, 106 | .offset-by-one-third.columns { margin-left: 34.6666666667%; } 107 | .offset-by-two-thirds.column, 108 | .offset-by-two-thirds.columns { margin-left: 69.3333333333%; } 109 | 110 | .offset-by-one-half.column, 111 | .offset-by-one-half.columns { margin-left: 52%; } 112 | 113 | } 114 | 115 | 116 | /* Base Styles 117 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 118 | /* NOTE 119 | html is set to 62.5% so that all the REM measurements throughout Skeleton 120 | are based on 10px sizing. So basically 1.5rem = 15px :) */ 121 | html { 122 | font-size: 62.5%; } 123 | body { 124 | font-size: 1.5em; /* currently ems cause chrome bug misinterpreting rems on body element */ 125 | line-height: 1.6; 126 | font-weight: 400; 127 | font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; 128 | color: #222; } 129 | 130 | 131 | /* Typography 132 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 133 | h1, h2, h3, h4, h5, h6 { 134 | margin-top: 0; 135 | margin-bottom: 2rem; 136 | font-weight: 300; } 137 | h1 { font-size: 4.0rem; line-height: 1.2; letter-spacing: -.1rem;} 138 | h2 { font-size: 3.6rem; line-height: 1.25; letter-spacing: -.1rem; } 139 | h3 { font-size: 3.0rem; line-height: 1.3; letter-spacing: -.1rem; } 140 | h4 { font-size: 2.4rem; line-height: 1.35; letter-spacing: -.08rem; } 141 | h5 { font-size: 1.8rem; line-height: 1.5; letter-spacing: -.05rem; } 142 | h6 { font-size: 1.5rem; line-height: 1.6; letter-spacing: 0; } 143 | 144 | /* Larger than phablet */ 145 | @media (min-width: 550px) { 146 | h1 { font-size: 5.0rem; } 147 | h2 { font-size: 4.2rem; } 148 | h3 { font-size: 3.6rem; } 149 | h4 { font-size: 3.0rem; } 150 | h5 { font-size: 2.4rem; } 151 | h6 { font-size: 1.5rem; } 152 | } 153 | 154 | p { 155 | margin-top: 0; } 156 | 157 | 158 | /* Links 159 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 160 | a { 161 | color: #1EAEDB; } 162 | a:hover { 163 | color: #0FA0CE; } 164 | 165 | 166 | /* Buttons 167 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 168 | .button, 169 | button, 170 | input[type="submit"], 171 | input[type="reset"], 172 | input[type="button"] { 173 | display: inline-block; 174 | height: 38px; 175 | padding: 0 30px; 176 | color: #555; 177 | text-align: center; 178 | font-size: 11px; 179 | font-weight: 600; 180 | line-height: 38px; 181 | letter-spacing: .1rem; 182 | text-transform: uppercase; 183 | text-decoration: none; 184 | white-space: nowrap; 185 | background-color: transparent; 186 | border-radius: 4px; 187 | border: 1px solid #bbb; 188 | cursor: pointer; 189 | box-sizing: border-box; } 190 | .button:hover, 191 | button:hover, 192 | input[type="submit"]:hover, 193 | input[type="reset"]:hover, 194 | input[type="button"]:hover, 195 | .button:focus, 196 | button:focus, 197 | input[type="submit"]:focus, 198 | input[type="reset"]:focus, 199 | input[type="button"]:focus { 200 | color: #333; 201 | border-color: #888; 202 | outline: 0; } 203 | .button.button-primary, 204 | button.button-primary, 205 | input[type="submit"].button-primary, 206 | input[type="reset"].button-primary, 207 | input[type="button"].button-primary { 208 | color: #FFF; 209 | background-color: #33C3F0; 210 | border-color: #33C3F0; } 211 | .button.button-primary:hover, 212 | button.button-primary:hover, 213 | input[type="submit"].button-primary:hover, 214 | input[type="reset"].button-primary:hover, 215 | input[type="button"].button-primary:hover, 216 | .button.button-primary:focus, 217 | button.button-primary:focus, 218 | input[type="submit"].button-primary:focus, 219 | input[type="reset"].button-primary:focus, 220 | input[type="button"].button-primary:focus { 221 | color: #FFF; 222 | background-color: #1EAEDB; 223 | border-color: #1EAEDB; } 224 | 225 | 226 | /* Forms 227 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 228 | input[type="email"], 229 | input[type="number"], 230 | input[type="search"], 231 | input[type="text"], 232 | input[type="tel"], 233 | input[type="url"], 234 | input[type="password"], 235 | textarea, 236 | select { 237 | height: 38px; 238 | padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */ 239 | background-color: #fff; 240 | border: 1px solid #D1D1D1; 241 | border-radius: 4px; 242 | box-shadow: none; 243 | box-sizing: border-box; } 244 | /* Removes awkward default styles on some inputs for iOS */ 245 | input[type="email"], 246 | input[type="number"], 247 | input[type="search"], 248 | input[type="text"], 249 | input[type="tel"], 250 | input[type="url"], 251 | input[type="password"], 252 | textarea { 253 | -webkit-appearance: none; 254 | -moz-appearance: none; 255 | appearance: none; } 256 | textarea { 257 | min-height: 65px; 258 | padding-top: 6px; 259 | padding-bottom: 6px; } 260 | input[type="email"]:focus, 261 | input[type="number"]:focus, 262 | input[type="search"]:focus, 263 | input[type="text"]:focus, 264 | input[type="tel"]:focus, 265 | input[type="url"]:focus, 266 | input[type="password"]:focus, 267 | textarea:focus, 268 | select:focus { 269 | border: 1px solid #33C3F0; 270 | outline: 0; } 271 | label, 272 | legend { 273 | display: block; 274 | margin-bottom: .5rem; 275 | font-weight: 600; } 276 | fieldset { 277 | padding: 0; 278 | border-width: 0; } 279 | input[type="checkbox"], 280 | input[type="radio"] { 281 | display: inline; } 282 | label > .label-body { 283 | display: inline-block; 284 | margin-left: .5rem; 285 | font-weight: normal; } 286 | 287 | 288 | /* Lists 289 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 290 | ul { 291 | list-style: circle inside; } 292 | ol { 293 | list-style: decimal inside; } 294 | ol, ul { 295 | padding-left: 0; 296 | margin-top: 0; } 297 | ul ul, 298 | ul ol, 299 | ol ol, 300 | ol ul { 301 | margin: 1.5rem 0 1.5rem 3rem; 302 | font-size: 90%; } 303 | li { 304 | margin-bottom: 1rem; } 305 | 306 | 307 | /* Code 308 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 309 | code { 310 | padding: .2rem .5rem; 311 | margin: 0 .2rem; 312 | font-size: 90%; 313 | white-space: nowrap; 314 | background: #F1F1F1; 315 | border: 1px solid #E1E1E1; 316 | border-radius: 4px; } 317 | pre > code { 318 | display: block; 319 | padding: 1rem 1.5rem; 320 | white-space: pre; } 321 | 322 | 323 | /* Tables 324 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 325 | th, 326 | td { 327 | padding: 12px 15px; 328 | text-align: left; 329 | border-bottom: 1px solid #E1E1E1; } 330 | th:first-child, 331 | td:first-child { 332 | padding-left: 0; } 333 | th:last-child, 334 | td:last-child { 335 | padding-right: 0; } 336 | 337 | 338 | /* Spacing 339 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 340 | button, 341 | .button { 342 | margin-bottom: 1rem; } 343 | input, 344 | textarea, 345 | select, 346 | fieldset { 347 | margin-bottom: 1.5rem; } 348 | pre, 349 | blockquote, 350 | dl, 351 | figure, 352 | table, 353 | p, 354 | ul, 355 | ol, 356 | form { 357 | margin-bottom: 2.5rem; } 358 | 359 | 360 | /* Utilities 361 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 362 | .u-full-width { 363 | width: 100%; 364 | box-sizing: border-box; } 365 | .u-max-full-width { 366 | max-width: 100%; 367 | box-sizing: border-box; } 368 | .u-pull-right { 369 | float: right; } 370 | .u-pull-left { 371 | float: left; } 372 | 373 | 374 | /* Misc 375 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 376 | hr { 377 | margin-top: 3rem; 378 | margin-bottom: 3.5rem; 379 | border-width: 0; 380 | border-top: 1px solid #E1E1E1; } 381 | 382 | 383 | /* Clearing 384 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 385 | 386 | /* Self Clearing Goodness */ 387 | .container:after, 388 | .row:after, 389 | .u-cf { 390 | content: ""; 391 | display: table; 392 | clear: both; } 393 | 394 | 395 | /* Media Queries 396 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 397 | /* 398 | Note: The best way to structure the use of media queries is to create the queries 399 | near the relevant code. For example, if you wanted to change the styles for buttons 400 | on small devices, paste the mobile query code up in the buttons section and style it 401 | there. 402 | */ 403 | 404 | 405 | /* Larger than mobile */ 406 | @media (min-width: 400px) {} 407 | 408 | /* Larger than phablet (also point when grid becomes active) */ 409 | @media (min-width: 550px) {} 410 | 411 | /* Larger than tablet */ 412 | @media (min-width: 750px) {} 413 | 414 | /* Larger than desktop */ 415 | @media (min-width: 1000px) {} 416 | 417 | /* Larger than Desktop HD */ 418 | @media (min-width: 1200px) {} 419 | -------------------------------------------------------------------------------- /public/tools.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 杩欐槸鍩轰簬html5鐨勫墠绔浘鐗囧伐鍏凤紝鍘嬬缉宸ュ叿銆� 3 | */ 4 | var ImageResizer=function(opts){ 5 | var settings={ 6 | resizeMode:"auto"//鍘嬬缉妯″紡锛屾€诲叡鏈変笁绉� auto,width,height auto琛ㄧず鑷姩鏍规嵁鏈€澶х殑瀹藉害鍙婇珮搴︾瓑姣斿帇缂╋紝width琛ㄧず鍙牴鎹搴︽潵鍒ゆ柇鏄惁闇€瑕佺瓑姣斾緥鍘嬬缉锛宧eight绫讳技銆� 7 | ,dataSource:"" //鏁版嵁婧愩€傛暟鎹簮鏄寚闇€瑕佸帇缂╃殑鏁版嵁婧愶紝鏈変笁绉嶇被鍨嬶紝image鍥剧墖鍏冪礌锛宐ase64瀛楃涓诧紝canvas瀵硅薄锛岃繕鏈夐€夋嫨鏂囦欢鏃跺€欑殑file瀵硅薄銆傘€傘€� 8 | ,dataSourceType:"image" //image base64 canvas 9 | ,maxWidth:150 //鍏佽鐨勬渶澶у搴� 10 | ,maxHeight:200 //鍏佽鐨勬渶澶ч珮搴︺€� 11 | ,onTmpImgGenerate:function(img){} //褰撲腑闂村浘鐗囩敓鎴愭椂鍊欑殑鎵ц鏂规硶銆傘€傝繖涓椂鍊欒涓嶈涔变慨鏀硅繖鍥剧墖锛屽惁鍒欎細鎵撲贡鍘嬬缉鍚庣殑缁撴灉銆� 12 | ,success:function(resizeImgBase64,canvas){ 13 | 14 | }//鍘嬬缉鎴愬姛鍚庡浘鐗囩殑base64瀛楃涓叉暟鎹€� 15 | ,debug:false //鏄惁寮€鍚皟璇曟ā寮忋€� 16 | 17 | }; 18 | var appData={}; 19 | $.extend(settings,opts); 20 | 21 | var _debug=function(str,styles){ 22 | if(settings.debug==true){ 23 | if(styles){ 24 | console.log(str,styles); 25 | } 26 | else{ 27 | console.log(str); 28 | } 29 | } 30 | }; 31 | var innerTools={ 32 | getBase4FromImgFile:function(file,callBack){ 33 | 34 | var reader = new FileReader(); 35 | reader.onload = function(e) { 36 | var base64Img= e.target.result; 37 | //var $img = $('').attr("src", e.target.result) 38 | //$('#preview').empty().append($img) 39 | if(callBack){ 40 | callBack(base64Img); 41 | } 42 | }; 43 | reader.readAsDataURL(file); 44 | } 45 | 46 | //--澶勭悊鏁版嵁婧愩€傘€傘€傘€傚皢鎵€鏈夋暟鎹簮閮藉鐞嗘垚涓哄浘鐗囧浘鐗囧璞★紝鏂逛究澶勭悊銆� 47 | ,getImgFromDataSource:function(datasource,dataSourceType,callback){ 48 | var _me=this; 49 | var img1=new Image(); 50 | if(dataSourceType=="img"||dataSourceType=="image"){ 51 | img1.src=$(datasource).attr("src"); 52 | if(callback){ 53 | callback(img1); 54 | } 55 | } 56 | else if(dataSourceType=="base64"){ 57 | img1.src=datasource; 58 | if(callback){ 59 | callback(img1); 60 | } } 61 | else if(dataSourceType=="canvas"){ 62 | img1.src = datasource.toDataURL("image/jpeg"); 63 | if(callback){ 64 | callback(img1); 65 | } 66 | } 67 | else if(dataSourceType=="file"){ 68 | _me.getBase4FromImgFile(function(base64str){ 69 | img1.src=base64str; 70 | if(callback){ 71 | callback(img1); 72 | } 73 | }); 74 | } 75 | 76 | } 77 | //璁$畻鍥剧墖鐨勯渶瑕佸帇缂╃殑灏哄銆傚綋鐒讹紝鍘嬬缉妯″紡锛屽帇缂╅檺鍒剁洿鎺ヤ粠setting閲岄潰鍙栧嚭鏉ャ€� 78 | ,getResizeSizeFromImg:function(img){ 79 | var _img_info={ 80 | w:$(img)[0].naturalWidth, 81 | h:$(img)[0].naturalHeight 82 | }; 83 | console.log("鐪熷疄灏哄锛�"); 84 | console.log(_img_info); 85 | var _resize_info={ 86 | w:0 87 | ,h:0 88 | }; 89 | if(_img_info.w<=settings.maxWidth&&_img_info.h<=settings.maxHeight){ 90 | return _img_info; 91 | } 92 | if(settings.resizeMode=="auto"){ 93 | var _percent_scale=parseFloat(_img_info.w/_img_info.h); 94 | var _size1={ 95 | w:0 96 | ,h:0 97 | }; 98 | var _size_by_mw={ 99 | w:settings.maxWidth 100 | ,h:parseInt(settings.maxWidth/_percent_scale) 101 | }; 102 | var _size_by_mh={ 103 | w:parseInt(settings.maxHeight*_percent_scale) 104 | ,h:settings.maxHeight 105 | }; 106 | if(_size_by_mw.h<=settings.maxHeight){ 107 | return _size_by_mw; 108 | } 109 | if(_size_by_mh.w<=settings.maxWidth){ 110 | return _size_by_mh; 111 | } 112 | 113 | return { 114 | w:settings.maxWidth 115 | ,h:settings.maxHeight 116 | }; 117 | 118 | } 119 | if(settings.resizeMode=="width"){ 120 | if(_img_info.w<=settings.maxWidth){ 121 | return _img_info; 122 | } 123 | var _size_by_mw={ 124 | w:settings.maxWidth 125 | ,h:parseInt(settings.maxWidth/_percent_scale) 126 | }; 127 | return _size_by_mw; 128 | } 129 | 130 | if(settings.resizeMode=="height"){ 131 | if(_img_info.h<=settings.maxHeight){ 132 | 133 | return _img_info; 134 | } 135 | var _size_by_mh={ 136 | w:parseInt(settings.maxHeight*_percent_scale) 137 | ,h:settings.maxHeight 138 | }; 139 | return _size_by_mh; 140 | } 141 | 142 | } 143 | //--灏嗙浉鍏冲浘鐗囧璞$敾鍒癱anvas閲岄潰鍘汇€� 144 | ,drawToCanvas:function(img,theW,theH,realW,realH,callback){ 145 | 146 | var canvas = document.createElement("canvas"); 147 | canvas.width=theW; 148 | canvas.height=theH; 149 | var ctx = canvas.getContext('2d'); 150 | ctx.drawImage(img, 151 | 0,//sourceX, 152 | 0,//sourceY, 153 | realW,//sourceWidth, 154 | realH,//sourceHeight, 155 | 0,//destX, 156 | 0,//destY, 157 | theW,//destWidth, 158 | theH//destHeight 159 | ); 160 | 161 | //--鑾峰彇base64瀛楃涓插強canvas瀵硅薄浼犵粰success鍑芥暟銆� 162 | var base64str=canvas.toDataURL("image/jpeg"); 163 | if(callback){ 164 | callback(base64str,canvas); 165 | } 166 | } 167 | }; 168 | 169 | //--寮€濮嬪鐞嗐€� 170 | (function(){ 171 | innerTools.getImgFromDataSource(settings.dataSource,settings.dataSourceType,function(_tmp_img){ 172 | 173 | setTimeout(function(){ 174 | var __tmpImg=_tmp_img; 175 | settings.onTmpImgGenerate(_tmp_img); 176 | //--璁$畻灏哄銆� 177 | var _limitSizeInfo=innerTools.getResizeSizeFromImg(__tmpImg); 178 | console.log(_limitSizeInfo); 179 | var _img_info={ 180 | w:$(__tmpImg)[0].naturalWidth, 181 | h:$(__tmpImg)[0].naturalHeight 182 | }; 183 | 184 | innerTools.drawToCanvas(__tmpImg,_limitSizeInfo.w,_limitSizeInfo.h,_img_info.w,_img_info.h,function(base64str,canvas){ 185 | settings.success(base64str,canvas); 186 | }); 187 | },1000); 188 | 189 | 190 | }); 191 | })(); 192 | 193 | var returnObject={ 194 | 195 | 196 | }; 197 | 198 | return returnObject; 199 | }; -------------------------------------------------------------------------------- /routers/comments.js: -------------------------------------------------------------------------------- 1 | const RateLimit = require('koa2-ratelimit').RateLimit; 2 | const router = require('koa-router')(); 3 | const userModel = require('../lib/mysql.js') 4 | const config = require('../config/info.js') 5 | const checkNotLogin = require('../middlewares/check.js').checkNotLogin 6 | const checkLogin = require('../middlewares/check.js').checkLogin; 7 | const moment = require('moment') 8 | const tc = require('text-censor') 9 | const nodemailer = require('nodemailer') 10 | 11 | const mailTransport = nodemailer.createTransport({ 12 | host: config.stmpHost, 13 | port: config.stmpPort, 14 | secureConnection: true, // 使用SSL方式(安全方式,防止被窃取信息) 15 | auth: { 16 | user: config.stmpEmail, 17 | pass: config.stmpEmailPass 18 | }, 19 | }); 20 | 21 | 22 | const commentLimiter = RateLimit.middleware({ 23 | interval: 10 * 60 * 1000, // 10min 24 | delayAfter: 1, // begin slowing down responses after the first request 25 | timeWait: 3 * 1000, // slow down subsequent responses by 3 seconds per request 26 | max: 5, // start blocking after 5 requests 27 | prefixKey: 'post/comment/:link/push', // to allow the bdd to Differentiate the endpoint 28 | message: "Too many accounts created from this IP, please try again after 10min" 29 | }); 30 | 31 | // post 提交评论 32 | router.post('/comment/:link/push', commentLimiter, async (ctx, next) => { 33 | let name = ctx.request.body.name, 34 | email = ctx.request.body.email, 35 | content = ctx.request.body.content, 36 | website = ctx.request.body.website, 37 | reply = ctx.request.body.reply, 38 | replyuser = '', 39 | replyemail = '', 40 | link = ctx.params.link, 41 | type = 'post', 42 | time = moment().format('YYYY-MM-DD HH:mm:ss'), 43 | newName = name.replace(/[<">']/g, (target) => { 44 | return { 45 | '<': '<', 46 | '"': '"', 47 | '>': '>', 48 | "'": ''' 49 | }[target] 50 | }), 51 | newContent = content.replace(/[<">']/g, (target) => { 52 | return { 53 | '<': '<', 54 | '"': '"', 55 | '>': '>', 56 | "'": ''' 57 | }[target] 58 | }); 59 | let testNum = /^[1-9]+[0-9]*]*$/; 60 | if(!testNum.test(link)){ 61 | type = 'page'; 62 | 63 | } 64 | await userModel.findCommentInfo(reply, link) 65 | .then(result => { 66 | if (result.length != 0) { 67 | replyuser = result[0].name; 68 | replyemail = result[0].email; 69 | console.log(result) 70 | } else { 71 | reply = 0 72 | } 73 | }) 74 | tc.filter(newName, function (err, censored) { 75 | newName = censored 76 | }) 77 | tc.filter(newContent, function (err, censored) { 78 | newContent = censored 79 | }) 80 | // console.log([newName, email, website, newContent, link, reply, replyuser, time]) 81 | // let reg = /[a-zA-Z0-9_]{1,10}/; 82 | let reg = /^\d*([a-zA-Z])+\d*$/; 83 | let urlreg = /^$|^([hH][tT]{2}[pP]:\/\/|[hH][tT]{2}[pP][sS]:\/\/)(([A-Za-z0-9-~]+)\.)+([A-Za-z0-9-~\/])+$/; 84 | let ereg = /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/; 85 | // [\u4e00-\u9fa5_a-zA-Z0-9_]{1,10} 86 | 87 | 88 | if(type == 'post'){ 89 | mailOptions = { 90 | from: '"'+config.myUsername+'" <'+config.stmpEmail+'>', 91 | to: config.myEmail, 92 | subject: config.websiteTitle+' - 你有一条评论', 93 | text: '您的博客有一条新评论,来自用户' + name + ':' + content + ' 文章地址为:'+config.domain+'/post/'+link, 94 | }; 95 | }else{ 96 | mailOptions = { 97 | from: '"'+config.myUsername+'" <'+config.stmpEmail+'>', 98 | to: config.myEmail, 99 | subject: config.websiteTitle+' - 你有一条评论', 100 | text: '您的博客有一条新评论,来自用户' + name + ':' + content + ' 页面地址为:'+config.domain+'/s/'+link, 101 | }; 102 | } 103 | if (!urlreg.test(website) || !ereg.test(email) || newName == '') { 104 | ctx.body = false 105 | } else { 106 | await userModel.createComment([newName, email, website, newContent, link, reply, replyuser, time]) 107 | .then(() => { 108 | ctx.body = true 109 | }).catch(() => { 110 | ctx.body = false 111 | }) 112 | if (ctx.session.user) { 113 | if(type == 'post'){ 114 | mailOptions = { 115 | from: '"'+config.myUsername+'" <'+config.stmpEmail+'>', 116 | to: replyemail, 117 | subject: config.websiteTitle+' - 你有一条回复评论', 118 | text: '您有一条回复评论 文章地址为:'+config.domain+'/post/'+link, 119 | }; 120 | }else{ 121 | mailOptions = { 122 | from: '"'+config.myUsername+'" <'+config.stmpEmail+'>', 123 | to: replyemail, 124 | subject: config.websiteTitle+' - 你有一条回复评论', 125 | text: '您有一条回复评论 页面地址为:'+config.domain+'/s/'+link, 126 | }; 127 | } 128 | mailTransport.sendMail(mailOptions, function (err, msg) { 129 | if (err) { 130 | console.log(err); 131 | // res.render('index', { title: err }); 132 | } 133 | else { 134 | console.log(msg); 135 | // res.render('index', { title: "已接收:" + msg.accepted }); 136 | } 137 | }); 138 | } else { 139 | mailTransport.sendMail(mailOptions, function (err, msg) { 140 | if (err) { 141 | console.log(err); 142 | // res.render('index', { title: err }); 143 | } 144 | else { 145 | console.log(msg); 146 | // res.render('index', { title: "已接收:" + msg.accepted }); 147 | } 148 | }); 149 | } 150 | } 151 | }) 152 | 153 | // 删除评论 154 | router.post('/comment/:id/remove', async (ctx, next) => { 155 | let id = ctx.params.id, 156 | allow; 157 | if (ctx.session.user) { 158 | allow = true 159 | } else { 160 | allow = false 161 | } 162 | if (allow) { 163 | await userModel.deleteComments(id) 164 | .then(() => { 165 | ctx.body = { 166 | data: 1 167 | } 168 | }).catch(() => { 169 | ctx.body = { 170 | data: 2 171 | } 172 | }) 173 | } else { 174 | ctx.body = { 175 | data: 3 176 | } 177 | } 178 | }) 179 | module.exports = router -------------------------------------------------------------------------------- /routers/pages.js: -------------------------------------------------------------------------------- 1 | const router = require('koa-router')(); 2 | const userModel = require('../lib/mysql.js') 3 | const checkNotLogin = require('../middlewares/check.js').checkNotLogin 4 | const checkLogin = require('../middlewares/check.js').checkLogin; 5 | const md = require('markdown-it')(); 6 | 7 | // 单页面 8 | router.get('/s/:linkname', async (ctx, next) => { 9 | let res, pagesArr, comres; 10 | await userModel.findPageDataByLink(ctx.params.linkname) 11 | .then(result => { 12 | //console.log(result ) 13 | res = result 14 | console.log(res[0]) 15 | }) 16 | await userModel.findPageInfoById() 17 | .then(result => { 18 | pagesArr = result; 19 | }) 20 | await userModel.findComments(ctx.params.linkname) 21 | .then(result => { 22 | comres = result; 23 | }) 24 | await ctx.render('sPage', { 25 | session: ctx.session, 26 | comments: comres, 27 | comments_length: comres.length, 28 | pagesArr: pagesArr, 29 | pages: res[0] 30 | }) 31 | 32 | }) 33 | 34 | 35 | // 创建页面 36 | router.get('/createpage', async (ctx, next) => { 37 | await checkLogin(ctx) 38 | await ctx.render('createpage', { 39 | session: ctx.session, 40 | }) 41 | }) 42 | 43 | // post 创建新页面 44 | router.post('/createpage', async (ctx, next) => { 45 | let linkname = ctx.request.body.linkname, 46 | title = ctx.request.body.title, 47 | content = ctx.request.body.content, 48 | hascom = ctx.request.body.hascom, 49 | allowEdit = true, 50 | newTitle = title.replace(/[<">']/g, (target) => { 51 | return { 52 | '<': '<', 53 | '"': '"', 54 | '>': '>', 55 | "'": ''' 56 | }[target] 57 | }); 58 | // let reg = /[a-zA-Z0-9_]{1,10}/; 59 | let reg = /^\d*([a-zA-Z])+\d*$/; 60 | // [\u4e00-\u9fa5_a-zA-Z0-9_]{1,10} 61 | // console.log([linkname,name, newTitle, md.render(content), content,typeof hascom]) 62 | 63 | if (!ctx.session.user) { 64 | allowEdit = false 65 | } else { 66 | // allowEdit = true 67 | await userModel.findPageDataByLink(linkname) 68 | .then(result => { 69 | let cln = result; 70 | if (result.length === 0) { 71 | allowEdit = true 72 | } else { 73 | allowEdit = false 74 | } 75 | }) 76 | } 77 | if (linkname.match(reg) === null || hascom.match(reg) === null) { 78 | ctx.body = 'unallow' 79 | } else { 80 | if (allowEdit) { 81 | await userModel.insertPage([linkname.match(reg)[0], newTitle, md.render(content), content, hascom.match(reg)[0]]) 82 | .then(() => { 83 | ctx.body = true 84 | }).catch(() => { 85 | ctx.body = false 86 | }) 87 | } else { 88 | ctx.body = 'error' 89 | } 90 | } 91 | 92 | }) 93 | 94 | // 编辑单页面 95 | router.get('/s/:linkname/edit', async (ctx, next) => { 96 | let name = ctx.session.user, 97 | linkname = ctx.params.linkname, 98 | res; 99 | await checkLogin(ctx) 100 | await userModel.findPageDataByLink(linkname) 101 | .then(result => { 102 | res = result[0]; 103 | console.log(result) 104 | }) 105 | await ctx.render('editpage', { 106 | session: ctx.session, 107 | pagesContent: res.content, 108 | pagesLinkname: res.linkname, 109 | pagesTitle: res.title, 110 | pagesHascom: res.hascom 111 | }) 112 | 113 | }) 114 | 115 | // post 编辑单页面 116 | router.post('/s/:linkname/edit', async (ctx, next) => { 117 | let title = ctx.request.body.title, 118 | content = ctx.request.body.content, 119 | description = ctx.request.body.description, 120 | hascom = ctx.request.body.hascom, 121 | linkname = ctx.params.linkname, 122 | ln = ctx.request.body.linkname, 123 | pageid, 124 | allowEdit = true, 125 | // 现在使用markdown不需要单独转义 126 | newTitle = title.replace(/[<">']/g, (target) => { 127 | return { 128 | '<': '<', 129 | '"': '"', 130 | '>': '>', 131 | "'": ''' 132 | }[target] 133 | }); 134 | // let reg = /[a-zA-Z0-9_]{1,10}/; 135 | let reg = /^\d*([a-zA-Z])+\d*$/; 136 | // console.log(ln.match(reg)) 137 | await userModel.findPageDataByLink(linkname) 138 | .then(res => { 139 | // console.log(res[0].name,ctx.session.user) 140 | if (!ctx.session.user) { 141 | allowEdit = false 142 | } else { 143 | console.log(res[0].id) 144 | pageid = res[0].id 145 | allowEdit = true 146 | } 147 | }) 148 | if (ln.match(reg) === null || hascom.match(reg) === null) { 149 | ctx.body = 'unallow' 150 | } else { 151 | if (allowEdit) { 152 | await userModel.updatePage([ln.match(reg)[0], newTitle, content, md.render(content), hascom.match(reg)[0], pageid]) 153 | .then(() => { 154 | ctx.body = true 155 | }).catch(() => { 156 | ctx.body = false 157 | }) 158 | } else { 159 | ctx.body = 'error' 160 | } 161 | } 162 | }) 163 | 164 | // 删除单页面 165 | router.post('/s/:linkname/remove', async (ctx, next) => { 166 | let linkname = ctx.params.linkname; 167 | if (ctx.session.user) { 168 | await userModel.deleteCommentsByLink(linkname); 169 | await userModel.deletePage(linkname) 170 | .then(() => { 171 | ctx.body = { 172 | data: 1 173 | } 174 | }).catch(() => { 175 | ctx.body = { 176 | data: 2 177 | } 178 | }) 179 | } else { 180 | ctx.body = { 181 | data: 3 182 | } 183 | } 184 | }) 185 | 186 | module.exports = router -------------------------------------------------------------------------------- /routers/posts.js: -------------------------------------------------------------------------------- 1 | const router = require('koa-router')(); 2 | const userModel = require('../lib/mysql.js') 3 | const moment = require('moment') 4 | const checkNotLogin = require('../middlewares/check.js').checkNotLogin 5 | const checkLogin = require('../middlewares/check.js').checkLogin; 6 | const md = require('markdown-it')(); 7 | 8 | 9 | 10 | // 文章页 11 | router.get('/', async (ctx, next) => { 12 | let res, 13 | postsLength, 14 | pagesArr; 15 | await userModel.findPostByPage(1) 16 | .then(result => { 17 | //console.log(result) 18 | res = result 19 | }) 20 | await userModel.findAllPost() 21 | .then(result => { 22 | postsLength = result.length 23 | }) 24 | await userModel.findPageInfoById() 25 | .then(result => { 26 | pagesArr = result; 27 | }) 28 | await ctx.render('posts', { 29 | session: ctx.session, 30 | posts: res, 31 | postsLength: postsLength, 32 | pagesArr: pagesArr, 33 | postsPageLength: Math.ceil(postsLength / 5), 34 | 35 | }) 36 | 37 | }) 38 | 39 | // 首页分页,每次输出10条 40 | router.post('/post/page', async (ctx, next) => { 41 | let page = ctx.request.body.page; 42 | await userModel.findPostByPage(page) 43 | .then(result => { 44 | //console.log(result) 45 | ctx.body = result 46 | }).catch(() => { 47 | ctx.body = 'error' 48 | }) 49 | }) 50 | 51 | // 单篇文章页 52 | router.get('/post/:postId', async (ctx, next) => { 53 | let res, 54 | comres, 55 | pageOne, 56 | res_pv, 57 | pagesArr, 58 | res_summary; 59 | await userModel.findDataById(ctx.params.postId) 60 | .then(result => { 61 | res = result[0] 62 | res_summary = result[0].md.substr(0, 50) 63 | res_pv = parseInt(result[0]['pv']) 64 | res_pv += 1 65 | // console.log(res_pv) 66 | }) 67 | await userModel.findPageInfoById() 68 | .then(result => { 69 | pagesArr = result; 70 | }) 71 | await userModel.findComments(ctx.params.postId) 72 | .then(result => { 73 | comres = result; 74 | }) 75 | await userModel.updatePostPv([res_pv, ctx.params.postId]) 76 | console.log(res.id) 77 | await ctx.render('sPost', { 78 | session: ctx.session, 79 | posts: res, 80 | comments: comres, 81 | comments_length: comres.length, 82 | pagesArr: pagesArr, 83 | pageOne: pageOne, 84 | Summary: res_summary 85 | }) 86 | 87 | }) 88 | 89 | // 发表文章页面 90 | router.get('/create', async (ctx, next) => { 91 | await checkLogin(ctx) 92 | await ctx.render('create', { 93 | session: ctx.session, 94 | }) 95 | }) 96 | 97 | // post 发表文章 98 | router.post('/create', async (ctx, next) => { 99 | let title = ctx.request.body.title, 100 | content = ctx.request.body.content, 101 | time = moment().format('MMM, Do, YYYY'), 102 | allow = true, 103 | // 现在使用markdown不需要单独转义 104 | newContent = content.replace(/[<">']/g, (target) => { 105 | return { 106 | '<': '<', 107 | '"': '"', 108 | '>': '>', 109 | "'": ''' 110 | }[target] 111 | }), 112 | newTitle = title.replace(/[<">']/g, (target) => { 113 | return { 114 | '<': '<', 115 | '"': '"', 116 | '>': '>', 117 | "'": ''' 118 | }[target] 119 | }); 120 | if (ctx.session.user) { 121 | allow = true 122 | } else { 123 | allow = false 124 | } 125 | //console.log([name, newTitle, content, id, time]) 126 | if (allow) { 127 | await userModel.insertPost([newTitle, md.render(content), content, time]) 128 | .then(() => { 129 | ctx.body = true 130 | }).catch(() => { 131 | ctx.body = false 132 | }) 133 | } else { 134 | ctx.body = 'error' 135 | } 136 | 137 | }) 138 | 139 | 140 | 141 | // 编辑单篇文章页面 142 | router.get('/post/:postId/edit', async (ctx, next) => { 143 | let name = ctx.session.user, 144 | postId = ctx.params.postId, 145 | res; 146 | await checkLogin(ctx) 147 | await userModel.findDataById(postId) 148 | .then(result => { 149 | res = result[0] 150 | }) 151 | await ctx.render('edit', { 152 | session: ctx.session, 153 | postsContent: res.md, 154 | postsTitle: res.title 155 | }) 156 | 157 | }) 158 | 159 | // post 编辑单篇文章 160 | router.post('/post/:postId/edit', async (ctx, next) => { 161 | let title = ctx.request.body.title, 162 | content = ctx.request.body.content, 163 | id = ctx.session.id, 164 | postId = ctx.params.postId, 165 | allowEdit = true; 166 | // 现在使用markdown不需要单独转义 167 | newTitle = title.replace(/[<">']/g, (target) => { 168 | return { 169 | '<': '<', 170 | '"': '"', 171 | '>': '>', 172 | "'": ''' 173 | }[target] 174 | }), 175 | newContent = content.replace(/[<">']/g, (target) => { 176 | return { 177 | '<': '<', 178 | '"': '"', 179 | '>': '>', 180 | "'": ''' 181 | }[target] 182 | }); 183 | await userModel.findDataById(postId) 184 | .then(res => { 185 | // console.log(Boolean('ctx.session.user')) 186 | if (res[0].id === postId && ctx.session.user) { 187 | allowEdit = false 188 | } else { 189 | allowEdit = true 190 | } 191 | }) 192 | if (allowEdit) { 193 | await userModel.updatePost([newTitle, md.render(content), content, postId]) 194 | .then(() => { 195 | ctx.body = true 196 | }).catch(() => { 197 | ctx.body = false 198 | }) 199 | } else { 200 | ctx.body = 'error' 201 | } 202 | }) 203 | 204 | // 删除单篇文章 205 | router.post('/post/:postId/remove', async (ctx, next) => { 206 | let postId = ctx.params.postId, 207 | allow; 208 | if (ctx.session.user) { 209 | allow = true 210 | } else { 211 | allow = false 212 | } 213 | if (allow) { 214 | await userModel.deletePost(postId) 215 | .then(() => { 216 | ctx.body = { 217 | data: 1 218 | } 219 | }).catch(() => { 220 | ctx.body = { 221 | data: 2 222 | } 223 | }) 224 | await userModel.deleteCommentsByLink(postId); 225 | } else { 226 | ctx.body = { 227 | data: 3 228 | } 229 | } 230 | }) 231 | 232 | 233 | module.exports = router -------------------------------------------------------------------------------- /routers/signin.js: -------------------------------------------------------------------------------- 1 | const RateLimit = require('koa2-ratelimit').RateLimit; 2 | const router = require('koa-router')(); 3 | const userModel = require('../lib/mysql.js') 4 | const md5 = require('md5') 5 | const checkNotLogin = require('../middlewares/check.js').checkNotLogin 6 | const checkLogin = require('../middlewares/check.js').checkLogin 7 | const fs = require('fs') 8 | const captcha = require('trek-captcha') 9 | 10 | const getloginimiter = RateLimit.middleware({ 11 | interval: 15*60*1000, // 15 minutes 12 | max: 100, 13 | prefixKey: 'get/signin' // to allow the bdd to Differentiate the endpoint 14 | }); 15 | 16 | const loginLimiter = RateLimit.middleware({ 17 | interval: 10*60*1000, // 10min 18 | delayAfter: 1, // begin slowing down responses after the first request 19 | timeWait: 3*1000, // slow down subsequent responses by 3 seconds per request 20 | max: 5, // start blocking after 5 requests 21 | prefixKey: 'post/signin', // to allow the bdd to Differentiate the endpoint 22 | message: "Too many accounts created from this IP, please try again after 10min" 23 | }); 24 | 25 | router.get('/signin', getloginimiter, async(ctx, next) => { 26 | await checkNotLogin(ctx) 27 | const { token, buffer } = await captcha() 28 | // fs.createWriteStream('public/code.gif').on('finish', () => console.log(token)).end(buffer); 29 | console.log(token) 30 | let codeBase64 = buffer.toString('base64'); 31 | ctx.session.code = token 32 | await ctx.render('signin', { 33 | session: ctx.session, 34 | code:codeBase64 35 | }) 36 | console.log(ctx.session) 37 | }) 38 | 39 | router.post('/signin', loginLimiter, async(ctx, next) => { 40 | console.log(ctx.request.body) 41 | let name = ctx.request.body.name; 42 | let pass = ctx.request.body.password; 43 | let code = ctx.request.body.code; 44 | await userModel.findDataByName(name) 45 | .then(result => { 46 | let res = result; 47 | if(code!=ctx.session.code){ 48 | ctx.body = 0 49 | console.log('验证码错误') 50 | } 51 | else if (name === res[0]['name'] && md5(pass) === res[0]['pass'] ) { 52 | ctx.body = true 53 | ctx.session.user = res[0]['name'] 54 | ctx.session.id = res[0]['id'] 55 | delete ctx.session.code; 56 | console.log('ctx.session.id', ctx.session.id) 57 | console.log('session', ctx.session) 58 | console.log('登录成功') 59 | }else{ 60 | ctx.body = false 61 | console.log('登录失败') 62 | } 63 | }).catch(err => { 64 | console.log(err) 65 | }) 66 | 67 | }) 68 | 69 | module.exports = router -------------------------------------------------------------------------------- /routers/signout.js: -------------------------------------------------------------------------------- 1 | const router = require('koa-router')(); 2 | 3 | router.get('/signout', async(ctx, next) => { 4 | ctx.session = null; 5 | console.log('登出成功') 6 | ctx.body = true 7 | }) 8 | 9 | module.exports = router -------------------------------------------------------------------------------- /routers/upload.js: -------------------------------------------------------------------------------- 1 | const router = require('koa-router')(); 2 | const userModel = require('../lib/mysql.js') 3 | const moment = require('moment') 4 | const checkNotLogin = require('../middlewares/check.js').checkNotLogin 5 | const checkLogin = require('../middlewares/check.js').checkLogin; 6 | const fs = require('fs') 7 | 8 | //上传图片页面 9 | router.get('/uploadimg', async (ctx, next) => { 10 | await checkLogin(ctx) 11 | await ctx.render('uploadimg', { 12 | session: ctx.session, 13 | }) 14 | }) 15 | 16 | // post 上传图片 17 | router.post('/uploadimg/upload', async (ctx, next) => { 18 | let img = ctx.request.body.img, 19 | imgname = moment().unix(), 20 | time = moment().format('YYYY-MM-DD HH:mm:ss'), 21 | allowEdit = true; 22 | if (!ctx.session.user) { 23 | allowEdit = false 24 | } else { 25 | allowEdit = true 26 | } 27 | if (allowEdit) { 28 | let imgBuffer = new Buffer(img, 'base64'); 29 | // console.log(imgBuffer) 30 | fs.createWriteStream('public/images/' + imgname + '.gif').on('finish', () => { 31 | }).end(imgBuffer); 32 | await userModel.uploadImg([imgname, time]) 33 | .then(() => { 34 | ctx.body = { 35 | status: true, 36 | imgurl: '![](/images/' + imgname + '.gif)' 37 | } 38 | }).catch(() => { 39 | console.log('upload_img_error') 40 | }) 41 | 42 | } else { 43 | ctx.body = { 44 | status: false 45 | } 46 | } 47 | }) 48 | 49 | //图片管理页面 50 | router.get('/img', async (ctx, next) => { 51 | let res, 52 | imgsLength; 53 | await checkLogin(ctx) 54 | await userModel.findImgByPage(1) 55 | .then(result => { 56 | //console.log(result) 57 | res = result 58 | }) 59 | await userModel.findAllImgs() 60 | .then(result => { 61 | imgsLength = result.length 62 | }) 63 | await ctx.render('img', { 64 | session: ctx.session, 65 | imgs: res, 66 | imgsLength: imgsLength, 67 | imgsPageLength: Math.ceil(imgsLength / 10), 68 | }) 69 | }) 70 | 71 | 72 | // 分页,每次输出10条 73 | router.post('/img/page', async (ctx, next) => { 74 | let page = ctx.request.body.page; 75 | await userModel.findImgByPage(page) 76 | .then(result => { 77 | //console.log(result) 78 | ctx.body = result 79 | }).catch(() => { 80 | ctx.body = 'error' 81 | }) 82 | }) 83 | 84 | // post 删除图片 85 | router.post('/img/delete', async (ctx, next) => { 86 | let id = ctx.request.body.id, 87 | name = ctx.request.body.name 88 | allowEdit = true; 89 | if (!ctx.session.user) { 90 | allowEdit = false 91 | } else { 92 | allowEdit = true 93 | } 94 | if (allowEdit) { 95 | await userModel.deleteImg(id) 96 | .then(() => { 97 | fs.unlink('public/images/'+name+'.gif',function (err) { 98 | if(err) throw err; 99 | console.log('删除成功') 100 | }) 101 | ctx.body = true 102 | }).catch(() => { 103 | ctx.body = false 104 | }) 105 | 106 | } else { 107 | ctx.body = false 108 | } 109 | }) 110 | 111 | //相册页面 112 | router.get('/photo', async (ctx, next) => { 113 | let res, 114 | photosLength,pagesArr; 115 | // await checkLogin(ctx) 116 | await userModel.findPageInfoById() 117 | .then(result => { 118 | pagesArr = result; 119 | }) 120 | await userModel.findPhotoByPage(1) 121 | .then(result => { 122 | //console.log(result) 123 | res = result 124 | }) 125 | await userModel.findAllPhotos() 126 | .then(result => { 127 | photosLength = result.length 128 | }) 129 | await ctx.render('photo', { 130 | session: ctx.session, 131 | imgs: res, 132 | pagesArr:pagesArr, 133 | photosLength: photosLength, 134 | photosPageLength: Math.ceil(photosLength / 5), 135 | }) 136 | }) 137 | 138 | //上传相册图片页面 139 | router.get('/uploadphoto', async (ctx, next) => { 140 | await checkLogin(ctx) 141 | await ctx.render('uploadphoto', { 142 | session: ctx.session, 143 | }) 144 | }) 145 | 146 | // post 上传相册图片 147 | router.post('/uploadphoto/upload', async (ctx, next) => { 148 | let img = ctx.request.body.img, 149 | imgname = moment().unix(), 150 | title = ctx.request.body.title, 151 | time = moment().format('YYYY-MM-DD HH:mm:ss'), 152 | allowEdit = true; 153 | if (!ctx.session.user) { 154 | allowEdit = false 155 | } else { 156 | allowEdit = true 157 | } 158 | if (allowEdit) { 159 | let imgBuffer = new Buffer(img, 'base64'); 160 | // console.log(imgBuffer) 161 | fs.createWriteStream('public/photos/' + imgname + '.gif').on('finish', () => { 162 | }).end(imgBuffer); 163 | await userModel.uploadPhoto([imgname, title,time]) 164 | .then(() => { 165 | ctx.body = { 166 | status: true 167 | } 168 | }).catch(() => { 169 | console.log('upload_img_error') 170 | }) 171 | 172 | } else { 173 | ctx.body = { 174 | status: false 175 | } 176 | } 177 | }) 178 | 179 | // 相册分页,每次输出10条 180 | router.post('/photo/page', async (ctx, next) => { 181 | let page = ctx.request.body.page; 182 | await userModel.findPhotoByPage(page) 183 | .then(result => { 184 | //console.log(result) 185 | ctx.body = result 186 | }).catch(() => { 187 | ctx.body = 'error' 188 | }) 189 | }) 190 | 191 | // post 删除相册图片 192 | router.post('/photo/delete', async (ctx, next) => { 193 | let id = ctx.request.body.id, 194 | name = ctx.request.body.name 195 | allowEdit = true; 196 | if (!ctx.session.user) { 197 | allowEdit = false 198 | } else { 199 | allowEdit = true 200 | } 201 | if (allowEdit) { 202 | await userModel.deletePhoto(id) 203 | .then(() => { 204 | fs.unlink('public/photos/'+name+'.gif',function (err) { 205 | if(err) throw err; 206 | console.log('删除成功') 207 | }) 208 | ctx.body = true 209 | }).catch(() => { 210 | ctx.body = false 211 | }) 212 | 213 | } else { 214 | ctx.body = false 215 | } 216 | }) 217 | 218 | module.exports = router -------------------------------------------------------------------------------- /setup.js: -------------------------------------------------------------------------------- 1 | const apiModel = require('./lib/mysql.js') 2 | const md5 = require('md5') 3 | 4 | //第一次使用请先创建数据库 5 | // 进入登录mysql输入命令:create database `najeh` default character set utf8 collate utf8_general_ci; 6 | 7 | //创建完数据库以后进入此目录 node setup.js 后即可根据下面信息创建管理员用户 8 | 9 | //创建管理员 10 | apiModel.insertData(['admin', md5('123456')]).then(() => { 11 | console.log('创建成功'); 12 | process.exit(); 13 | }) 14 | 15 | //删除管理员 16 | // apiModel.deleteData('admin').then(() => { 17 | // console.log('删除成功'); 18 | // process.exit(); 19 | // }) -------------------------------------------------------------------------------- /views/comment.ejs: -------------------------------------------------------------------------------- 1 |
2 | <% if( comments_length==0 ){ %><% }else{ %> 3 |

<%- comments_length %>条评论

4 | <% } %> 5 | 29 |

留下一条评论

30 |
31 |
32 | <% if(session.user ){ %> 33 | >>您已登录 34 | 35 | 36 | 37 | <% }else{ %> 38 | 39 | 40 | 41 | <% } %> 42 |
43 |
44 | 45 |
46 |
47 | 48 | 49 | 50 |
51 |
提交评论
52 |
53 |
54 | -------------------------------------------------------------------------------- /views/create.ejs: -------------------------------------------------------------------------------- 1 | <%- include("header",{type:'create'}) %> 2 |
3 |
4 |
5 | 6 | 7 |
8 |
9 | 10 | 11 |
12 |
发表
13 |
14 |
15 | 45 | <%- include("footer",{type:'all'}) %> -------------------------------------------------------------------------------- /views/createpage.ejs: -------------------------------------------------------------------------------- 1 | <%- include("header",{type:'createpage'}) %> 2 |
3 |
4 |
5 | 6 | 7 |
8 |
9 |
10 | 11 |
12 |
13 | 14 | 15 |
16 |
17 | 开启评论 18 | 关闭评论 19 |
20 |
发表
21 |
22 |
23 | 55 | <%- include("footer",{type:'all'}) %> -------------------------------------------------------------------------------- /views/edit.ejs: -------------------------------------------------------------------------------- 1 | <%- include("header",{type:'edit'}) %> 2 |
3 |
4 |
5 | 6 | 7 |
8 |
9 |
10 | 11 | 12 |
13 |
修改
14 | 15 |
16 | 40 | <%- include("footer",{type:'all'}) %> -------------------------------------------------------------------------------- /views/editpage.ejs: -------------------------------------------------------------------------------- 1 | <%- include("header",{type:'editpage'}) %> 2 |
3 |
4 |
5 | 6 | 7 |
8 |
9 |
10 | 11 |
12 |
13 |
14 | 15 | 16 |
17 |
18 | checked<% }%>>开启评论 19 | checked<% }%>>关闭评论 20 |
21 |
修改
22 | 23 |
24 | 48 | <%- include("footer",{type:'all'}) %> -------------------------------------------------------------------------------- /views/footer.ejs: -------------------------------------------------------------------------------- 1 |
2 | 5 |
6 |
7 | <%- statistics %> 8 | 9 | 10 | -------------------------------------------------------------------------------- /views/header.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <% if(type == 'photo'){ %>相册 - <%- websiteTitle %><% }%><% if(type == 'img'){ %>图床 - <%- websiteTitle %><% }%><% if(type == 'uploadimg'){ %>上传图片 - <%- websiteTitle %><% }%><% if(type == 'create'){ %>新文章 - <%- websiteTitle %><% }%><% if(type == 'edit'){ %>编辑文章 - <%- websiteTitle %><% }%><% if(type == 'signin'){ %>登录 - <%- websiteTitle %><% }%><% if(type == 'all'){ %><%- websiteIndexTitle %><% }%><% if(type == 'post'){ %><%- posts.title %> - <%- websiteTitle %><% }%><% if(type == 'page'){ %><%- pages.title %> - <%- websiteTitle %><% }%><% if(type == 'createpage'){ %>新页面 - <%- websiteTitle %><% }%><% if(type == 'editpage'){ %>编辑页面 - <%- websiteTitle %><% }%> 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | <% if(type == 'post'){ %> 15 | 16 | 17 | 18 | <% }%> 19 | 53 | 54 | 55 | 56 |
登录成功
57 | <% if(session.user){ %> 58 | 97 | <% } %> 98 | <% if(!session.user){ %> 99 | 131 | <% } %> 132 |
133 |
134 | 139 |

<%- myUsername %>

140 |

<%- indexDescription %>

141 |
-------------------------------------------------------------------------------- /views/img.ejs: -------------------------------------------------------------------------------- 1 | <%- include("header",{type:'img'}) %> 2 |
3 | 上传新图片 4 |
    5 | <% imgs.forEach(function(res){ %> 6 |
  • 7 | <%- res.name %> 8 | 删除 9 |
  • 10 | <% }) %> 11 |
12 | 15 | 16 | 55 |
56 | 81 | <%- include("footer",{type:'all'}) %> -------------------------------------------------------------------------------- /views/photo.ejs: -------------------------------------------------------------------------------- 1 | <%- include("header",{type:'photo'}) %> 2 |
3 | <% if(session.user){ %> 4 | 上传新图片 5 | <% }%> 6 |
7 |
    8 | <% imgs.forEach(function(res){ %> 9 |
  • 10 | 11 | <% if(session.user){ %>删除<% }%> 12 |
  • 13 | <% }) %> 14 |
15 |
16 | 19 | 20 | 59 |
60 | <% if(session.user){ %> 61 | 86 | <% }%> 87 | <%- include("footer",{type:'all'}) %> -------------------------------------------------------------------------------- /views/posts.ejs: -------------------------------------------------------------------------------- 1 | <%- include("header",{type:'all'}) %> 2 | 3 | 4 |
5 | <% posts.forEach(function(res){ %> 6 | 14 | <% }) %> 15 |
16 | 17 | 18 | 56 | 57 | <%- include("footer",{type:'all'}) %> 58 | 59 | -------------------------------------------------------------------------------- /views/sPage.ejs: -------------------------------------------------------------------------------- 1 | <%- include("header",{type:'page'}) %> 2 | 3 |
4 |
5 |
6 |

<%= pages.title %>

7 |
8 | <%- pages.md %> 9 |
10 |
11 |

12 | <% if(session.user ){ %> 13 | 编辑 14 | 删除 15 | <% } %> 16 |

17 | <% if(pages.hascom == 'true'){ %> 18 | <%- include("comment",{type:'page'}) %> 19 | <% }%> 20 |
21 | 40 |
41 | <%- include("footer",{type:'all'}) %> -------------------------------------------------------------------------------- /views/sPost.ejs: -------------------------------------------------------------------------------- 1 | <%- include("header",{type:'post'}) %> 2 | 3 |
4 |
5 |
6 |

<%= posts.title %>

7 | 12 |
13 | <%- posts.content %> 14 |
15 |
16 |

17 | <% if(session.user ){ %> 18 | 编辑 19 | 删除 20 | <% } %> 21 |

22 | <%- include("comment",{type:'post'}) %> 23 |
24 | 43 |
44 | <%- include("footer",{type:'post'}) %> -------------------------------------------------------------------------------- /views/signin.ejs: -------------------------------------------------------------------------------- 1 | <%- include("header",{type:'signin'}) %> 2 |
3 |
4 |
5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 |
13 |
14 | 15 |
16 |
17 |
登录
18 |
19 |
20 |
21 | 66 | <%- include("footer",{type:'all'}) %> -------------------------------------------------------------------------------- /views/uploadimg.ejs: -------------------------------------------------------------------------------- 1 | <%- include("header",{type:'uploadimg'}) %> 2 | 3 | 4 |
5 |
6 |
7 | 8 | 9 |
10 | 11 | 12 | 13 |
14 | 15 | 16 |
17 |
18 | 19 | 20 |
21 |
上传
22 |
23 |
24 | 52 | <%- include("footer",{type:'all'}) %> -------------------------------------------------------------------------------- /views/uploadphoto.ejs: -------------------------------------------------------------------------------- 1 | <%- include("header",{type:'uploadimg'}) %> 2 | 3 | 4 |
5 |
6 |
7 | 8 | 9 |
10 | 11 | 12 | 13 |
14 | 15 | 16 |
17 |
18 | 19 | 20 |
21 |
上传
22 |
23 |
24 | 51 | <%- include("footer",{type:'all'}) %> --------------------------------------------------------------------------------