commit
06ec52b00b
48 changed files with 6201 additions and 0 deletions
@ -0,0 +1,2 @@ |
|||
node_modules |
|||
.idea |
@ -0,0 +1,3 @@ |
|||
{ |
|||
"sqltools.connections": [] |
|||
} |
@ -0,0 +1,60 @@ |
|||
// require('module-alias/register')
|
|||
require('./global/index.js'); |
|||
|
|||
const Koa = require('koa'); |
|||
const jwt = require('koa-jwt'); |
|||
const views = require('koa-views'); |
|||
const serve = require('koa-static'); |
|||
const app = new Koa(); |
|||
const cors = require('@koa/cors'); |
|||
const koaBody = require('koa-body'); |
|||
const router = require('./routes/index.js'); |
|||
const config = require('./config.js'); |
|||
const path = require('path') |
|||
|
|||
app.use(serve(path.join(__dirname + '/public'))); |
|||
app.use(views(path.join(__dirname + '/public'), { |
|||
extension: 'pug' |
|||
})); |
|||
app.use(cors()); |
|||
|
|||
// Custom 401 handling if you don't want to expose koa-jwt errors to users
|
|||
app.use(async (ctx, next) => { |
|||
return next().catch((err) => { |
|||
if (401 == err.status) { |
|||
ctx.status = 401; |
|||
ctx.body = { |
|||
message: 'Protected resource, use Authorization header to get access\n', |
|||
data: null, |
|||
code: 401 |
|||
}; |
|||
} else { |
|||
throw err; |
|||
} |
|||
}); |
|||
}); |
|||
// https://www.v2ex.com/t/320710有关token不需要状态,可以多人登录同一个账号
|
|||
app.use(jwt({ |
|||
secret: config.share_key |
|||
}).unless({ |
|||
path: [/^\/api\/login/, /^\/api\/register/, /^((?!\/api).)*$/,/^\/api\/menus\/getAll/] |
|||
})); |
|||
|
|||
|
|||
// logger
|
|||
app.use(async (ctx, next) => { |
|||
const start = new Date() |
|||
await next() |
|||
const ms = new Date() - start |
|||
log(`${ctx.method} ${ctx.url} - ${ms}ms`) |
|||
}); |
|||
// 请求解析
|
|||
app.use(koaBody()); |
|||
// 路由注册
|
|||
app.use(router.routes()).use(router.allowedMethods()); |
|||
// error-handling
|
|||
app.on('error', (err, ctx) => { |
|||
console.error('server error', err, ctx) |
|||
}); |
|||
|
|||
module.exports = app |
@ -0,0 +1,90 @@ |
|||
#!/usr/bin/env node |
|||
|
|||
/** |
|||
* Module dependencies. |
|||
*/ |
|||
|
|||
var app = require('../app'); |
|||
var debug = require('debug')('demo:server'); |
|||
var http = require('http'); |
|||
|
|||
/** |
|||
* Get port from environment and store in Express. |
|||
*/ |
|||
|
|||
var port = normalizePort(process.env.PORT || '3000'); |
|||
// app.set('port', port); |
|||
|
|||
/** |
|||
* Create HTTP server. |
|||
*/ |
|||
|
|||
var server = http.createServer(app.callback()); |
|||
|
|||
/** |
|||
* Listen on provided port, on all network interfaces. |
|||
*/ |
|||
|
|||
server.listen(port); |
|||
server.on('error', onError); |
|||
server.on('listening', onListening); |
|||
|
|||
/** |
|||
* Normalize a port into a number, string, or false. |
|||
*/ |
|||
|
|||
function normalizePort(val) { |
|||
var port = parseInt(val, 10); |
|||
|
|||
if (isNaN(port)) { |
|||
// named pipe |
|||
return val; |
|||
} |
|||
|
|||
if (port >= 0) { |
|||
// port number |
|||
return port; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* Event listener for HTTP server "error" event. |
|||
*/ |
|||
|
|||
function onError(error) { |
|||
if (error.syscall !== 'listen') { |
|||
throw error; |
|||
} |
|||
|
|||
var bind = typeof port === 'string' ? |
|||
'Pipe ' + port : |
|||
'Port ' + port; |
|||
|
|||
// handle specific listen errors with friendly messages |
|||
switch (error.code) { |
|||
case 'EACCES': |
|||
console.error(bind + ' requires elevated privileges'); |
|||
process.exit(1); |
|||
break; |
|||
case 'EADDRINUSE': |
|||
console.error(bind + ' is already in use'); |
|||
process.exit(1); |
|||
break; |
|||
default: |
|||
throw error; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Event listener for HTTP server "listening" event. |
|||
*/ |
|||
|
|||
function onListening() { |
|||
var addr = server.address(); |
|||
var bind = typeof addr === 'string' ? |
|||
'pipe ' + addr : |
|||
'port ' + addr.port; |
|||
debug('Listening on ' + bind); |
|||
} |
@ -0,0 +1,12 @@ |
|||
/** |
|||
* 逻辑文案管理 |
|||
*/ |
|||
|
|||
const sysCode = { |
|||
|
|||
SUCCESS: "success", |
|||
Fail: "fail", |
|||
} |
|||
|
|||
|
|||
module.exports = sysCode |
@ -0,0 +1,32 @@ |
|||
/** |
|||
* 逻辑文案管理 |
|||
*/ |
|||
|
|||
const userCode = { |
|||
|
|||
ERROR_USER_NAME: '用户名格式为6-16位的小写字母,包括-、_', |
|||
|
|||
ERROR_EMAIL: '请输入正确的邮箱地址', |
|||
|
|||
ERROR_PASSWORD: '密码长度应该为6-16', |
|||
|
|||
ERROR_PASSWORD_CONFORM: '两次密码不一致', |
|||
|
|||
ERROR_SYS: '系统错误', |
|||
|
|||
FAIL_EMAIL_IS_EXIST: '邮箱已被注册', |
|||
|
|||
FAIL_USER_NAME_IS_EXIST: '用户名已被注册', |
|||
|
|||
FAIL_USER_NAME_OR_PASSWORD_ERROR: '用户名或登录密码错误', |
|||
|
|||
FAIL_USER_NO_LOGIN: '用户未登录', |
|||
FAIL_USER_NO_EXIST: '用户不存在', |
|||
ERROR_USER_EMPTY: '用户名不能为空', |
|||
ERROR_MORE_USER: '查询到多个用户', |
|||
|
|||
|
|||
} |
|||
|
|||
|
|||
module.exports = userCode |
@ -0,0 +1,11 @@ |
|||
module.exports = { |
|||
db: { |
|||
host: '47.244.111.211', |
|||
port: '3306', |
|||
user: 'noderest', |
|||
password: '8WBtsejYGiEESJMh', |
|||
database: 'noderest', |
|||
connectTimeout:3000 |
|||
}, |
|||
share_key: 'dsadasdasd' |
|||
} |
@ -0,0 +1,33 @@ |
|||
const fs = require('fs'); |
|||
const path = require('path'); |
|||
const Bean = require('../utils/index.js'); |
|||
|
|||
// 控制器收集规则
|
|||
const routes = fs.readdirSync(path.resolve(__dirname)); |
|||
const controler = {}; |
|||
routes.forEach(route => { |
|||
if (fs.statSync(path.resolve(__dirname, route)).isDirectory()) { |
|||
const deep = Bean.readFileDeep(path.resolve(__dirname, route)).file; |
|||
|
|||
controler[route] = {}; |
|||
deep.forEach(file => { |
|||
Object.keys(require(file)).forEach(key => { |
|||
if (Object.keys(controler[route]).includes(key)) { |
|||
let str = "注意有相同的控制器:{" + route + ':' + key + '}'; |
|||
throw str |
|||
} |
|||
}) |
|||
controler[route] = { |
|||
...controler[route], |
|||
...require(file) |
|||
} |
|||
}) |
|||
} |
|||
if (fs.statSync(path.resolve(__dirname, route)).isFile()) { |
|||
if (route !== 'index.js') { |
|||
controler[route.slice(0, -3)] = require(path.resolve(__dirname, route)); |
|||
} |
|||
} |
|||
}) |
|||
|
|||
module.exports = controler |
@ -0,0 +1,258 @@ |
|||
const menuServices = require('../../services/menus.js') |
|||
|
|||
|
|||
function findeBelong(data, index) { |
|||
let array = []; |
|||
for (let i = data.length - 1; i >= 0; i--) { |
|||
if (data[i].belongto == index) { |
|||
const obj = { |
|||
id: data[i].id, |
|||
name: data[i].name, |
|||
desc: data[i].about, |
|||
children: [] |
|||
} |
|||
array.push(obj); |
|||
data.splice(i, 1); |
|||
} |
|||
} |
|||
return array; |
|||
} |
|||
|
|||
function sortTree(arr, all) { |
|||
let tree = (arr, all) => { |
|||
for (let i = 0; i < arr.length; i++) { |
|||
let item = findeBelong(all, arr[i].id); |
|||
for (let j = 0; j < item.length; j++) { |
|||
const obj = { |
|||
id: item[j].id, |
|||
name: item[j].name, |
|||
desc: item[j].desc, |
|||
children: [] |
|||
} |
|||
arr[i].children.push(obj); |
|||
} |
|||
tree(arr[i].children, all) |
|||
} |
|||
} |
|||
tree(arr, all) |
|||
} |
|||
|
|||
module.exports = { |
|||
/** |
|||
* 获取所有的菜单 |
|||
* @param ctx |
|||
* @param next |
|||
* @returns {Promise<void>} |
|||
*/ |
|||
async getAll(ctx, next) { |
|||
let result = { |
|||
success: false, |
|||
message: '', |
|||
data: null |
|||
} |
|||
let getResult = await menuServices.getAllMenus(); |
|||
if (getResult && Array.isArray(getResult)) { |
|||
let menus = JSON.parse(JSON.stringify(getResult)); |
|||
let fa = findeBelong(menus, '0'); |
|||
sortTree(fa, menus); |
|||
if (menus.length > 0) { |
|||
result.success = false; |
|||
result.message = '菜单不完整'; |
|||
ctx.body = result |
|||
return |
|||
} else { |
|||
result.success = true; |
|||
result.message = 'success'; |
|||
result.data = fa; |
|||
} |
|||
|
|||
} else{ |
|||
result.success = false; |
|||
result.message = 'fail'; |
|||
ctx.body = result |
|||
return ; |
|||
} |
|||
//menus有长度表示还有菜单没消耗完
|
|||
ctx.body = result |
|||
}, |
|||
/** |
|||
* 创建菜单 |
|||
* @param ctx |
|||
* @param next |
|||
* @returns {Promise<void>} |
|||
*/ |
|||
async createOne(ctx, next) { |
|||
let result = { |
|||
success: false, |
|||
message: '', |
|||
data: null |
|||
} |
|||
let formData = ctx.request.body; |
|||
|
|||
//验证参数的必需
|
|||
let menuResult = await menuServices.validatorNeed(formData, [ |
|||
{key: 'name', error: '标题不能为空', validate: (data) => data == undefined}, |
|||
{key: 'belongto', error: '没有所属ID', validate: (data) => data == undefined} |
|||
]); |
|||
if (!menuResult.success) { |
|||
result.success = false; |
|||
result.message = menuResult.message; |
|||
ctx.body = result; |
|||
return; |
|||
} else { |
|||
// 验证所属ID是数据库中的
|
|||
if (Number(formData.belongto) > 0) { |
|||
let allMenus = await menuServices.getAllMenus(); |
|||
let allID = allMenus.map(v => v.id); |
|||
if (allID.indexOf(formData.belongto) == -1) { |
|||
result.success = false; |
|||
result.message = '没有该菜单'; |
|||
ctx.body = result; |
|||
return; |
|||
} |
|||
} |
|||
let createResult = await menuServices.createMenu(formData); |
|||
if (createResult && createResult.insertId * 1 > 0) { |
|||
result.success = true; |
|||
result.message = '创建成功'; |
|||
} else { |
|||
result.success = true; |
|||
result.message = '系统错误'; |
|||
ctx.body = result; |
|||
return; |
|||
} |
|||
} |
|||
ctx.body = result; |
|||
}, |
|||
/** |
|||
* |
|||
* 修改菜单 |
|||
*/ |
|||
async updateOne(ctx, next) { |
|||
let result = { |
|||
success: false, |
|||
message: '', |
|||
data: null |
|||
} |
|||
let formData = ctx.request.body; |
|||
//验证参数的必需
|
|||
let menuResult = await menuServices.validatorNeed(formData, [ |
|||
{key: 'id', error: 'id不能为空', validate: (data) => data == undefined}, |
|||
{ |
|||
key: 'id', error: '没有这个菜单', validate: async (data) => { |
|||
let allMenus = await menuServices.getAllMenus(); |
|||
let allID = allMenus.map(v => v.id); |
|||
if (allID.indexOf(formData.id) == -1) { |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
}, |
|||
{key: 'belongto', error: '没有父类', validate: (data) => data == undefined || data < 0}, |
|||
{ |
|||
key: 'belongto', error: '没有父ID', validate: async (data) => { |
|||
if (data == 0) { |
|||
return false; |
|||
} |
|||
let allMenus = await menuServices.getAllMenus(); |
|||
let allID = allMenus.map(v => v.id); |
|||
if (allID.indexOf(formData.belongto) == -1) { |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
}, |
|||
{key: 'id', error: 'ID不能与父ID相同', validate: (data) => formData.id == formData.belongto} |
|||
]); |
|||
if (!menuResult.success) { |
|||
result.success = false; |
|||
result.message = menuResult.message; |
|||
ctx.body = result; |
|||
return; |
|||
} else { |
|||
let updateResult = await menuServices.updateMenu(formData); |
|||
if (updateResult) { |
|||
result.success = true; |
|||
result.message = 'success'; |
|||
} else { |
|||
result.success = false; |
|||
result.message = 'fail'; |
|||
} |
|||
} |
|||
ctx.body = result; |
|||
}, |
|||
/** |
|||
* 删除菜单 |
|||
*/ |
|||
async deleteOne(ctx, next) { |
|||
let result = { |
|||
success: false, |
|||
message: '', |
|||
data: null |
|||
} |
|||
let formData = ctx.request.body; |
|||
//验证参数的必需
|
|||
let menuResult = await menuServices.validatorNeed(formData, [ |
|||
{key: 'id', error: 'id不能为空', validate: (data) => data == undefined}, |
|||
{ |
|||
key: 'id', error: '没有这个菜单', validate: async (data) => { |
|||
let allMenus = await menuServices.getAllMenus(); |
|||
let allID = allMenus.map(v => v.id); |
|||
if (allID.indexOf(formData.id) == -1) { |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
}, |
|||
{ |
|||
key: 'id', error: '这个菜单存在子菜单,替换ID出错', validate: async (data) => { |
|||
let judgeResult = await menuServices.judgeID(data); |
|||
if (formData.fix==0){ |
|||
return false; |
|||
} |
|||
if(judgeResult&&!formData.fix){ |
|||
return true |
|||
}else if(judgeResult&&formData.fix){ |
|||
//替换ID不能跟要删除的ID相同
|
|||
if (formData.fix==formData.id){ |
|||
return '替换ID不能跟要删除的ID相同'; |
|||
} |
|||
// 替换ID不能跟需要修改的ID相同
|
|||
let uID = judgeResult.map(v => v.id); |
|||
if (uID.indexOf(formData.fix) != -1) { |
|||
return '替换ID不能跟需要修改的ID相同'; |
|||
} |
|||
// 替换ID必须存在与菜单中
|
|||
let allMenus = await menuServices.getAllMenus(); |
|||
let allID = allMenus.map(v => v.id); |
|||
if (allID.indexOf(formData.fix) == -1) { |
|||
return '替换ID必须存在与菜单中'; |
|||
}else { |
|||
return false; |
|||
} |
|||
}else { |
|||
return false |
|||
} |
|||
} |
|||
}, |
|||
]); |
|||
if (!menuResult.success) { |
|||
result.success = false; |
|||
result.message = menuResult.message; |
|||
ctx.body = result; |
|||
return; |
|||
} else { |
|||
let judgeResult = await menuServices.judgeID(formData.id); |
|||
let deleteResult = await menuServices.deleteMenu(formData,judgeResult,formData.fix); |
|||
if (deleteResult){ |
|||
//删除成功
|
|||
result.success = true; |
|||
result.message = 'success'; |
|||
} else { |
|||
result.success = false; |
|||
result.message = 'fail'; |
|||
} |
|||
} |
|||
ctx.body = result; |
|||
} |
|||
} |
@ -0,0 +1,71 @@ |
|||
// // var data = [
|
|||
// // {id: 1, address: "安徽", parent_id: 0},
|
|||
// // {id: 2, address: "江苏", parent_id: 0},
|
|||
// // {id: 3, address: "合肥", parent_id: 1},
|
|||
// // {id: 4, address: "庐阳区", parent_id: 3},
|
|||
// // {id: 5, address: "大杨镇", parent_id: 4},
|
|||
// // {id: 6, address: "南京", parent_id: 2},
|
|||
// // {id: 7, address: "玄武区", parent_id: 6},
|
|||
// // {id: 8, address: "梅园新村街道", parent_id: 7},
|
|||
// // {id: 9, address: "上海", parent_id: 0},
|
|||
// // {id: 10, address: "黄浦区", parent_id: 9},
|
|||
// // {id: 11, address: "外滩", parent_id: 10},
|
|||
// // {id: 12, address: "安庆", parent_id: 1}
|
|||
// // ];
|
|||
// var data = [ { id: 1, name: 'html', belongto: 0, about: '22' },
|
|||
// { id: 2, name: 'css', belongto: 0, about: '2256' },
|
|||
// { id: 3, name: 'js', belongto: 1, about: '5422' },
|
|||
// { id: 4, name: 'js', belongto: 2, about: '5422' },
|
|||
// { id: 5, name: 'js', belongto: 3, about: '5422' },
|
|||
// { id: 6, name: 'js', belongto: 1, about: '5422' },
|
|||
// { id: 7, name: 'js', belongto: 1, about: '5422' },
|
|||
// { id: 8, name: 'js', belongto: 5, about: '5422' },
|
|||
// { id: 9, name: 'js', belongto: 8, about: '5422' },
|
|||
// { id: 10, name: 'js', belongto: 8, about: '5422' },
|
|||
// { id: 11, name: 'js', belongto: 10, about: '5422' },
|
|||
// { id: 12, name: 'js', belongto: 11, about: '5422' } ]
|
|||
//
|
|||
// function findeBelong(data, index) {
|
|||
// let array = [];
|
|||
// for (let i = data.length-1; i >= 0 ; i--) {
|
|||
// if(data[i].belongto == index){
|
|||
// const obj = {
|
|||
// id: data[i].id,
|
|||
// name: data[i].name,
|
|||
// desc: data[i].about,
|
|||
// children: []
|
|||
// }
|
|||
// array.push(obj);
|
|||
// data.splice(i,1);
|
|||
// }
|
|||
// }
|
|||
// return array;
|
|||
// }
|
|||
//
|
|||
// function sortTree(arr,all){
|
|||
// let tree = (arr,all)=>{
|
|||
// for (let i = 0; i < arr.length; i++) {
|
|||
// let item = findeBelong(all,arr[i].id);
|
|||
// for (let j = 0; j < item.length; j++) {
|
|||
// const obj = {
|
|||
// id: item[j].id,
|
|||
// name: item[j].name,
|
|||
// desc: item[j].desc,
|
|||
// children: []
|
|||
// }
|
|||
// arr[i].children.push(obj);
|
|||
// }
|
|||
// tree(arr[i].children,all)
|
|||
// }
|
|||
// }
|
|||
// tree(arr,all)
|
|||
// }
|
|||
// let fa = findeBelong(data,0);
|
|||
// sortTree(fa,data);
|
|||
// console.log(fa);
|
|||
// console.log(data);
|
|||
// /*
|
|||
// * 1. 先找出ID==0的菜单
|
|||
// * 2. 选中第一个ID的菜单,去菜单表中寻找是否有其子菜单,找到之后构建插入然后删除这个,然后递归查这一个的子菜单
|
|||
// *
|
|||
// * */
|
@ -0,0 +1,181 @@ |
|||
const userCode = require('../../codes/user.js') |
|||
const userInfoService = require('../../services/user-info') |
|||
|
|||
module.exports = { |
|||
/** |
|||
* 修改个人信息,由于用户名和邮箱比较重要,暂不提供修改 |
|||
* @param {*} ctx |
|||
* @param {*} next |
|||
*/ |
|||
async modifyUserinfo(ctx, next) { |
|||
let user = ctx.state.user; |
|||
let formData = ctx.request.body; |
|||
let result = { |
|||
message: 'fail', |
|||
data: null, |
|||
success: false |
|||
}; |
|||
// 根据ID查询
|
|||
let userResult = await userInfoService.getExistOneByIdOrUserName(user); |
|||
if (userResult) { |
|||
// 用户信息验证,不校验密码
|
|||
let validateResult = await userInfoService.validatorNeed(formData, false) |
|||
if (!validateResult.success) { |
|||
result.success = false; |
|||
result.message = validateResult.message; |
|||
ctx.body = result |
|||
return |
|||
} |
|||
let r = await userInfoService.update(formData, user.id); |
|||
if (r) { |
|||
result.success = true; |
|||
result.message = 'success'; |
|||
} else { |
|||
result.success = false; |
|||
result.message = 'fail'; |
|||
} |
|||
} else { |
|||
result.success = false; |
|||
result.message = userCode.FAIL_USER_NO_EXIST |
|||
} |
|||
ctx.body = result |
|||
}, |
|||
async getUserinfo(ctx, next) { |
|||
let formData = ctx.state.user; |
|||
let result = { |
|||
message: '', |
|||
data: null, |
|||
code: 400 |
|||
}; |
|||
let userResult = await userInfoService.getExistOneByIdOrUserName(formData); |
|||
if (userResult) { |
|||
result.code = 200; |
|||
delete userResult.password |
|||
result.data = userResult; |
|||
} else { |
|||
result.message = userCode.FAIL_USER_NO_EXIST |
|||
} |
|||
ctx.body = result; |
|||
}, |
|||
|
|||
/** |
|||
* 登录操作,返回 |
|||
* @param {*} ctx |
|||
* @param {*} next |
|||
*/ |
|||
async login(ctx, next) { |
|||
let formData = ctx.request.body; |
|||
let result = { |
|||
message: 'fail', |
|||
data: null, |
|||
success: false |
|||
} |
|||
let validateResult = await userInfoService.validatorNeed(formData) |
|||
if (!validateResult.success) { |
|||
result.success = false; |
|||
result.message = validateResult.message; |
|||
ctx.body = result |
|||
return |
|||
} |
|||
// 是否存在一个相同用户
|
|||
let existOne = await userInfoService.getExistOne(formData); |
|||
if (Array.isArray(existOne)) { |
|||
if (existOne.length > 1) { |
|||
result.success = false; |
|||
result.message = userCode.ERROR_MORE_USER; |
|||
ctx.body = result; |
|||
return; |
|||
} |
|||
existOne = existOne[0]; |
|||
// 密码验证,获取token
|
|||
let token = await userInfoService.validatorPwd(formData, existOne) |
|||
if (!token) { |
|||
result.success = false; |
|||
result = userCode.FAIL_USER_NAME_OR_PASSWORD_ERROR; |
|||
ctx.body = result; |
|||
return; |
|||
} else { |
|||
result.success = true; |
|||
result.message = 'success'; |
|||
result.data = token; |
|||
} |
|||
} else { |
|||
result.success = false; |
|||
result.message = userCode.FAIL_USER_NO_EXIST; |
|||
ctx.body = result; |
|||
return; |
|||
} |
|||
ctx.body = result; |
|||
}, |
|||
|
|||
/** |
|||
* 注册操作 |
|||
* @param {*} ctx 上下文 |
|||
* { |
|||
* imgurl, |
|||
* email, |
|||
* password, 必须 |
|||
* confirmPassword,必须 |
|||
* username, 必须 |
|||
* nickname, |
|||
* createTime, |
|||
* modifiedTime, |
|||
* level |
|||
* } |
|||
*/ |
|||
async register(ctx, next) { |
|||
let formData = ctx.request.body; |
|||
let result = { |
|||
success: false, |
|||
message: 'fail', |
|||
data: null |
|||
} |
|||
// 用户注册信息验证
|
|||
let validateResult = await userInfoService.validatorSignUp(formData) |
|||
if (!validateResult.success) { |
|||
result.success = false; |
|||
result.message = validateResult.message; |
|||
ctx.body = result; |
|||
return |
|||
} |
|||
// 是否存在一个相同用户
|
|||
let existOne = await userInfoService.getExistOne(formData); |
|||
if (Array.isArray(existOne)) { |
|||
if (existOne.length > 1) { |
|||
result.success = false; |
|||
result.message = userCode.ERROR_MORE_USER; |
|||
ctx.body = result; |
|||
return; |
|||
} |
|||
existOne = existOne[0]; |
|||
// 判断是否存在相同用户名或者邮箱
|
|||
if (existOne.username === formData.username) { |
|||
result.message = userCode.FAIL_USER_NAME_IS_EXIST |
|||
ctx.body = result |
|||
return |
|||
} |
|||
if (existOne.email === formData.email) { |
|||
result.message = userCode.FAIL_EMAIL_IS_EXIST |
|||
ctx.body = result |
|||
return |
|||
} |
|||
} |
|||
// 创建用户
|
|||
let userResult = await userInfoService.create({ |
|||
imgurl: formData.imgurl, |
|||
email: formData.email, |
|||
password: formData.password, |
|||
username: formData.username, |
|||
nickname: formData.nickname, |
|||
createTime: new Date().getTime(), |
|||
level: 1, |
|||
}) |
|||
if (userResult && userResult.insertId * 1 > 0) { |
|||
result.success = true; |
|||
result.message = 'success' |
|||
} else { |
|||
result.message = userCode.ERROR_SYS |
|||
} |
|||
ctx.body = result; |
|||
} |
|||
} |
@ -0,0 +1,10 @@ |
|||
const menus = require('../menus/index.js') |
|||
|
|||
module.exports = { |
|||
async home(ctx, next) { |
|||
await menus.getAll(ctx, next); |
|||
await ctx.render('home', { |
|||
data: JSON.stringify(ctx.body.data) |
|||
}) |
|||
} |
|||
}; |
@ -0,0 +1,8 @@ |
|||
/** |
|||
* |
|||
* 只注册全局变量 |
|||
* |
|||
*/ |
|||
const getOneRes = require('./res.util.js'); |
|||
global.log = require('debug')('demo:server'); |
|||
global.oneRes = getOneRes.message; |
@ -0,0 +1,45 @@ |
|||
const SuccessTemplate = { |
|||
code: 200, |
|||
data: null, |
|||
message: 'success' |
|||
} |
|||
|
|||
const failTemplate = { |
|||
code: 400, |
|||
data: null, |
|||
message: 'fail' |
|||
} |
|||
const template = { |
|||
code: 200, |
|||
data: null, |
|||
message: 'ok' |
|||
} |
|||
module.exports = { |
|||
success(code, message, data) { |
|||
let res = { |
|||
...SuccessTemplate |
|||
}; |
|||
code && (res.code = code); |
|||
message && (res.message = message); |
|||
data && (res.data = data); |
|||
return res; |
|||
}, |
|||
fail(code, message, data) { |
|||
let res = { |
|||
...failTemplate |
|||
}; |
|||
code && (res.code = code); |
|||
message && (res.message = message); |
|||
data && (res.data = data); |
|||
return res; |
|||
}, |
|||
message(code, message, data) { |
|||
let res = { |
|||
...template |
|||
}; |
|||
code && (res.code = code); |
|||
message && (res.message = message); |
|||
data && (res.data = data); |
|||
return res; |
|||
} |
|||
} |
@ -0,0 +1,43 @@ |
|||
const fs = require('fs'); |
|||
const getSqlContentMap = require('./util/get-sql-content-map'); |
|||
const { |
|||
query |
|||
} = require('./util/db'); |
|||
|
|||
|
|||
// 打印脚本执行日志
|
|||
const eventLog = function (err, sqlFile, index) { |
|||
if (err) { |
|||
console.log(`[ERROR] sql脚本文件: ${sqlFile} 第${index + 1}条脚本 执行失败 o(╯□╰)o !`) |
|||
} else { |
|||
console.log(`[SUCCESS] sql脚本文件: ${sqlFile} 第${index + 1}条脚本 执行成功 O(∩_∩)O !`) |
|||
} |
|||
} |
|||
|
|||
// 获取所有sql脚本内容
|
|||
let sqlContentMap = getSqlContentMap() |
|||
|
|||
// 执行建表sql脚本
|
|||
const createAllTables = async () => { |
|||
for (let key in sqlContentMap) { |
|||
let sqlShell = sqlContentMap[key] |
|||
let sqlShellList = sqlShell.split(';') |
|||
|
|||
for (let [i, shell] of sqlShellList.entries()) { |
|||
if (shell.trim()) { |
|||
let result = await query(shell) |
|||
if (result.serverStatus * 1 === 2) { |
|||
eventLog(null, key, i) |
|||
} else { |
|||
eventLog(true, key, i) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
console.log('sql脚本执行结束!') |
|||
console.log('请按 ctrl + c 键退出!') |
|||
|
|||
} |
|||
|
|||
createAllTables() |
@ -0,0 +1,11 @@ |
|||
|
|||
-- CREATE TABLE IF NOT EXISTS `open` ( |
|||
-- `id` int(11) NOT NULL AUTO_INCREMENT, |
|||
-- `card` varchar(255) NOT NULL, |
|||
-- `host` varchar(255) NOT NULL, |
|||
-- PRIMARY KEY (`id`) |
|||
-- ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
|||
|
|||
-- INSERT INTO `open` set card='[0,0,0,1,1]', host='1'; |
|||
|
|||
-- INSERT INTO `open` set card='[0,0,0,1,2]', host='2'; |
@ -0,0 +1,13 @@ |
|||
|
|||
CREATE TABLE IF NOT EXISTS `category` ( |
|||
`id` bigint(20) NOT NULL AUTO_INCREMENT, |
|||
`name` varchar(255) DEFAULT NULL, |
|||
`belongto` varchar(255) DEFAULT NULL, |
|||
`about` varchar(255) DEFAULT NULL, |
|||
PRIMARY KEY (`id`) USING BTREE |
|||
) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
|||
|
|||
|
|||
INSERT INTO `category` set id='1', name='html', belongto='0', about='22'; |
|||
INSERT INTO `category` set id='2', name='css', belongto='0', about='2256'; |
|||
INSERT INTO `category` set id='3', name='js', belongto='1', about='5422'; |
@ -0,0 +1,14 @@ |
|||
-- level: 0:管理员 |
|||
-- level: 1:普通用户 |
|||
CREATE TABLE IF NOT EXISTS `user_info` ( |
|||
`id` int(11) NOT NULL AUTO_INCREMENT, |
|||
`imgurl` varchar(255) DEFAULT NULL, |
|||
`email` varchar(255) DEFAULT NULL, |
|||
`password` varchar(255) DEFAULT NULL, |
|||
`username` varchar(255) DEFAULT NULL, |
|||
`nickname` varchar(255) DEFAULT NULL, |
|||
`createTime` varchar(20) DEFAULT NULL, |
|||
`modifiedTime` varchar(20) DEFAULT NULL, |
|||
`level` int(11) DEFAULT '1', |
|||
PRIMARY KEY (`id`) |
|||
) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
@ -0,0 +1,30 @@ |
|||
const mysql = require('mysql') |
|||
var config = require('../../config.js') |
|||
const pool = mysql.createPool({ |
|||
...config.db |
|||
}) |
|||
|
|||
let query = function (sql, values) { |
|||
return new Promise((resolve, reject) => { |
|||
pool.getConnection(function (err, connection) { |
|||
if (err) { |
|||
reject(err) |
|||
} else { |
|||
connection.query(sql, values, (err, rows) => { |
|||
|
|||
if (err) { |
|||
reject(err) |
|||
} else { |
|||
resolve(rows) |
|||
} |
|||
connection.release() |
|||
}) |
|||
} |
|||
}) |
|||
}) |
|||
|
|||
} |
|||
|
|||
module.exports = { |
|||
query |
|||
} |
@ -0,0 +1,30 @@ |
|||
const fs = require('fs') |
|||
const getSqlMap = require('./get-sql-map') |
|||
|
|||
let sqlContentMap = {} |
|||
|
|||
/** |
|||
* 读取sql文件内容 |
|||
* @param {string} fileName 文件名称 |
|||
* @param {string} path 文件所在的路径 |
|||
* @return {string} 脚本文件内容 |
|||
*/ |
|||
function getSqlContent( fileName, path ) { |
|||
let content = fs.readFileSync( path, 'binary' ) |
|||
sqlContentMap[ fileName ] = content |
|||
} |
|||
|
|||
/** |
|||
* 封装所有sql文件脚本内容 |
|||
* @return {object} |
|||
*/ |
|||
function getSqlContentMap () { |
|||
let sqlMap = getSqlMap() |
|||
for( let key in sqlMap ) { |
|||
getSqlContent( key, sqlMap[key] ) |
|||
} |
|||
|
|||
return sqlContentMap |
|||
} |
|||
|
|||
module.exports = getSqlContentMap |
@ -0,0 +1,20 @@ |
|||
const fs = require('fs') |
|||
const walkFile = require('./walk-file') |
|||
|
|||
/** |
|||
* 获取sql目录下的文件目录数据 |
|||
* @return {object} |
|||
*/ |
|||
function getSqlMap() { |
|||
let basePath = __dirname |
|||
basePath = basePath.replace(/\\/g, '\/') |
|||
|
|||
let pathArr = basePath.split('\/') |
|||
pathArr = pathArr.splice(0, pathArr.length - 1) |
|||
basePath = pathArr.join('/') + '/sql/' |
|||
|
|||
let fileList = walkFile(basePath, 'sql') |
|||
return fileList |
|||
} |
|||
|
|||
module.exports = getSqlMap |
@ -0,0 +1,28 @@ |
|||
const fs = require('fs') |
|||
|
|||
/** |
|||
* 遍历目录下的文件目录 |
|||
* @param {string} pathResolve 需进行遍历的目录路径 |
|||
* @param {string} mime 遍历文件的后缀名 |
|||
* @return {object} 返回遍历后的目录结果 |
|||
*/ |
|||
const walkFile = function( pathResolve , mime ){ |
|||
|
|||
let files = fs.readdirSync( pathResolve ) |
|||
|
|||
let fileList = {} |
|||
|
|||
for( let [ i, item] of files.entries() ) { |
|||
let itemArr = item.split('\.') |
|||
|
|||
let itemMime = ( itemArr.length > 1 ) ? itemArr[ itemArr.length - 1 ] : 'undefined' |
|||
let keyName = item + '' |
|||
if( mime === itemMime ) { |
|||
fileList[ item ] = pathResolve + item |
|||
} |
|||
} |
|||
|
|||
return fileList |
|||
} |
|||
|
|||
module.exports = walkFile |
@ -0,0 +1,98 @@ |
|||
const dbUtils = require('../utils/db-util') |
|||
|
|||
const menus = { |
|||
async ceateMenu(model) { |
|||
let result = await dbUtils.insertData('category', model); |
|||
return result; |
|||
}, |
|||
// async deleteMenu(id) {
|
|||
// let result = await dbUtils.deleteDataById('category', id);
|
|||
// if (result.serverStatus == 2) {
|
|||
// result = true
|
|||
// } else {
|
|||
// result = false
|
|||
// }
|
|||
// },
|
|||
deleteMenu(id,subList,fix) { |
|||
let sql = []; |
|||
sql.push('DELETE FROM category WHERE id = '+id); |
|||
if(subList){ |
|||
for (let i = 0; i < subList.length; i++) { |
|||
sql.push("UPDATE category SET belongto='"+fix+"' WHERE id = "+subList[i].id); |
|||
} |
|||
} |
|||
console.log(sql) |
|||
return new Promise((resolve,reject)=>{ |
|||
dbUtils.execTrans(sql,(err)=>{ |
|||
if (err){ |
|||
resolve(false); |
|||
} else { |
|||
resolve(true) |
|||
} |
|||
}) |
|||
}) |
|||
}, |
|||
/** |
|||
* 更新菜单信息 |
|||
* @param {object} model 数据模型 |
|||
* @return {object} mysql执行结果 |
|||
*/ |
|||
async update(model, id) { |
|||
let result = await dbUtils.updateData('category', model, id) |
|||
if (result.serverStatus == 2) { |
|||
result = true |
|||
} else { |
|||
result = false |
|||
} |
|||
return result |
|||
}, |
|||
/** |
|||
* 获取所有菜单 |
|||
*/ |
|||
async getAllMenus() { |
|||
let _sql = `SELECT * from category;`; |
|||
let result = await dbUtils.query(_sql); |
|||
if (Array.isArray(result)) { |
|||
result = result |
|||
} else { |
|||
result = null; |
|||
} |
|||
return result |
|||
}, |
|||
|
|||
async getMenusByID(id) { |
|||
let _sql = ` |
|||
SELECT * from category |
|||
where id="${id}";`;
|
|||
let result = await dbUtils.query(_sql); |
|||
if (Array.isArray(result) && result.length > 0) { |
|||
result = result |
|||
} else { |
|||
result = null; |
|||
} |
|||
return result |
|||
}, |
|||
|
|||
/** |
|||
* 获取子菜单 |
|||
* 0: 主菜单 |
|||
* 1: 属于ID:1的子菜单 |
|||
* 2: 属于ID:2的子菜单 |
|||
*/ |
|||
|
|||
async getMenusByBelongTo(belongto) { |
|||
let _sql = ` |
|||
SELECT * from category |
|||
where belongto="${belongto}";`;
|
|||
let result = await dbUtils.query(_sql); |
|||
if (Array.isArray(result) && result.length > 0) { |
|||
result = result |
|||
} else { |
|||
result = null; |
|||
} |
|||
return result |
|||
}, |
|||
|
|||
} |
|||
|
|||
module.exports = menus |
@ -0,0 +1,110 @@ |
|||
const dbUtils = require('./../utils/db-util') |
|||
|
|||
const user = { |
|||
|
|||
/** |
|||
* 数据库创建用户 |
|||
* @param {object} model 用户数据模型 |
|||
* @return {object} mysql执行结果 |
|||
*/ |
|||
async create(model) { |
|||
let result = await dbUtils.insertData('user_info', model) |
|||
return result |
|||
}, |
|||
/** |
|||
* 更新用户信息 |
|||
* @param {object} model 用户数据模型 |
|||
* @return {object} mysql执行结果 |
|||
*/ |
|||
async update(model, id) { |
|||
let result = await dbUtils.updateData('user_info', model, id) |
|||
if (result.serverStatus == 2) { |
|||
result = true |
|||
} else { |
|||
result = false |
|||
} |
|||
return result |
|||
}, |
|||
/** |
|||
* 查找一个存在用户的数据 |
|||
* @param {obejct} options 查找条件参数 |
|||
* @return {object|null} 查找结果 |
|||
*/ |
|||
async getExistOne(options) { |
|||
let _sql = ` |
|||
SELECT * from user_info |
|||
where email="${options.email}" or username="${options.username}";` |
|||
let result = await dbUtils.query(_sql) |
|||
if (Array.isArray(result) && result.length > 0) { |
|||
result = result |
|||
} else { |
|||
result = null; |
|||
} |
|||
return result |
|||
}, |
|||
|
|||
/** |
|||
* 根据ID或者用户名查找一个存在用户的数据 |
|||
* @param {obejct} options 查找条件参数 |
|||
* @return {object|null} 查找结果 |
|||
*/ |
|||
async getExistOneByIdOrUserName(options) { |
|||
let _sql = ''; |
|||
if (options.username) { |
|||
_sql = ` |
|||
SELECT * from user_info |
|||
where username="${options.username}";` |
|||
} |
|||
if (options.id) { |
|||
_sql = ` |
|||
SELECT * from user_info |
|||
where id="${options.id}";` |
|||
} |
|||
let result = await dbUtils.query(_sql) |
|||
if (Array.isArray(result) && result.length > 0) { |
|||
result = result |
|||
} else { |
|||
result = null; |
|||
} |
|||
return result |
|||
}, |
|||
|
|||
/** |
|||
* 根据用户名和密码查找用户 |
|||
* @param {object} options 用户名密码对象 |
|||
* @return {object|null} 查找结果 |
|||
*/ |
|||
async getOneByUserName(options) { |
|||
let _sql = ` |
|||
SELECT * from user_info |
|||
where username="${options.username}";` |
|||
let result = await dbUtils.query(_sql) |
|||
if (Array.isArray(result) && result.length > 0) { |
|||
result = result |
|||
} else { |
|||
result = null; |
|||
} |
|||
return result |
|||
}, |
|||
|
|||
/** |
|||
* 根据用户名查找用户信息 |
|||
* @param {string} userName 用户账号名称 |
|||
* @return {object|null} 查找结果 |
|||
*/ |
|||
async getUserInfoByUserName(userName) { |
|||
let _sql = ` |
|||
SELECT * from user_info |
|||
where username="${userName}";`;
|
|||
let result = await dbUtils.query(_sql); |
|||
if (Array.isArray(result) && result.length > 0) { |
|||
result = result |
|||
} else { |
|||
result = null; |
|||
} |
|||
return result |
|||
}, |
|||
} |
|||
|
|||
|
|||
module.exports = user |
File diff suppressed because it is too large
@ -0,0 +1,38 @@ |
|||
{ |
|||
"name": "noderest", |
|||
"version": "1.0.0", |
|||
"description": "", |
|||
"main": "./src/main.js", |
|||
"private": true, |
|||
"scripts": { |
|||
"dev": "set DEBUG=demo:server,demo:ssc,demo:sql & cross-env PORT=3303 nodemon ./bin/www", |
|||
"db": "node ./init/index.js", |
|||
"test": "mocha" |
|||
}, |
|||
"keywords": [], |
|||
"author": "Dash Crash", |
|||
"license": "ISC", |
|||
"dependencies": { |
|||
"@koa/cors": "^2.2.3", |
|||
"async": "^3.1.0", |
|||
"bcryptjs": "^2.4.3", |
|||
"debug": "^4.1.1", |
|||
"jsonwebtoken": "^8.5.1", |
|||
"koa": "^2.11.0", |
|||
"koa-body": "^4.1.1", |
|||
"koa-jwt": "^3.6.0", |
|||
"koa-router": "^7.4.0", |
|||
"koa-static": "^5.0.0", |
|||
"lodash": "^4.17.15", |
|||
"mocha": "^6.2.2", |
|||
"module-alias": "^2.2.2", |
|||
"mysql": "^2.17.1", |
|||
"nodemon": "^1.19.4", |
|||
"pug": "^2.0.4", |
|||
"validator": "^12.0.0" |
|||
}, |
|||
"devDependencies": { |
|||
"cross-env": "^6.0.3", |
|||
"koa-views": "^6.2.1" |
|||
} |
|||
} |
@ -0,0 +1,9 @@ |
|||
extends template/layout.pug |
|||
|
|||
|
|||
block content |
|||
include ui/login.pug |
|||
|
|||
append script |
|||
//script init({nb: decode("#{data}")}) |
|||
script(src='/static/js/home.js'); |
@ -0,0 +1,3 @@ |
|||
body { |
|||
background-color: #F5F5D5; |
|||
} |
@ -0,0 +1,10 @@ |
|||
|
|||
/**************************************/ |
|||
.login-panel .mask{ |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
background-color: rgba(0, 0, 0, 0.2); |
|||
} |
@ -0,0 +1 @@ |
|||
const homeVue = init({nb: decode("#{data}")}) |
@ -0,0 +1,17 @@ |
|||
const init = (data = {}) => { |
|||
return new Vue.extend({ |
|||
data() { |
|||
return data |
|||
} |
|||
}) |
|||
} |
|||
|
|||
const decode = (text) => { |
|||
var temp = document.createElement("div"); |
|||
//2.然后将要转换的字符串设置为这个元素的innerHTML(ie,火狐,google都支持)
|
|||
temp.innerHTML = text; |
|||
//3.最后返回这个元素的innerText(ie支持)或者textContent(火狐,google支持),即得到经过HTML解码的字符串了。
|
|||
var output = temp.innerText || temp.textContent; |
|||
temp = null; |
|||
return output |
|||
} |
@ -0,0 +1 @@ |
|||
footer |
@ -0,0 +1 @@ |
|||
header |
@ -0,0 +1,19 @@ |
|||
//- https://pug.bootcss.com/language/inheritance.html |
|||
|
|||
html |
|||
head |
|||
title 我的站点 |
|||
block css |
|||
link(href='/static/css/index.css' rel='stylesheet') |
|||
link(href='/static/css/style.css' rel='stylesheet') |
|||
body |
|||
#app |
|||
block header |
|||
include header.pug |
|||
block content |
|||
block foot |
|||
include footer.pug |
|||
block script |
|||
script(src='https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js') |
|||
script(src='https://cdn.jsdelivr.net/npm/vue/dist/vue.js') |
|||
script(src='/static/js/index.js') |
@ -0,0 +1,3 @@ |
|||
.login-panel |
|||
.mask |
|||
div {{nb}} |
@ -0,0 +1,13 @@ |
|||
## 约定 |
|||
``` |
|||
//各个模块之间的消息传递 |
|||
//200表示正确的返回 |
|||
//其他表示处理中存在错误 |
|||
{ |
|||
code: 200, |
|||
data: null, |
|||
message: 'ok' |
|||
} |
|||
``` |
|||
|
|||
todo:将数据库操作全部改为占位符形式防止sql注入 |
@ -0,0 +1,14 @@ |
|||
var Router = require('koa-router'); |
|||
const controler = require('../../controler/index.js') |
|||
|
|||
var router = new Router(); |
|||
|
|||
router.post('/menus/getall', controler.menus.getAll); |
|||
router.post('/menus/create', controler.menus.createOne); |
|||
router.post('/menus/update', controler.menus.updateOne); |
|||
router.post('/menus/delete', controler.menus.deleteOne); |
|||
|
|||
module.exports = { |
|||
name: __dirname.split('\\')[__dirname.split('\\').length - 1], |
|||
router |
|||
}; |
@ -0,0 +1,14 @@ |
|||
var Router = require('koa-router'); |
|||
const controler = require('../../controler/index.js') |
|||
|
|||
var router = new Router(); |
|||
router.post('/login', controler.user.login); |
|||
router.post('/register', controler.user.register); |
|||
|
|||
router.get('/userinfo', controler.user.getUserinfo); |
|||
router.post('/modifyuserinfo', controler.user.modifyUserinfo); |
|||
|
|||
module.exports = { |
|||
name: __dirname.split('\\')[__dirname.split('\\').length - 1], |
|||
router |
|||
}; |
@ -0,0 +1,34 @@ |
|||
const path = require('path'); |
|||
const Bean = require('../utils/index.js'); |
|||
|
|||
const router = require('koa-router')(); |
|||
|
|||
// 路由收集规则
|
|||
const api_routes = Bean.readFileDeep(path.resolve(__dirname, 'api')).file; |
|||
const api_root = '/api'; |
|||
api_routes.forEach(route => { |
|||
if (route != path.resolve(__filename)) { |
|||
const obj = require(route); |
|||
const child_router = obj.router; |
|||
// 可以根据路由筛选动态设置路由前缀
|
|||
// const name = obj.name;
|
|||
// router.prefix('/api');
|
|||
// app.use(router.routes()).use(router.allowedMethods());
|
|||
router.use(api_root, child_router.routes(), child_router.allowedMethods()) |
|||
} |
|||
}); |
|||
|
|||
const views_routes = Bean.readFileDeep(path.resolve(__dirname, 'views')).file; |
|||
const views_root = '/'; |
|||
views_routes.forEach(route => { |
|||
if (route != path.resolve(__filename)) { |
|||
const obj = require(route); |
|||
const child_router = obj.router; |
|||
// 可以根据路由筛选动态设置路由前缀
|
|||
// const name = obj.name;
|
|||
// router.prefix('/api');
|
|||
// app.use(router.routes()).use(router.allowedMethods());
|
|||
router.use(views_root, child_router.routes(), child_router.allowedMethods()) |
|||
} |
|||
}); |
|||
module.exports = router |
@ -0,0 +1,12 @@ |
|||
var Router = require('koa-router'); |
|||
const controler = require('../../controler/index.js') |
|||
|
|||
var router = new Router(); |
|||
|
|||
router.get('/', controler.views.home); |
|||
|
|||
|
|||
module.exports = { |
|||
name: __dirname.split('\\')[__dirname.split('\\').length - 1], |
|||
router |
|||
}; |
@ -0,0 +1,84 @@ |
|||
const menus = require('./../models/menus'); |
|||
|
|||
//菜单的增删改查
|
|||
const menuServices = { |
|||
// 获取所有菜单
|
|||
async getAllMenus() { |
|||
let result = await menus.getAllMenus(); |
|||
return result |
|||
}, |
|||
|
|||
async createMenu(model) { |
|||
let result = await menus.ceateMenu(model); |
|||
return result |
|||
}, |
|||
|
|||
async judgeID(id) { |
|||
let result = await menus.getMenusByID(id); |
|||
if (result){ |
|||
result = result[0]; |
|||
let belong = await menus.getMenusByBelongTo(result.id); |
|||
if (belong){ |
|||
if (belong.length>0){ |
|||
return belong; |
|||
} else { |
|||
return null; |
|||
} |
|||
}else { |
|||
return null; |
|||
} |
|||
}else { |
|||
return null; |
|||
} |
|||
}, |
|||
async deleteMenu(model,list,fix) { |
|||
let id = model.id; |
|||
let result = await menus.deleteMenu(id,list,fix); |
|||
return result |
|||
}, |
|||
async updateMenu(model) { |
|||
let data = { |
|||
...model, |
|||
// modifiedTime: new Date().getTime()
|
|||
} |
|||
let id = data.id; |
|||
delete data.id; |
|||
let result = await menus.update(data,id); |
|||
return result |
|||
}, |
|||
/** |
|||
* 验证所需要的参数 |
|||
* @param model |
|||
* @returns {Promise<void>} |
|||
*/ |
|||
async validatorNeed(model,keys=[]) { |
|||
let result = { |
|||
success: true, |
|||
message: '', |
|||
data: null |
|||
} |
|||
for (let key of keys){ |
|||
let notHaveValue = model[key.key]==undefined |
|||
if (notHaveValue){ |
|||
result.success=false; |
|||
result.message=key.error; |
|||
break; |
|||
} |
|||
let notJudge = key.validate&&await key.validate(model[key.key]); |
|||
if (typeof notJudge == 'string'){ |
|||
result.success=false; |
|||
result.message=notJudge; |
|||
break; |
|||
}else if (typeof notJudge == 'boolean'&¬Judge){ |
|||
result.success=false; |
|||
result.message=key.error; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
} |
|||
|
|||
|
|||
module.exports = menuServices; |
@ -0,0 +1,176 @@ |
|||
const bcrypt = require('bcryptjs'); |
|||
const jwt = require('jsonwebtoken'); |
|||
const { |
|||
promisify |
|||
} = require('util'); |
|||
/** |
|||
* 用户业务操作 |
|||
*/ |
|||
const config = require('./../config.js'); |
|||
const validator = require('validator') |
|||
const userModel = require('./../models/user-info') |
|||
const userCode = require('./../codes/user') |
|||
|
|||
const user = { |
|||
|
|||
/** |
|||
* 创建用户 |
|||
* @param {object} user 用户信息 |
|||
* @return {object} 创建结果 |
|||
*/ |
|||
async create(user) { |
|||
let salt = await promisify(bcrypt.genSalt)(10); |
|||
let pwd = await promisify(bcrypt.hash)(user.password, salt); |
|||
user.password = pwd; |
|||
let result = await userModel.create(user) |
|||
return result |
|||
}, |
|||
/** |
|||
* 更新用户 |
|||
* @param {object} user 用户信息 |
|||
* @return {object} 创建结果 |
|||
*/ |
|||
async update(user, id) { |
|||
let data = { |
|||
...user, |
|||
modifiedTime: new Date().getTime() |
|||
} |
|||
// /不能修改用户名
|
|||
delete data.username; |
|||
// 不能修改邮箱
|
|||
delete data.email; |
|||
let resultData = await userModel.update(data, id) |
|||
return resultData |
|||
}, |
|||
/** |
|||
* 查找存在用户信息 |
|||
* @param {object} formData 查找的表单数据 |
|||
* @return {object|null} 查找结果 |
|||
*/ |
|||
async getExistOne(formData) { |
|||
let resultData = await userModel.getExistOne({ |
|||
'email': formData.email, |
|||
'username': formData.username |
|||
}) |
|||
return resultData |
|||
}, |
|||
/** |
|||
* 根据ID查找存在用户信息 |
|||
* @param {object} formData 查找的表单数据 |
|||
* @return {object|null} 查找结果 |
|||
*/ |
|||
async getExistOneByIdOrUserName(formData) { |
|||
let resultData = await userModel.getExistOneByIdOrUserName({ |
|||
'id': formData.id |
|||
}) |
|||
if (resultData) { |
|||
return resultData[0]; |
|||
} |
|||
return resultData |
|||
}, |
|||
|
|||
|
|||
/** |
|||
* 登录Token获取 |
|||
* @param {object} formData 登录表单信息 |
|||
* @return {object} 登录业务操作结果 |
|||
*/ |
|||
async validatorPwd(formData, rowData) { |
|||
let token = ''; |
|||
let isSame = await promisify(bcrypt.compare)(formData.password, rowData.password); |
|||
if (isSame) { |
|||
// 1小时的登录时间
|
|||
token = jwt.sign({ |
|||
id: rowData.id, |
|||
username: rowData.username, |
|||
}, config.share_key, { |
|||
expiresIn: '1h' |
|||
}); |
|||
token = 'Bearer ' + token; |
|||
} |
|||
return token |
|||
}, |
|||
|
|||
|
|||
/** |
|||
* 根据用户名查找用户业务操作 |
|||
* @param {string} userName 用户名 |
|||
* @return {object|null} 查找结果 |
|||
*/ |
|||
async getUserInfoByUserName(userName) { |
|||
|
|||
let resultData = await userModel.getUserInfoByUserName(userName) || {} |
|||
// let userInfo = {
|
|||
// // id: resultData.id,
|
|||
// email: resultData.email,
|
|||
// username: resultData.username,
|
|||
// detailInfo: resultData.detail_info,
|
|||
// createTime: resultData.create_time
|
|||
// }
|
|||
return resultData |
|||
}, |
|||
|
|||
|
|||
/** |
|||
* 检验用户注册数据 |
|||
* @param {object} userInfo 用户注册数据 |
|||
* @return {object} 校验结果 |
|||
*/ |
|||
validatorSignUp(userInfo) { |
|||
let result = { |
|||
success: false, |
|||
message: '', |
|||
data: null |
|||
} |
|||
if (/^[a-z0-9\_\-]{6,16}$/.test(userInfo.username || '') === false) { |
|||
result.message = userCode.ERROR_USER_NAME |
|||
return result |
|||
} |
|||
if (userInfo.email && !validator.isEmail(userInfo.email)) { |
|||
; |
|||
result.message = userCode.ERROR_EMAIL |
|||
return result |
|||
} |
|||
if (!/[\w+]{6,16}/.test(userInfo.password || '')) { |
|||
result.message = userCode.ERROR_PASSWORD |
|||
return result |
|||
} |
|||
if (userInfo.password !== userInfo.confirmPassword) { |
|||
result.message = userCode.ERROR_PASSWORD_CONFORM |
|||
return result |
|||
} |
|||
|
|||
result.success = true |
|||
return result |
|||
}, |
|||
/** |
|||
* 检验用户必须的数据 |
|||
* @param {object} userInfo 用户数据 |
|||
* @return {object} 校验结果 |
|||
*/ |
|||
validatorNeed(userInfo, needPwd = true) { |
|||
let result = { |
|||
success: false, |
|||
message: '', |
|||
} |
|||
if (!userInfo.username && !userInfo.email) { |
|||
result.success = false; |
|||
result.message = '用户名或者邮箱不能为空' |
|||
return result |
|||
} |
|||
if (userInfo.email && !validator.isEmail(userInfo.email)) { |
|||
result.success = false; |
|||
result.message = userCode.ERROR_EMAIL |
|||
return result |
|||
} |
|||
if (needPwd && !userInfo.password) { |
|||
result.success = false; |
|||
result.message = '密码不能为空' |
|||
return result |
|||
} |
|||
result.success = true |
|||
return result |
|||
} |
|||
} |
|||
|
|||
module.exports = user |
@ -0,0 +1,14 @@ |
|||
const assert = require('assert'); |
|||
const userdb = require('./../src/models/user-info.js'); |
|||
describe('#hello.js', () => { |
|||
it('0', async (done) => { |
|||
try { |
|||
let data = userdb.create({ |
|||
username: "sdada" |
|||
}); |
|||
done(); |
|||
} catch (error) { |
|||
done(error); |
|||
} |
|||
}); |
|||
}); |
@ -0,0 +1,66 @@ |
|||
const monthEnum = [ |
|||
'01', '02', '03', '04', '05', '06', |
|||
'07', '08', '09', '10', '11', '12', |
|||
] |
|||
|
|||
const dayEnum = [ |
|||
'01', '02', '03', '04', '05', '06', '07', '08', '09', '10', |
|||
'11', '12', '13', '14', '15', '16', '17', '18', '19', '20', |
|||
'21', '22', '23', '04', '25', '26', '27', '28', '29', '30', '31', |
|||
] |
|||
|
|||
const timeEnum = [ |
|||
'00', |
|||
'01', '02', '03', '04', '05', '06', '07', '08', '09', '10', |
|||
'11', '12', '13', '14', '15', '16', '17', '18', '19', '20', |
|||
'21', '22', '23', '04', '25', '26', '27', '28', '29', '30', |
|||
'31', '32', '33', '34', '35', '36', '37', '38', '39', '40', |
|||
'41', '42', '43', '44', '45', '46', '47', '48', '49', '50', |
|||
'51', '52', '53', '54', '55', '56', '57', '58', '59', |
|||
] |
|||
|
|||
const datatime = { |
|||
|
|||
parseStampToFormat(timestamp, type) { |
|||
let _date |
|||
if (timestamp) { |
|||
_date = new Date(timestamp) |
|||
} else { |
|||
_date = new Date() |
|||
} |
|||
|
|||
let parsedDate |
|||
let parseTime |
|||
let parseDatetime |
|||
|
|||
let yearNum = _date.getFullYear() |
|||
let monthNum = monthEnum[_date.getMonth()] |
|||
let dayNum = dayEnum[_date.getDate() - 1] |
|||
let hourNum = timeEnum[_date.getHours()] |
|||
let minNum = timeEnum[_date.getMinutes()] |
|||
let secNum = timeEnum[_date.getSeconds()] |
|||
|
|||
type = type || 'YYYY/MM/DD/hh/mm/ss' |
|||
|
|||
parseDatetime = type |
|||
.replace('YYYY', yearNum) |
|||
.replace('MM', monthNum) |
|||
.replace('DD', dayNum) |
|||
.replace('hh', hourNum) |
|||
.replace('mm', minNum) |
|||
.replace('ss', secNum) |
|||
|
|||
return parseDatetime |
|||
}, |
|||
|
|||
getNowDatetime() { |
|||
let timestamp = new Date().getTime() |
|||
let nowDatetime = this.parseStampToFormat(timestamp) |
|||
return nowDatetime |
|||
}, |
|||
|
|||
|
|||
|
|||
} |
|||
|
|||
module.exports = datatime |
@ -0,0 +1,162 @@ |
|||
var config = require('./../config.js') |
|||
const mysql = require("mysql") |
|||
const async = require("async"); |
|||
|
|||
const pool = mysql.createPool({ |
|||
...config.db |
|||
}) |
|||
|
|||
|
|||
// var pool = mysql.createPool({
|
|||
// host: "144.48.4.186",
|
|||
// user: "noderest",
|
|||
// password: "8WBtsejYGiEESJMh",
|
|||
// database: "noderest",
|
|||
// connectionLimit: 33,
|
|||
// port: "3306",
|
|||
// waitForConnections: false
|
|||
// });
|
|||
//mysql事务处理
|
|||
let execTrans =function(sqlparamsEntities, callback) { |
|||
//建立连接
|
|||
pool.getConnection(function (err, connection) { |
|||
if (err) { |
|||
//抛出连接错误
|
|||
return callback(err, null); |
|||
} |
|||
connection.beginTransaction(function (err) { |
|||
if (err) { |
|||
return callback(err, null); |
|||
} |
|||
console.log("开始执行transaction,共执行" + sqlparamsEntities.length + "条数据"); |
|||
var funcAry = []; |
|||
sqlparamsEntities.forEach(function (sql_param) { |
|||
var temp = function (cb) { |
|||
// var sql = sql_param.sql;
|
|||
// var param = sql_param.params;
|
|||
connection.query(sql_param, function (tErr, rows, fields) { |
|||
if (tErr) { |
|||
connection.rollback(function () { |
|||
console.log("事务失败," + sql_param + ",ERROR:" + tErr); |
|||
throw tErr; |
|||
}); |
|||
} else { |
|||
return cb(null, 'ok'); |
|||
} |
|||
}) |
|||
}; |
|||
funcAry.push(temp); |
|||
}); |
|||
|
|||
async.series(funcAry, function (err, result) { |
|||
console.log("transaction error: " + err); |
|||
if (err) { |
|||
connection.rollback(function (err) { |
|||
console.log("transaction error: " + err); |
|||
connection.release(); |
|||
return callback(err, null); |
|||
}); |
|||
} else { |
|||
connection.commit(function (err, info) { |
|||
console.log("transaction info: " + JSON.stringify(info)); |
|||
if (err) { |
|||
console.log("执行事务失败," + err); |
|||
connection.rollback(function (err) { |
|||
console.log("transaction error: " + err); |
|||
connection.release(); |
|||
return callback(err, null); |
|||
}); |
|||
} else { |
|||
connection.release(); |
|||
return callback(null, info); |
|||
} |
|||
}) |
|||
} |
|||
}) |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
let query = function (sql, values) { |
|||
return new Promise((resolve, reject) => { |
|||
pool.getConnection(function (err, connection) { |
|||
if (err) { |
|||
resolve(err) |
|||
} else { |
|||
connection.query(sql, values, (err, rows) => { |
|||
|
|||
if (err) { |
|||
reject(err) |
|||
} else { |
|||
resolve(rows) |
|||
} |
|||
connection.release() |
|||
}) |
|||
} |
|||
}) |
|||
}) |
|||
|
|||
} |
|||
|
|||
let createTable = function (sql) { |
|||
return query(sql, []) |
|||
} |
|||
|
|||
let findDataLast = function (table) { |
|||
let _sql = "SELECT * FROM ?? ORDER BY id DESC LIMIT 1;" |
|||
return query(_sql, [table]) |
|||
} |
|||
|
|||
let findDataById = function (table, id) { |
|||
let _sql = "SELECT * FROM ?? WHERE id = ? " |
|||
return query(_sql, [table, id, start, end]) |
|||
} |
|||
|
|||
|
|||
let findDataByPage = function (table, keys, start, end) { |
|||
let _sql = "SELECT ?? FROM ?? LIMIT ? , ?" |
|||
return query(_sql, [keys, table, start, end]) |
|||
} |
|||
|
|||
|
|||
let insertData = function (table, values) { |
|||
let _sql = "INSERT INTO ?? SET ?" |
|||
return query(_sql, [table, values]) |
|||
} |
|||
|
|||
|
|||
let updateData = function (table, values, id) { |
|||
let _sql = "UPDATE ?? SET ? WHERE id = ?" |
|||
return query(_sql, [table, values, id]) |
|||
} |
|||
|
|||
|
|||
let deleteDataById = function (table, id) { |
|||
let _sql = "DELETE FROM ?? WHERE id = ?" |
|||
return query(_sql, [table, id]) |
|||
} |
|||
|
|||
|
|||
let select = function (table, keys) { |
|||
let _sql = "SELECT ?? FROM ?? " |
|||
return query(_sql, [keys, table]) |
|||
} |
|||
|
|||
let count = function (table) { |
|||
let _sql = "SELECT COUNT(*) AS total_count FROM ?? " |
|||
return query(_sql, [table]) |
|||
} |
|||
|
|||
module.exports = { |
|||
query, |
|||
findDataLast, |
|||
createTable, |
|||
findDataById, |
|||
findDataByPage, |
|||
deleteDataById, |
|||
insertData, |
|||
updateData, |
|||
select, |
|||
count, |
|||
execTrans, |
|||
} |
@ -0,0 +1,26 @@ |
|||
const fs = require('fs'); |
|||
const path = require('path'); |
|||
|
|||
|
|||
module.exports = { |
|||
readFileDeep(dir) { |
|||
const routes = { |
|||
dir: [], |
|||
file: [] |
|||
}; |
|||
const routeFunc = (dirname) => { |
|||
const files = fs.readdirSync(path.resolve(dirname)); |
|||
files.forEach(file => { |
|||
if (fs.statSync(path.resolve(dirname, file)).isDirectory()) { |
|||
routes.dir.push(path.resolve(dirname, file)); |
|||
routeFunc(path.resolve(dirname, file)) |
|||
} |
|||
if (fs.statSync(path.resolve(dirname, file)).isFile()) { |
|||
routes.file.push(path.resolve(dirname, file)); |
|||
} |
|||
}) |
|||
return routes |
|||
} |
|||
return routeFunc(dir); |
|||
} |
|||
} |
@ -0,0 +1,37 @@ |
|||
const Types = { |
|||
|
|||
isPrototype(data) { |
|||
return Object.prototype.toString.call(data).toLowerCase() |
|||
}, |
|||
|
|||
isArray(data) { |
|||
return this.isPrototype(data) === '[object array]' |
|||
}, |
|||
|
|||
isJSON(data) { |
|||
return this.isPrototype(data) === '[object object]' |
|||
}, |
|||
|
|||
isFunction(data) { |
|||
return this.isPrototype(data) === '[object function]' |
|||
}, |
|||
|
|||
isString(data) { |
|||
return this.isPrototype(data) === '[object string]' |
|||
}, |
|||
|
|||
isNumber(data) { |
|||
return this.isPrototype(data) === '[object number]' |
|||
}, |
|||
|
|||
isUndefined(data) { |
|||
return this.isPrototype(data) === '[object undefined]' |
|||
}, |
|||
|
|||
isNull(data) { |
|||
return this.isPrototype(data) === '[object null]' |
|||
} |
|||
|
|||
} |
|||
|
|||
module.exports = Types |
Loading…
Reference in new issue