更新
This commit is contained in:
+55
@@ -0,0 +1,55 @@
|
||||
// https://molunerfinn.com/Use-Jest-To-Test-Vue-Koa/#Koa%E5%90%8E%E7%AB%AFApi%E6%B5%8B%E8%AF%95
|
||||
//https://jestjs.io/docs/api#testeachtablename-fn-timeout
|
||||
//Jest CLI选项 : https://runebook.dev/zh-CN/docs/jest/cli#--forceexit
|
||||
//匹配器:https://www.jianshu.com/p/c1b5676c1edd
|
||||
const bamboo = require('./lib/main')
|
||||
const glob = require("glob")
|
||||
const path = require('path')
|
||||
import request from 'supertest';
|
||||
|
||||
let server = ""
|
||||
let list = []
|
||||
|
||||
/*当前根目录*/
|
||||
function isPath(args) {
|
||||
return path.resolve('./' + (args || ""))
|
||||
}
|
||||
|
||||
function load(directory) {
|
||||
const path_root = isPath()
|
||||
let files = glob.sync(directory)
|
||||
files = files.map(item => {
|
||||
const parse = path.parse(item);
|
||||
parse.father = path.basename(path.resolve(parse.dir, '..'))
|
||||
parse.file_father = path.basename(path.resolve(parse.dir + '/' + parse.name, '..'))
|
||||
return {
|
||||
parse,
|
||||
res: require(path.resolve(path_root + "/" + item))
|
||||
}
|
||||
})
|
||||
return files
|
||||
}
|
||||
|
||||
list = load("app/*/test/*.js")
|
||||
|
||||
beforeAll(() => {
|
||||
return new Promise((resolve, reject) => {
|
||||
bamboo.fullList.push(async (app) => {
|
||||
server = app.server
|
||||
//回复测试数据镜像sql文件
|
||||
await app.db.tool.reduction()
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
|
||||
});
|
||||
afterAll(() => {
|
||||
server.close();
|
||||
console.log('服务器关闭!');
|
||||
});
|
||||
|
||||
|
||||
describe.each(list)('测试清单名称:$res.describe_name', (testDescribe) => {
|
||||
test.each(testDescribe.res.testList)('测试名称:$test_name', async (o) => await o.fun(request, server));
|
||||
});
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
/*系统启动后要做初始化*/
|
||||
module.exports = (app) => {
|
||||
console.log("启动完成");
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
module.exports = {
|
||||
doc: "用户",
|
||||
api: true,//是否需要生成api接口
|
||||
model: {
|
||||
uid: {type: "STRING", comment: '用户id'},
|
||||
age: {type: "INTEGER", comment: '年龄', defaultValue: 0},
|
||||
age2: {type: "INTEGER", comment: '年龄', defaultValue: 0},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
module.exports = {
|
||||
doc : "用户信息表",
|
||||
model: {
|
||||
uid : {type: "STRING", comment: '用户id'},
|
||||
phone: {type: "STRING", comment: '手机号', defaultValue: null,},
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
// path : "cms/api/index",//可以覆盖自动生成的路由地址
|
||||
params: {
|
||||
"age": "int?"
|
||||
},
|
||||
fun : async (ctx, app) => {
|
||||
|
||||
const body = ctx.params
|
||||
const User = await app.db.table("User").find()
|
||||
//成功返回的2种方式
|
||||
// ctx.body = app.res.success(User,"success",200)//"success",200可以省略
|
||||
return User
|
||||
|
||||
//异常返回的2种方式
|
||||
// ctx.body = app.res.error(User, "error", 400)//"error",400可以省略
|
||||
// return false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
name:"加入房间",
|
||||
doc:``,
|
||||
params: {
|
||||
"type": ["accountPassword"],//登录类型
|
||||
"data": "object",//数据
|
||||
},
|
||||
fun : async (ctx, app) => {
|
||||
const {type, data} = ctx.params
|
||||
if (await $components.login[type](data)) {
|
||||
return $res.success({
|
||||
token: await $components.jwt.sign({})
|
||||
}, "登录成功")
|
||||
}
|
||||
|
||||
|
||||
return $res.error({}, "登录失败")
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
module.exports = {
|
||||
name : "离开房间",
|
||||
doc : ``,
|
||||
params: {
|
||||
// "room_name": 'string',//房间
|
||||
// "uid" : 'string',//用户id
|
||||
},
|
||||
fun : (socket, {msg, onname, callback}) => {
|
||||
console.log('断线:', socket.id);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
module.exports = {
|
||||
name : "加入房间",
|
||||
doc : ``,
|
||||
params: {
|
||||
"room_name": 'string',//房间
|
||||
"uid" : 'string',//用户id
|
||||
},
|
||||
fun : (socket, {msg, onname, callback}) => {
|
||||
console.log('加入房间:', msg);
|
||||
socket.join(msg.room_name)//加入房间
|
||||
socket.emit('success', {
|
||||
event: onname,
|
||||
res : app.res.success(""),
|
||||
})
|
||||
socket.to(msg.room_name).emit('success', {
|
||||
event: onname,
|
||||
res : app.res.success(msg, "有人加入房间"),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
module.exports = {
|
||||
name : "离开房间",
|
||||
doc : ``,
|
||||
params: {
|
||||
// "room_name": 'string',//房间
|
||||
// "uid" : 'string',//用户id
|
||||
},
|
||||
fun : (socket, {msg, onname, callback}) => {
|
||||
console.log('离开房间:', socket.id);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
module.exports = (app, msg, callback) => {
|
||||
console.log('接收到的消息:', msg);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
module.exports = {
|
||||
doc: "联系人表",
|
||||
api: true,//是否需要生成api接口
|
||||
model: {
|
||||
uid: {type: "STRING", comment: '用户id/群id'},
|
||||
to_uid: {type: "STRING", comment: '接收人用户id'},
|
||||
type: {type: "STRING", comment: '类型,单人/群:one/group'},
|
||||
status: {type: "STRING", comment: '状态:已结束/未结束:y/n'},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
module.exports = {
|
||||
doc: "消息表",
|
||||
api: true,//是否需要生成api接口
|
||||
model: {
|
||||
uid: {type: "STRING", comment: '发送人用户id'},
|
||||
name: {type: "STRING", comment: '发送人名称'},
|
||||
avatar: {type: "STRING", comment: '发送人头像'},
|
||||
to_uid: {type: "STRING", comment: '接收人用户id'},
|
||||
to_name: {type: "STRING", comment: '接收人名称'},
|
||||
to_avatar: {type: "STRING", comment: '接收人头像'},
|
||||
status: {type: "STRING", comment: '状态:已读/未读:y/n'},
|
||||
type: {type: "STRING", comment: '消息类型:file / image / text / event'},
|
||||
sendTime: {type: "STRING", comment: '消息发送时间'},
|
||||
content: {type: "STRING", comment: '消息内容,如果type=file,此属性表示文件的URL地址'},
|
||||
fileSize: {type: "STRING", comment: '文件大小'},
|
||||
fileName: {type: "STRING", comment: '文件名称'},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
module.exports = {
|
||||
doc: "自动回复表",
|
||||
api: true,//是否需要生成api接口
|
||||
model: {
|
||||
type: {type: "STRING", comment: '类型,自动回复/问候语:auto/hello'},
|
||||
status: {type: "STRING", comment: '状态:显示/隐藏:y/n'},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
module.exports = {
|
||||
describe_name: "permission/权限管理",
|
||||
testList : [
|
||||
{
|
||||
test_name: "账号密码注册",
|
||||
fun : async (request, server) => {
|
||||
const response = await request(server)
|
||||
.post('/permission/api/registered')
|
||||
.send({
|
||||
type: "accountPassword",
|
||||
data: {
|
||||
account : "test",
|
||||
password: "123456",
|
||||
},
|
||||
})
|
||||
// expect(response.status).toEqual(200)
|
||||
expect(response.body.status).toEqual(200)
|
||||
expect(response.body.data).toHaveProperty('token')
|
||||
}
|
||||
},
|
||||
{
|
||||
test_name: "账号密码登录",
|
||||
fun : async (request, server) => {
|
||||
const response = await request(server)
|
||||
.post('/permission/api/login')
|
||||
.send({
|
||||
type: "accountPassword",
|
||||
data: {
|
||||
account : "test",
|
||||
password: "123456",
|
||||
},
|
||||
})
|
||||
// expect(response.status).toEqual(200)
|
||||
expect(response.body.status).toEqual(200)
|
||||
expect(response.body.data).toHaveProperty('token')
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
params: {
|
||||
"type": ["accountPassword"],//登录类型
|
||||
"data": "object",//数据
|
||||
},
|
||||
fun : async (ctx, app) => {
|
||||
const {type, data} = ctx.params
|
||||
if (await $components.login[type](data)) {
|
||||
return $res.success({
|
||||
token: await $components.jwt.sign({})
|
||||
}, "登录成功")
|
||||
}
|
||||
|
||||
|
||||
return $res.error({}, "登录失败")
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
params: {
|
||||
"type": ["accountPassword"],//注册类型
|
||||
"data": "object",//数据
|
||||
},
|
||||
fun : async (ctx, app) => {
|
||||
const {type, data} = ctx.params
|
||||
if (await $components.registered[type](data)) {
|
||||
return $res.success({
|
||||
token: await $components.jwt.sign({})
|
||||
}, "注册成功")
|
||||
}
|
||||
|
||||
return $res.error({}, "登录失败")
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
module.exports = {
|
||||
//获取用户所属组织信息
|
||||
async getUserToOrg(uid) {
|
||||
|
||||
},
|
||||
//获取用户所属分组信息
|
||||
async getUserToGroup(uid) {
|
||||
|
||||
},
|
||||
//获取用户权限
|
||||
async getUserToPermission(uid) {
|
||||
|
||||
},
|
||||
//获取用户角色信息
|
||||
async getUserToRole(uid) {
|
||||
|
||||
},
|
||||
//获取用户组织/分组/角色/权限
|
||||
async getUserAll(uid) {
|
||||
|
||||
},
|
||||
//获取组织下全部分组
|
||||
async getOrgToGroupAll(uid) {
|
||||
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
const crypto = require('crypto');
|
||||
module.exports = {
|
||||
// 随机数(盐值)
|
||||
getRandomSalt() {
|
||||
return Math.random().toString().slice(2, 5);
|
||||
},
|
||||
// 加密用户密码(原始密码,盐值)
|
||||
// 密码同样是123456,由于采用了随机盐值,前后运算得出的结果是不同的。
|
||||
// 这样带来的好处是,多个用户,同样的密码,攻击者需要进行多次运算才能够完全破解。
|
||||
// 同样是纯数字3位短盐值,随机盐值破解所需的运算量,是固定盐值的1000倍。
|
||||
cryptPwd(password, salt) {
|
||||
|
||||
// 密码“加盐”
|
||||
const saltPassword = password + ':' + salt;
|
||||
// 加盐密码的md5值
|
||||
const md5 = crypto.createHash('md5');
|
||||
return md5.update(saltPassword).digest('hex');
|
||||
},
|
||||
// 密码验证,如果验证通过 返回 true
|
||||
cryptPwdVerification(password, salt, user_password_md5) {
|
||||
return this.cryptPwd(password, salt) === user_password_md5;
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
secret : 'sQ6CIfqS4SqF1zZqRZbCDAT5@T]X4fCD',//秘钥
|
||||
algorithm: 'HS256',//数字签名或 MAC 算法
|
||||
expiresIn: "7d",//有效期:例如:1000, "2 days", "10h", "7d". 数值被解释为秒数。如果使用字符串,请确保提供时间单位(天、小时等),否则默认使用毫秒单位("120"等于"120ms")。
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
const jwt = require("jsonwebtoken");
|
||||
const config = require("./config.js");
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* 签发token
|
||||
* @param {object} data 加入到签名里的数据.
|
||||
* @return {string} token 令牌.
|
||||
*/
|
||||
sign: (data) => jwt.sign(data, config.secret, {algorithm: config.algorithm, expiresIn: config.expiresIn}),
|
||||
/**
|
||||
* 验证token
|
||||
* @param {string} token 令牌.
|
||||
* @return {boolean} 验证通过返回true.
|
||||
*/
|
||||
verify: (token) => jwt.verify(token, config.secret, {algorithm: config.algorithm, expiresIn: config.expiresIn}),
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* app.components.login.accountPassword
|
||||
* 账号密码登陆
|
||||
* @param {string} data.account 账号.
|
||||
* @param {string} data.password 密码.
|
||||
* @return {object} res 验证是否通过.
|
||||
*/
|
||||
module.exports = async (data) => {
|
||||
const {account, password} = data
|
||||
const User = await app.db.table("User").where({account}).find()
|
||||
if (!User) return false
|
||||
const {salt} = User
|
||||
const ver = app.components.encrypt.cryptPwdVerification(password, salt, User.password)
|
||||
return ver
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* app.components.registered.accountPassword
|
||||
* 账号密码注册
|
||||
* @param {string} data.account 账号.
|
||||
* @param {string} data.password 密码.
|
||||
* @return {boolean} 注册 是否 成功.
|
||||
*/
|
||||
module.exports = async (data) => {
|
||||
const {account, password} = data
|
||||
const salt = app.components.encrypt.getRandomSalt()
|
||||
const md5 = app.components.encrypt.cryptPwd(password, salt)
|
||||
await app.db.table("User").data({account, password: md5, salt}).save()
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
path : "app/*/api/*.js",
|
||||
prefix : "",//接口前缀
|
||||
statusTobody: true,//是否跟随body结果(如需接口报错也返回200,那么设置为false)
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
'use strict';
|
||||
/**
|
||||
* RBAC用户、角色、权限、组设
|
||||
* saas的权限验证
|
||||
*/
|
||||
const config = require("./config")
|
||||
|
||||
// 错误处理
|
||||
module.exports = {
|
||||
sort : 1, //排序
|
||||
use : true, // 是否使用
|
||||
fun : async (ctx, next, app) => {
|
||||
|
||||
|
||||
await next()
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
module.exports = {
|
||||
doc: "分组表",
|
||||
api: true,//是否需要生成api接口
|
||||
model: {
|
||||
gid: {type: "STRING", comment: '分组id'},
|
||||
name: {type: "STRING", comment: '分组名称'},
|
||||
to_gid: {type: "STRING", comment: '上级分组id'},
|
||||
to_oid: {type: "STRING", comment: '所属组织id'},
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
module.exports = {
|
||||
doc: "组织表",
|
||||
api: true,//是否需要生成api接口
|
||||
model: {
|
||||
oid: {type: "STRING", comment: '组织id'},
|
||||
name: {type: "STRING", comment: '组织名称'},
|
||||
general_management: {type: "STRING", comment: '是否为总管理平台(可以管理所有组织)'},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
module.exports = {
|
||||
doc: "权限列表",
|
||||
api: true,//是否需要生成api接口
|
||||
model: {
|
||||
pid: {type: "STRING", comment: '权限id'},
|
||||
to_pccode: {type: "STRING", comment: '所属权限分类码'},
|
||||
name: {type: "STRING", comment: '权限名称'},
|
||||
code: {type: "STRING", comment: '权限识别码'},
|
||||
value: {type: "STRING", comment: '权限值'},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
module.exports = {
|
||||
doc: "权限分类表",
|
||||
api: true,//是否需要生成api接口
|
||||
model: {
|
||||
name: {type: "STRING", comment: '权限分类名称'},
|
||||
pccode: {type: "STRING", comment: '权限分类识别码'},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
module.exports = {
|
||||
doc: "角色表",
|
||||
api: true,//是否需要生成api接口
|
||||
model: {
|
||||
rid: {type: "STRING", comment: '角色id'},
|
||||
name: {type: "STRING", comment: '角色名称'},
|
||||
to_rid: {type: "STRING", comment: '上级角色id'},
|
||||
to_oid: {type: "STRING", comment: '所属组织id'},
|
||||
to_gid: {type: "STRING", comment: '所属分组id'},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
module.exports = {
|
||||
doc: "角色拥有的权限",
|
||||
api: true,//是否需要生成api接口
|
||||
model: {
|
||||
rpid: {type: "STRING", comment: '角色权限id'},
|
||||
to_rid: {type: "STRING", comment: '角色id'},
|
||||
to_pid: {type: "STRING", comment: '权限id'},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
module.exports = {
|
||||
doc: "用户表",
|
||||
api: true,//是否需要生成api接口
|
||||
model: {
|
||||
uid: {type: "STRING", comment: '用户id'},
|
||||
account: {type: "STRING", comment: '用户账号'},
|
||||
password: {type: "STRING", comment: '用户加密密码'},
|
||||
salt: {type: "STRING", comment: '用户加密随机数'},
|
||||
to_oid: {type: "STRING", comment: '所属组织id'},
|
||||
to_gid: {type: "STRING", comment: '所属分组id'},
|
||||
to_rid: {type: "STRING", comment: '所属角色id'},
|
||||
to_uid: {type: "STRING", comment: '上级用户id'},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
module.exports = {
|
||||
doc: "用户资料表",
|
||||
api: true,//是否需要生成api接口
|
||||
model: {
|
||||
uid: {type: "STRING", comment: '用户id'},
|
||||
account: {type: "STRING", comment: '用户账号'},
|
||||
name: {type: "STRING", comment: '名称'},
|
||||
avatar: {type: "STRING", comment: '头像'},
|
||||
wechat_openid: {type: "STRING", comment: '微信openid'},
|
||||
phone_number: {type: "STRING", comment: '手机号'},
|
||||
age: {type: "STRING", comment: '年龄'},
|
||||
sex: {type: "STRING", comment: '性别'},
|
||||
province: {type: "STRING", comment: '省份'},
|
||||
city: {type: "STRING", comment: '城市'},
|
||||
area: {type: "STRING", comment: '地区'},
|
||||
address: {type: "STRING", comment: '详细地址'},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
module.exports = {
|
||||
describe_name: "permission/权限管理",
|
||||
testList : [
|
||||
{
|
||||
test_name: "账号密码注册",
|
||||
fun : async (request, server) => {
|
||||
const response = await request(server)
|
||||
.post('/permission/api/registered')
|
||||
.send({
|
||||
type: "accountPassword",
|
||||
data: {
|
||||
account : "test",
|
||||
password: "123456",
|
||||
},
|
||||
})
|
||||
// expect(response.status).toEqual(200)
|
||||
expect(response.body.status).toEqual(200)
|
||||
expect(response.body.data).toHaveProperty('token')
|
||||
}
|
||||
},
|
||||
{
|
||||
test_name: "账号密码登录",
|
||||
fun : async (request, server) => {
|
||||
const response = await request(server)
|
||||
.post('/permission/api/login')
|
||||
.send({
|
||||
type: "accountPassword",
|
||||
data: {
|
||||
account : "test",
|
||||
password: "123456",
|
||||
},
|
||||
})
|
||||
// expect(response.status).toEqual(200)
|
||||
expect(response.body.status).toEqual(200)
|
||||
expect(response.body.data).toHaveProperty('token')
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
presets: [['@babel/preset-env', { targets: { node: 'current' } }]],
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
/*应用配置*/
|
||||
module.exports = {
|
||||
port: 3000,
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
/*缓存配置*/
|
||||
@@ -1 +0,0 @@
|
||||
/*控制台配置*/
|
||||
@@ -1,77 +0,0 @@
|
||||
/*数据库配置*/
|
||||
module.exports = {
|
||||
mysql : {
|
||||
database: "bamboo",
|
||||
username: "bamboo",
|
||||
password: "bamboo",
|
||||
options : {
|
||||
dialect: 'mysql',
|
||||
host : "192.168.1.26",
|
||||
port : 3306,
|
||||
// 禁用日志记录或提供自定义日志记录功能;默认值:console.log
|
||||
// logging: false,
|
||||
// model的全局配置
|
||||
define: {
|
||||
// 添加create,update,delete时间戳
|
||||
timestamps: true,
|
||||
// 添加软删除
|
||||
paranoid: false,
|
||||
// 防止修改表名为复数
|
||||
freezeTableName: true,
|
||||
// 防止驼峰式字段被默认转为下划线
|
||||
underscored: false,
|
||||
},
|
||||
// 由于orm用的UTC时间,这里必须加上东八区,否则取出来的时间相差8小时
|
||||
timezone: '+08:00',
|
||||
// 连接数 = ((核心数 * 2) + 有效磁盘数)
|
||||
pool : {// 连接池
|
||||
max : require('os').cpus().length * 2 + 1,
|
||||
min : 0,
|
||||
acquire: 60000,
|
||||
idle : 100000,
|
||||
},
|
||||
dialectOptions: {
|
||||
charset : "utf8mb4",
|
||||
collate : "utf8mb4_general_ci",
|
||||
supportBigNumbers: true,
|
||||
bigNumberStrings : true,
|
||||
dateStrings : true,
|
||||
typeCast(field, next) {// 让读取date类型数据时返回字符串而不是UTC时间
|
||||
if (field.type === 'DATETIME') {
|
||||
// console.log(field);
|
||||
return field.string();
|
||||
}
|
||||
return next();
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
redis : {},
|
||||
sqlite: {
|
||||
dialect: 'sqlite',
|
||||
storage: 'app/sqlite/database.sqlite',
|
||||
logging: false,
|
||||
// model的全局配置
|
||||
define : {
|
||||
// 添加create,update,delete时间戳
|
||||
timestamps: true,
|
||||
// 添加软删除
|
||||
paranoid: false,
|
||||
// 防止修改表名为复数
|
||||
freezeTableName: true,
|
||||
// 防止驼峰式字段被默认转为下划线
|
||||
underscored: false,
|
||||
},
|
||||
dialectOptions: {
|
||||
typeCast(field, next) {// 让读取date类型数据时返回字符串而不是UTC时间
|
||||
if (field.type === 'DATETIME') {
|
||||
// console.log(field);
|
||||
return field.string();
|
||||
}
|
||||
return next();
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
module.exports = {
|
||||
dir: {
|
||||
"event" : "app/*/event/*.js",
|
||||
"status" : "app/*/status/*.js",
|
||||
"controller": "app/*/controller/*.js",
|
||||
"model" : "app/*/model/*.js",
|
||||
"middleware": "middleware/*.js",
|
||||
"extend" : "extend/*.js",
|
||||
"schedule" : "schedule/*.js",
|
||||
"sqlite" : "sqlite/model/*.js",
|
||||
"config" : "config/*.js",
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
/*文件磁盘配置*/
|
||||
@@ -0,0 +1,5 @@
|
||||
//全局配置,权重大于中间件配置与插件配置
|
||||
// 如果设置了全局配置,会覆盖中间件配置与插件配置
|
||||
module.exports = {
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*日志配置*/
|
||||
'use strict';
|
||||
module.exports = {
|
||||
replaceConsole: true,
|
||||
pm2 : true,
|
||||
appenders : {
|
||||
stdout: {//控制台输出
|
||||
type: 'console'
|
||||
},
|
||||
req : { //请求转发日志
|
||||
type : 'dateFile', //指定日志文件按时间打印
|
||||
filename : 'logs/req/req', //指定输出文件路径
|
||||
pattern : 'yyyy-MM-dd.log',
|
||||
alwaysIncludePattern: true
|
||||
},
|
||||
err : { //错误日志
|
||||
type : 'dateFile',
|
||||
filename : 'logs/err/err',
|
||||
pattern : 'yyyy-MM-dd.log',
|
||||
alwaysIncludePattern: true
|
||||
},
|
||||
oth : { //其他日志
|
||||
type : 'dateFile',
|
||||
filename : 'logs/oth/oth',
|
||||
pattern : 'yyyy-MM-dd.log',
|
||||
alwaysIncludePattern: true
|
||||
}
|
||||
|
||||
},
|
||||
categories : {
|
||||
//appenders:采用的appender,取appenders项,level:设置级别
|
||||
default: {appenders: ['stdout', 'req'], level: 'debug'},
|
||||
err : {appenders: ['stdout', 'err'], level: 'error'},
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
export default {
|
||||
routerPlus: {
|
||||
enable: true,
|
||||
package: 'egg-router-plus',
|
||||
},
|
||||
jwt: {
|
||||
enable: true,
|
||||
package: "egg-jwt"
|
||||
},
|
||||
cors: {
|
||||
enable: true,
|
||||
package: 'egg-cors',
|
||||
},
|
||||
validate: {
|
||||
enable: true,
|
||||
package: 'egg-validate',
|
||||
},
|
||||
sequelize:{
|
||||
enable: true,
|
||||
package: 'egg-sequelize',
|
||||
},
|
||||
axiosPlus: {
|
||||
enable: true,
|
||||
package: 'egg-axios-plus',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
/*URL和路由配置*/
|
||||
@@ -0,0 +1,47 @@
|
||||
//更多配置:http://axios-js.com/zh-cn/docs/index.html#%E8%AF%B7%E6%B1%82%E9%85%8D%E7%BD%AE
|
||||
|
||||
module.exports = {
|
||||
// `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
|
||||
// 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
|
||||
baseURL: 'https://some-domain.com/api/',
|
||||
// `headers` 是即将被发送的自定义请求头
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'},
|
||||
// `timeout` 指定请求超时的毫秒数(0 表示无超时时间)
|
||||
// 如果请求话费了超过 `timeout` 的时间,请求将被中断
|
||||
timeout: 30 * 1000,
|
||||
|
||||
// `withCredentials` 表示跨域请求时是否需要使用凭证
|
||||
withCredentials: false, // default
|
||||
|
||||
// `responseType` 表示服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
|
||||
responseType: 'json', // default
|
||||
|
||||
// `responseEncoding` indicates encoding to use for decoding responses
|
||||
// Note: Ignored for `responseType` of 'stream' or client-side requests
|
||||
responseEncoding: 'utf8', // default
|
||||
|
||||
// `xsrfCookieName` 是用作 xsrf token 的值的cookie的名称
|
||||
xsrfCookieName: 'XSRF-TOKEN', // default
|
||||
|
||||
// `xsrfHeaderName` is the name of the http header that carries the xsrf token value
|
||||
xsrfHeaderName: 'X-XSRF-TOKEN', // default
|
||||
|
||||
// `maxContentLength` 定义允许的响应内容的最大尺寸
|
||||
// maxContentLength: 2000,
|
||||
|
||||
// `maxRedirects` 定义在 node.js 中 follow 的最大重定向数目
|
||||
// 如果设置为0,将不会 follow 任何重定向
|
||||
// maxRedirects: 5, // default
|
||||
|
||||
// 'proxy' 定义代理服务器的主机名称和端口
|
||||
// `auth` 表示 HTTP 基础验证应当用于连接代理,并提供凭据
|
||||
// 这将会设置一个 `Proxy-Authorization` 头,覆写掉已有的通过使用 `header` 设置的自定义 `Proxy-Authorization` 头。
|
||||
// proxy: {
|
||||
// host: '127.0.0.1',
|
||||
// port: 9000,
|
||||
// auth: {
|
||||
// username: 'mikeymike',
|
||||
// password: 'rapunz3l'
|
||||
// }
|
||||
// },
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Axios 是一个基于 promise 的 HTTP 库
|
||||
*/
|
||||
const config = require("./config")
|
||||
const axios = require('axios');
|
||||
const request = require('./request');
|
||||
const requestError = require('./request.error');
|
||||
const response = require('./response');
|
||||
const responseError = require('./response.error');
|
||||
module.exports = async (app) => {
|
||||
Object.assign(axios.defaults, config)
|
||||
axios.interceptors.request.use(request,requestError)
|
||||
axios.interceptors.response.use(response,responseError)
|
||||
app.axios = axios
|
||||
app.alias["$axios"] = app.axios
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
//请求拦截器错误时
|
||||
module.exports = (error) => {
|
||||
// 对请求错误做些什么
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
//请求拦截器
|
||||
module.exports = (config) => {
|
||||
// 在发送请求之前做些什么
|
||||
return config;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
//响应拦截器错误时
|
||||
module.exports = (error) => {
|
||||
// 对请求错误做些什么
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
//响应拦截器
|
||||
module.exports = (response) => {
|
||||
// 对响应数据做点什么
|
||||
return response;
|
||||
}
|
||||
+2
-2
@@ -1,14 +1,14 @@
|
||||
module.exports = {
|
||||
success: (body, msg, status) => {
|
||||
return {
|
||||
res : body || null,
|
||||
data : body || null,
|
||||
status: status || 200,
|
||||
message : msg || "success"
|
||||
}
|
||||
},
|
||||
error : (body, msg, status) => {
|
||||
return {
|
||||
res : body || null,
|
||||
data : body || null,
|
||||
status: status || 400,
|
||||
message : msg || "error"
|
||||
}
|
||||
|
||||
@@ -6,4 +6,5 @@ const body = require("./body")
|
||||
|
||||
module.exports = async (app) => {
|
||||
app.res = body
|
||||
app.alias["$res"] = app.res
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ const config = require("./config")
|
||||
const mq = require("./queue")
|
||||
module.exports = async (app) => {
|
||||
app.mq = mq
|
||||
|
||||
app.alias["$mq"] = app.mq
|
||||
|
||||
const queueName = "boobam_schedule"
|
||||
const queue = mq.Queue(queueName);
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
path : "components/*/*.js",
|
||||
app_path: "app/*/components/*/*.js",
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* 通用组件
|
||||
* 加载components文件夹下的函数
|
||||
*/
|
||||
const config = require("./config")
|
||||
module.exports = async (app) => {
|
||||
const list = await app.load(config.path)
|
||||
Object.assign(list, await app.load(config.app_path))
|
||||
app.components = {}
|
||||
list.forEach(item => {
|
||||
if (!app.components[item.parse.file_father]) {
|
||||
app.components[item.parse.file_father] = {}
|
||||
}
|
||||
if (item.parse.name==='index') {
|
||||
Object.assign(app.components[item.parse.file_father],item.res)
|
||||
}else {
|
||||
app.components[item.parse.file_father][item.parse.name] = item.res
|
||||
}
|
||||
})
|
||||
app.alias["$components"] = app.components
|
||||
}
|
||||
@@ -6,6 +6,7 @@ const config = require("./config")
|
||||
const EventEmitter = require('events');
|
||||
module.exports = async (app) => {
|
||||
app.event = new EventEmitter()
|
||||
app.alias["$event"] = app.event
|
||||
const list = await app.load(config.path)
|
||||
list.forEach(item => {
|
||||
Object.keys(item.res).forEach(key => {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
module.exports = {
|
||||
path:"middleware/*/index.js"
|
||||
path:"middleware/*/index.js",
|
||||
app_path: "app/*/middleware/*/index.js",
|
||||
}
|
||||
|
||||
@@ -2,17 +2,23 @@
|
||||
* 加载中间件
|
||||
* 加载app/middleware文件夹下的中间件
|
||||
*/
|
||||
|
||||
const config = require("./config")
|
||||
module.exports = async (app) => {
|
||||
let list = await app.load(config.path)
|
||||
let list2 = await app.load(config.app_path)
|
||||
list=[...list,...list2]
|
||||
// Object.assign(list, list2)
|
||||
list = app.xe.orderBy(list, "res.sort")
|
||||
list = list.filter(item => item.res.use)
|
||||
list.forEach(async item => {
|
||||
console.log('加载的中间件:',item.parse.dir);
|
||||
if (item.res.loadFun) {
|
||||
//如果中间件定义了特殊加载方法
|
||||
await item.res.loadFun(app, item.res.fun)
|
||||
} else {
|
||||
app.use(async (ctx, next) => {
|
||||
|
||||
return await item.res.fun(ctx, next, app)
|
||||
})
|
||||
}
|
||||
|
||||
+49
-49
@@ -2,22 +2,22 @@
|
||||
const Sequelize = require("sequelize");
|
||||
const xe = require("xe-utils")
|
||||
module.exports = class Api {
|
||||
constructor(sequelize,models) {
|
||||
constructor(sequelize, models) {
|
||||
this.sequelize = sequelize
|
||||
this.models = models
|
||||
this.init()
|
||||
}
|
||||
|
||||
init() {
|
||||
this.tableName = ""
|
||||
this.tableWhere = ""
|
||||
this.tableData = ""
|
||||
this.tablePage = ""
|
||||
this.tableLimit = ""
|
||||
this.tableOrder = ""
|
||||
this.tableGroup = ""
|
||||
this.tableAttributes = ""
|
||||
this.t = ""
|
||||
this.tableName = null
|
||||
this.tableWhere = null
|
||||
this.tableData = null
|
||||
this.tablePage = null
|
||||
this.tableLimit = null
|
||||
this.tableOrder = null
|
||||
this.tableGroup = null
|
||||
this.tableAttributes = null
|
||||
this.t = null
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -166,7 +166,7 @@ module.exports = class Api {
|
||||
}
|
||||
const res = await this.models[this.tableName].findOne(
|
||||
{
|
||||
where: this.tableWhere,
|
||||
where : this.tableWhere,
|
||||
transaction: this.t
|
||||
}
|
||||
)
|
||||
@@ -184,12 +184,12 @@ module.exports = class Api {
|
||||
}
|
||||
const res = await this.models[this.tableName].findAll(
|
||||
{
|
||||
where: this.tableWhere,
|
||||
offset: (this.tablePage && this.tableLimit) ? this.tablePage - 1 * this.tableLimit : null,
|
||||
limit: this.tableLimit,
|
||||
order: this.tableOrder || [['updatedAt', 'DESC']], // 时间排序
|
||||
group: this.tableGroup,
|
||||
attributes: this.tableAttributes,
|
||||
where : this.tableWhere,
|
||||
offset : (this.tablePage && this.tableLimit) ? this.tablePage - 1 * this.tableLimit : null,
|
||||
limit : this.tableLimit,
|
||||
order : this.tableOrder || [['updatedAt', 'DESC']], // 时间排序
|
||||
group : this.tableGroup,
|
||||
attributes : this.tableAttributes,
|
||||
transaction: this.t
|
||||
}
|
||||
)
|
||||
@@ -210,8 +210,8 @@ module.exports = class Api {
|
||||
}
|
||||
const res = await this.models[this.tableName].findOrCreate(
|
||||
{
|
||||
defaults: this.tableData,
|
||||
where: this.tableWhere,
|
||||
defaults : this.tableData,
|
||||
where : this.tableWhere,
|
||||
transaction: this.t
|
||||
}
|
||||
)
|
||||
@@ -232,12 +232,12 @@ module.exports = class Api {
|
||||
}
|
||||
const {count, rows} = await this.models[this.tableName].findAndCountAll(
|
||||
{
|
||||
where: this.tableWhere,
|
||||
offset: (this.tablePage && this.tableLimit) ? this.tablePage - 1 * this.tableLimit : null,
|
||||
limit: this.tableLimit,
|
||||
order: this.tableOrder || [['updatedAt', 'DESC']], // 时间排序
|
||||
group: this.tableGroup,
|
||||
attributes: this.tableAttributes,
|
||||
where : this.tableWhere,
|
||||
offset : (this.tablePage && this.tableLimit) ? this.tablePage - 1 * this.tableLimit : null,
|
||||
limit : this.tableLimit,
|
||||
order : this.tableOrder || [['updatedAt', 'DESC']], // 时间排序
|
||||
group : this.tableGroup,
|
||||
attributes : this.tableAttributes,
|
||||
transaction: this.t
|
||||
}
|
||||
)
|
||||
@@ -264,7 +264,7 @@ module.exports = class Api {
|
||||
|
||||
let res = await this.models[this.tableName].findOne(
|
||||
{
|
||||
where: this.tableWhere,
|
||||
where : this.tableWhere,
|
||||
transaction: this.t
|
||||
}
|
||||
)
|
||||
@@ -279,7 +279,7 @@ module.exports = class Api {
|
||||
await this.models[this.tableName].update(
|
||||
data,
|
||||
{
|
||||
where: this.tableWhere,
|
||||
where : this.tableWhere,
|
||||
transaction: this.t
|
||||
}
|
||||
)
|
||||
@@ -296,14 +296,14 @@ module.exports = class Api {
|
||||
await this.models[this.tableName].decrement(
|
||||
this.tableData,
|
||||
{
|
||||
where: this.tableWhere,
|
||||
where : this.tableWhere,
|
||||
transaction: this.t
|
||||
}
|
||||
)
|
||||
|
||||
res = await this.models[this.tableName].findOne(
|
||||
{
|
||||
where: this.tableWhere,
|
||||
where : this.tableWhere,
|
||||
transaction: this.t
|
||||
}
|
||||
)
|
||||
@@ -329,7 +329,7 @@ module.exports = class Api {
|
||||
}
|
||||
let res = await this.models[this.tableName].findOne(
|
||||
{
|
||||
where: this.tableWhere,
|
||||
where : this.tableWhere,
|
||||
transaction: this.t
|
||||
}
|
||||
)
|
||||
@@ -344,7 +344,7 @@ module.exports = class Api {
|
||||
await this.models[this.tableName].update(
|
||||
data,
|
||||
{
|
||||
where: this.tableWhere,
|
||||
where : this.tableWhere,
|
||||
transaction: this.t
|
||||
}
|
||||
)
|
||||
@@ -361,14 +361,14 @@ module.exports = class Api {
|
||||
await this.models[this.tableName].increment(
|
||||
this.tableData,
|
||||
{
|
||||
where: this.tableWhere,
|
||||
where : this.tableWhere,
|
||||
transaction: this.t
|
||||
}
|
||||
)
|
||||
|
||||
res = await this.models[this.tableName].findOne(
|
||||
{
|
||||
where: this.tableWhere,
|
||||
where : this.tableWhere,
|
||||
transaction: this.t
|
||||
}
|
||||
)
|
||||
@@ -387,10 +387,10 @@ module.exports = class Api {
|
||||
const res = await this.models[this.tableName].count(
|
||||
this.tableData,
|
||||
{
|
||||
where: this.tableWhere,
|
||||
order: this.tableOrder || [['updatedAt', 'DESC']], // 时间排序
|
||||
group: this.tableGroup,
|
||||
attributes: this.tableAttributes,
|
||||
where : this.tableWhere,
|
||||
order : this.tableOrder || [['updatedAt', 'DESC']], // 时间排序
|
||||
group : this.tableGroup,
|
||||
attributes : this.tableAttributes,
|
||||
transaction: this.t
|
||||
}
|
||||
)
|
||||
@@ -408,10 +408,10 @@ module.exports = class Api {
|
||||
const res = await this.models[this.tableName].sum(
|
||||
this.tableData,
|
||||
{
|
||||
where: this.tableWhere,
|
||||
order: this.tableOrder || [['updatedAt', 'DESC']], // 时间排序
|
||||
group: this.tableGroup,
|
||||
attributes: this.tableAttributes,
|
||||
where : this.tableWhere,
|
||||
order : this.tableOrder || [['updatedAt', 'DESC']], // 时间排序
|
||||
group : this.tableGroup,
|
||||
attributes : this.tableAttributes,
|
||||
transaction: this.t
|
||||
}
|
||||
)
|
||||
@@ -429,10 +429,10 @@ module.exports = class Api {
|
||||
const res = await this.models[this.tableName].max(
|
||||
this.tableData,
|
||||
{
|
||||
where: this.tableWhere,
|
||||
order: this.tableOrder || [['updatedAt', 'DESC']], // 时间排序
|
||||
group: this.tableGroup,
|
||||
attributes: this.tableAttributes,
|
||||
where : this.tableWhere,
|
||||
order : this.tableOrder || [['updatedAt', 'DESC']], // 时间排序
|
||||
group : this.tableGroup,
|
||||
attributes : this.tableAttributes,
|
||||
transaction: this.t
|
||||
}
|
||||
)
|
||||
@@ -450,10 +450,10 @@ module.exports = class Api {
|
||||
const res = await this.models[this.tableName].min(
|
||||
this.tableData,
|
||||
{
|
||||
where: this.tableWhere,
|
||||
order: this.tableOrder || [['updatedAt', 'DESC']], // 时间排序
|
||||
group: this.tableGroup,
|
||||
attributes: this.tableAttributes,
|
||||
where : this.tableWhere,
|
||||
order : this.tableOrder || [['updatedAt', 'DESC']], // 时间排序
|
||||
group : this.tableGroup,
|
||||
attributes : this.tableAttributes,
|
||||
transaction: this.t
|
||||
}
|
||||
)
|
||||
|
||||
+16
-4
@@ -1,11 +1,11 @@
|
||||
module.exports = {
|
||||
database: "bamboo",
|
||||
username: "bamboo",
|
||||
password: "bamboo",
|
||||
username: "root",
|
||||
password: "123456",
|
||||
options: {
|
||||
dialect: 'mysql',
|
||||
host: "192.168.1.26",
|
||||
port: 3306,
|
||||
host: "127.0.0.1",
|
||||
port: 3357,
|
||||
// 禁用日志记录或提供自定义日志记录功能;默认值:console.log
|
||||
// logging: false,
|
||||
// model的全局配置
|
||||
@@ -44,4 +44,16 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
path:"app/*/model/*.js",
|
||||
sqlite:{
|
||||
host: 'localhost',
|
||||
dialect: 'sqlite',
|
||||
pool: {
|
||||
max: 5,
|
||||
min: 0,
|
||||
acquire: 30000,
|
||||
idle: 10000
|
||||
},
|
||||
storage: './database.sqlite',
|
||||
operatorsAliases: false
|
||||
}
|
||||
}
|
||||
|
||||
+12
-5
@@ -2,6 +2,7 @@
|
||||
* mysql/sequelize
|
||||
*
|
||||
* 参考文档:
|
||||
* https://demopark.github.io/sequelize-docs-Zh-CN/
|
||||
* https://sequelize.org/
|
||||
* https://sequelize.org/api/v6/identifiers
|
||||
* https://www.sequelize.com.cn/
|
||||
@@ -10,6 +11,7 @@ const config = require("./config")
|
||||
const Sequelize = require("sequelize");
|
||||
const operatorsAliases = require("./operatorsAliases");
|
||||
const Api = require("./api");
|
||||
const Tool = require("./tool.js");
|
||||
module.exports = async (app) => {
|
||||
const {database, username, password, options,} = config
|
||||
const sequelize = new Sequelize(database, username, password, {
|
||||
@@ -27,11 +29,11 @@ module.exports = async (app) => {
|
||||
model[key] = res.model[key]
|
||||
}
|
||||
model['id'] = {
|
||||
type: Sequelize.INTEGER,
|
||||
comment: '表自增id',
|
||||
allowNull: false,
|
||||
unique: 'id',
|
||||
primaryKey: true,
|
||||
type : Sequelize.INTEGER,
|
||||
comment : '表自增id',
|
||||
allowNull : false,
|
||||
unique : 'id',
|
||||
primaryKey : true,
|
||||
autoIncrement: true,
|
||||
}
|
||||
sequelize.define(parse.name, model)
|
||||
@@ -41,6 +43,10 @@ module.exports = async (app) => {
|
||||
app.models = sequelize.models
|
||||
const api = new Api(sequelize, sequelize.models)
|
||||
app.db = api
|
||||
app.db.tool = new Tool(app, sequelize)
|
||||
//全局变量
|
||||
app.alias["$db"] = app.db
|
||||
|
||||
// console.log(api);
|
||||
// console.log(await app.db.table("User").find());
|
||||
|
||||
@@ -60,6 +66,7 @@ module.exports = async (app) => {
|
||||
}
|
||||
|
||||
})
|
||||
// await app.db.tool.reduction()
|
||||
|
||||
})
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
const config = require("./config")
|
||||
import mysqldump from 'mysqldump';
|
||||
|
||||
const Importer = require('mysql-import');
|
||||
|
||||
module.exports = class {
|
||||
constructor(app, sequelize) {
|
||||
this.app = app
|
||||
this.sequelize = sequelize
|
||||
this.file = this.app.root + '/' + config.database + '.sql'
|
||||
}
|
||||
|
||||
//备份数据库所有表
|
||||
async backup(file) {
|
||||
this.file = file || this.app.root + '/' + config.database + '.sql'
|
||||
console.log('备份数据库中...');
|
||||
await mysqldump({
|
||||
connection: {
|
||||
host : config.options.host,
|
||||
port : config.options.port,
|
||||
user : config.username,
|
||||
password: config.password,
|
||||
database: config.database,
|
||||
|
||||
},
|
||||
dumpToFile: this.file,
|
||||
});
|
||||
console.log('备份数据库完成:', this.file);
|
||||
}
|
||||
//还原备份sql文件
|
||||
async reduction() {
|
||||
console.time("reduction")
|
||||
//先备份旧数据
|
||||
await this.backup(this.app.root + '/' + 'extend/mysql/backup/' + Date.now() + '.sql')
|
||||
//清空数据库
|
||||
await this.sequelize.drop()
|
||||
//导入sql文件
|
||||
const importer = new Importer({
|
||||
host : config.options.host,
|
||||
port : config.options.port,
|
||||
user : config.username,
|
||||
password: config.password,
|
||||
database: config.database,
|
||||
});
|
||||
this.file = this.app.root + '/' + config.database + '.sql'
|
||||
await importer.import(this.file)
|
||||
console.timeEnd("reduction")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,2 @@
|
||||
'use strict';
|
||||
module.exports = {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* 参数验证插件
|
||||
*/
|
||||
const config = require("./config")
|
||||
const Parameter = require('parameter');
|
||||
const parameter = new Parameter();
|
||||
module.exports = async (app) => {
|
||||
app.parameter = parameter
|
||||
app.alias["$parameter"] = app.parameter
|
||||
}
|
||||
@@ -11,5 +11,7 @@ module.exports = async (app) => {
|
||||
const redis = new Redis(config);
|
||||
app.redis = redis
|
||||
app.Redis = Redis
|
||||
|
||||
//全局变量
|
||||
app.alias["$redis"] = app.redis
|
||||
app.alias["$Redis"] = app.Redis
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
module.exports = {
|
||||
path:"app/*/io/*.js",
|
||||
path: "app/*/io/*.js",
|
||||
port: 3210,
|
||||
test_port: 3211,
|
||||
}
|
||||
|
||||
@@ -7,11 +7,16 @@
|
||||
*/
|
||||
const config = require("./config")
|
||||
const path = require('path')
|
||||
const uuid = require("uuid");
|
||||
module.exports = async (app) => {
|
||||
const parameter = app.parameter
|
||||
const server = require('http').createServer(app.callback());
|
||||
const io = require('socket.io')(server);
|
||||
const io = require('socket.io')(server, {cors: true});
|
||||
// let leaveRoom = () => {
|
||||
// }
|
||||
let list = await app.load(config.path)
|
||||
app.io = io
|
||||
app.alias["$io"] = app.io
|
||||
//等待所有插件载入完成后
|
||||
app.willReadyList.push(async () => {
|
||||
//默认命名空间
|
||||
@@ -24,17 +29,35 @@ module.exports = async (app) => {
|
||||
}
|
||||
});
|
||||
console.log('连接=>', "id:" + socket.id);
|
||||
|
||||
//监听disconnect事件
|
||||
socket.on('disconnect', (eventName, callback) => {
|
||||
console.log('断开=X', "id:" + socket.id)
|
||||
})
|
||||
// socket.on('disconnect', (eventName, callback) => {
|
||||
// console.log('断开=X', "id:" + socket.id)
|
||||
// leaveRoom(socket, {msg: '', onname: 'leaveRoom', callback})
|
||||
// })
|
||||
for (let el of list) {
|
||||
//空间名称
|
||||
// const namespace = path.basename(path.resolve(el.parse.dir, '..'))
|
||||
//事件名称
|
||||
const onname = el.parse.name
|
||||
socket.on(onname, (msg, callback) => {
|
||||
el.res(app, msg, callback)
|
||||
// if (onname === 'leaveRoom') {
|
||||
// //离开房间处理
|
||||
// leaveRoom = (socket, {msg, onname, callback}) => el.res.fun(socket, {msg, onname, callback})
|
||||
// }
|
||||
socket.on(onname, (msg, callback, anotherSocketId) => {
|
||||
console.log('anotherSocketId', socket.id);
|
||||
const validate = parameter.validate(el.res.params, msg);
|
||||
if (validate) {
|
||||
socket.emit('error', {
|
||||
event: onname,
|
||||
res : app.res.error(validate, "参数验证不通过", 204)
|
||||
})
|
||||
console.error('socket', socket.id, msg, onname, app.res.error(validate, "参数验证不通过", 204));
|
||||
// ctx.body = app.res.error(validate, "参数验证不通过", 204)
|
||||
} else {
|
||||
el.res.fun(socket, {msg, onname, callback})
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
});
|
||||
@@ -45,9 +68,15 @@ module.exports = async (app) => {
|
||||
//覆盖启动方法
|
||||
app.startServer = () => {
|
||||
// 监听端口
|
||||
app.startServer = server.listen(3000, () => {
|
||||
console.log('listening on *:3000');
|
||||
const port = (process.env.NODE_ENV === 'test' && config.test_port) || config.port || 3000
|
||||
const baseURL = "http://127.0.0.1"
|
||||
app.config.port = port
|
||||
app.config.baseURL = baseURL
|
||||
app.server = server.listen(port, () => {
|
||||
console.log(`http 服务: ${baseURL}:${port}`);
|
||||
console.log(`socket 服务: ${baseURL}:${port}`);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* For a detailed explanation regarding each configuration property, visit:
|
||||
* https://jestjs.io/docs/configuration
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
// 测试中所有导入的模块都应该自动模拟
|
||||
// automock: false,
|
||||
|
||||
// `n` 次失败后停止运行测试
|
||||
// bail: 0,
|
||||
|
||||
// TJest 应该存储其缓存依赖信息的目录
|
||||
// 缓存目录:“privatevarfolderscdm9j91n110831mbzcxnqtlz700000gnTjest_dx”,
|
||||
|
||||
// 每次测试前自动清除模拟调用、实例、上下文和结果
|
||||
clearMocks: true,
|
||||
|
||||
// 指示是否应在执行测试时收集覆盖率信息
|
||||
collectCoverage: false,
|
||||
|
||||
// 一组 glob 模式,指示应为其收集覆盖信息的一组文件
|
||||
// collectCoverageFrom: undefined,
|
||||
|
||||
// Jest 应该输出其覆盖文件的目录
|
||||
coverageDirectory: "coverage",
|
||||
|
||||
// 用于跳过覆盖收集的正则表达式模式字符串数组
|
||||
coveragePathIgnorePatterns: [
|
||||
"/node_modules/"
|
||||
],
|
||||
|
||||
// 指示应使用哪个提供程序来检测代码以进行覆盖
|
||||
coverageProvider: "v8",
|
||||
|
||||
// Jest 在编写报道报告时使用的记者姓名列表
|
||||
// coverageReporters: [
|
||||
// "json",
|
||||
// "text",
|
||||
// "lcov",
|
||||
// "clover"
|
||||
// ],
|
||||
|
||||
// 为覆盖结果配置最小阈值强制执行的对象
|
||||
// coverageThreshold: undefined,
|
||||
|
||||
// 自定义依赖项提取器的路径
|
||||
// dependencyExtractor: undefined,
|
||||
|
||||
// 调用已弃用的 API 会引发有用的错误消息
|
||||
// errorOnDeprecated: false,
|
||||
|
||||
// 假定时器的默认配置
|
||||
// fakeTimers: {
|
||||
// "enableGlobally": false
|
||||
// },
|
||||
|
||||
// 使用 glob 模式数组强制从被忽略的文件中收集覆盖率
|
||||
// forceCoverageMatch: [],
|
||||
|
||||
// 导出异步函数的模块的路径,该函数在所有测试套件之前触发一次
|
||||
// globalSetup: undefined,
|
||||
|
||||
// 导出所有测试套件后触发一次的异步函数的模块的路径
|
||||
// globalTeardown: undefined,
|
||||
|
||||
// 一组需要在所有测试环境中可用的全局变量
|
||||
// globals: {},
|
||||
|
||||
// 用于运行测试的最大工作人员数量。可以指定为 % 或数字。例如。 maxWorkers: 10% 将使用 CPU 数量的 10% + 1 作为最大工作线程数。 maxWorkers: 2 将使用最多 2 个工人。
|
||||
// maxWorkers: "50%",
|
||||
|
||||
// 从需要模块的位置递归搜索的目录名称数组
|
||||
// moduleDirectories: [
|
||||
// "node_modules"
|
||||
// ],
|
||||
|
||||
// 您的模块使用的一系列文件扩展名
|
||||
// moduleFileExtensions: [
|
||||
// "js",
|
||||
// "mjs",
|
||||
// "cjs",
|
||||
// "jsx",
|
||||
// "ts",
|
||||
// "tsx",
|
||||
// "json",
|
||||
// "node"
|
||||
// ],
|
||||
|
||||
// 从正则表达式到模块名称或模块名称数组的映射,允许使用单个模块存根资源
|
||||
// moduleNameMapper: {},
|
||||
|
||||
// 一个正则表达式模式字符串数组,在被认为对模块加载器“可见”之前与所有模块路径匹配
|
||||
// modulePathIgnorePatterns: [],
|
||||
|
||||
// 激活测试结果通知
|
||||
// notify: false,
|
||||
|
||||
// 一个指定通知模式的枚举。需要 { 通知:真 }
|
||||
// notifyMode: "failure-change",
|
||||
|
||||
// A preset that is used as a base for Jest's configuration
|
||||
// preset: undefined,
|
||||
|
||||
// Run tests from one or more projects
|
||||
// projects: undefined,
|
||||
|
||||
// Use this configuration option to add custom reporters to Jest
|
||||
// reporters: undefined,
|
||||
|
||||
// Automatically reset mock state before every test
|
||||
// resetMocks: false,
|
||||
|
||||
// Reset the module registry before running each individual test
|
||||
// resetModules: false,
|
||||
|
||||
// A path to a custom resolver
|
||||
// resolver: undefined,
|
||||
|
||||
// Automatically restore mock state and implementation before every test
|
||||
// restoreMocks: false,
|
||||
|
||||
// The root directory that Jest should scan for tests and modules within
|
||||
// rootDir: undefined,
|
||||
|
||||
// A list of paths to directories that Jest should use to search for files in
|
||||
// roots: [
|
||||
// "<rootDir>"
|
||||
// ],
|
||||
|
||||
// Allows you to use a custom runner instead of Jest's default test runner
|
||||
// runner: "jest-runner",
|
||||
|
||||
// The paths to modules that run some code to configure or set up the testing environment before each test
|
||||
// setupFiles: [],
|
||||
|
||||
// A list of paths to modules that run some code to configure or set up the testing framework before each test
|
||||
// setupFilesAfterEnv: [],
|
||||
|
||||
// The number of seconds after which a test is considered as slow and reported as such in the results.
|
||||
// slowTestThreshold: 5,
|
||||
|
||||
// A list of paths to snapshot serializer modules Jest should use for snapshot testing
|
||||
// snapshotSerializers: [],
|
||||
|
||||
// The test environment that will be used for testing
|
||||
// testEnvironment: "jest-environment-node",
|
||||
|
||||
// Options that will be passed to the testEnvironment
|
||||
// testEnvironmentOptions: {},
|
||||
|
||||
// Adds a location field to test results
|
||||
// testLocationInResults: false,
|
||||
|
||||
//Jest 用于检测测试文件的 glob 模式
|
||||
testMatch: ["**/+(*.)+(spec|test).+(ts|js)?(x)"],
|
||||
|
||||
// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
|
||||
// testPathIgnorePatterns: [
|
||||
// "/node_modules/"
|
||||
// ],
|
||||
|
||||
// The regexp pattern or array of patterns that Jest uses to detect test files
|
||||
// testRegex: [],
|
||||
|
||||
// This option allows the use of a custom results processor
|
||||
// testResultsProcessor: undefined,
|
||||
|
||||
// This option allows use of a custom test runner
|
||||
// testRunner: "jest-circus/runner",
|
||||
|
||||
// 从正则表达式到转换器路径的映射
|
||||
// transform: undefined,
|
||||
|
||||
// 与所有源文件路径匹配的正则表达式模式字符串数组,匹配的文件将跳过转换
|
||||
// transformIgnorePatterns: [
|
||||
// "/node_modules/",
|
||||
// "\\.pnp\\.[^\\/]+$"
|
||||
// ],
|
||||
|
||||
// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
|
||||
// unmockedModulePathPatterns: undefined,
|
||||
|
||||
// Indicates whether each individual test should be reported during the run
|
||||
// verbose: undefined,
|
||||
|
||||
// An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
|
||||
// watchPathIgnorePatterns: [],
|
||||
|
||||
// Whether to use watchman for file crawling
|
||||
// watchman: true,
|
||||
|
||||
|
||||
"testTimeout": 1000000
|
||||
};
|
||||
+38
-8
@@ -11,12 +11,25 @@ module.exports = class Bamboo extends Koa {
|
||||
/*初始化业务目录*/
|
||||
constructor(extend_directory, root) {
|
||||
super();
|
||||
//全局配置
|
||||
this.config = {}
|
||||
//xe-utils工具
|
||||
this.xe = xe
|
||||
//根目录
|
||||
this.root = this.isPath() || root;
|
||||
//插件路径
|
||||
this.extend_directory = extend_directory || `extend/*/index.js`
|
||||
//等待扩展已经加载完成后立即执行的任务列表
|
||||
this.willReadyList = []
|
||||
console.log(`当前根目录${this.root}`);
|
||||
console.log(`当前插件目录${this.extend_directory}`);
|
||||
//全局别名,推荐命名规则,$+全局变量名,如$db
|
||||
this.alias = {
|
||||
"app": this,
|
||||
"$": this,
|
||||
}
|
||||
//等待启动完成后立即执行的任务列表
|
||||
this.fullList = []
|
||||
// console.log(`当前根目录${this.root}`);
|
||||
// console.log(`当前插件目录${this.extend_directory}`);
|
||||
this.loadEvent()
|
||||
}
|
||||
|
||||
@@ -26,17 +39,33 @@ module.exports = class Bamboo extends Koa {
|
||||
for (let listElement of list) {
|
||||
await listElement.res(this)
|
||||
}
|
||||
this.willReadyList.push(() => {
|
||||
this.startServer()
|
||||
})
|
||||
await this.loadAlias()
|
||||
await this.willReady()
|
||||
}
|
||||
|
||||
/*加载别名到全局变量,注意只有完成加载扩展后才能使用*/
|
||||
async loadAlias() {
|
||||
for (let key of Object.keys(this.alias)) {
|
||||
global[key] = this.alias[key]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*扩展已经加载完成触发*/
|
||||
async willReady() {
|
||||
this.willReadyList.push(async () => {
|
||||
await this.startServer()
|
||||
await this.full()
|
||||
})
|
||||
for (let WRL of this.willReadyList) {
|
||||
await WRL()
|
||||
await WRL(this)
|
||||
}
|
||||
}
|
||||
|
||||
/*启动完成*/
|
||||
async full() {
|
||||
for (let ful of this.fullList) {
|
||||
await ful(this)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +89,7 @@ module.exports = class Bamboo extends Koa {
|
||||
files = files.map(item => {
|
||||
const parse = path.parse(item);
|
||||
parse.father = path.basename(path.resolve(parse.dir, '..'))
|
||||
parse.file_father = path.basename(path.resolve(parse.dir + '/' + parse.name, '..'))
|
||||
return {
|
||||
parse,
|
||||
res: require(path.resolve(path_root + "/" + item))
|
||||
@@ -73,7 +103,7 @@ module.exports = class Bamboo extends Koa {
|
||||
|
||||
/*启动服务*/
|
||||
startServer(prod) {
|
||||
this.listen(prod || 3000)
|
||||
console.log('启动服务:3000');
|
||||
app.server = this.listen(prod || 3000)
|
||||
console.log(`http服务:http://127.0.0.1:${prod || 3000}`);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -1,4 +1,4 @@
|
||||
//入口文件
|
||||
// 入口文件
|
||||
require('@babel/register')({
|
||||
presets: ['@babel/env'],
|
||||
plugins: [
|
||||
@@ -12,7 +12,8 @@ require('@babel/register')({
|
||||
|
||||
]
|
||||
})
|
||||
require('@babel/polyfill')
|
||||
// require('@babel/polyfill')
|
||||
const bamboo = require('./bamboo/index')
|
||||
const app = new bamboo();
|
||||
// app.listen(3000);
|
||||
module.exports = app
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
'use strict';
|
||||
const bodyParser = require('koa-bodyparser')
|
||||
// 错误处理
|
||||
// 解析json的入参
|
||||
module.exports = {
|
||||
sort: 4, //排序
|
||||
sort: 2, //排序
|
||||
use : true, // 是否使用
|
||||
fun : bodyParser()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
'use strict';
|
||||
const cors = require('@koa/cors')
|
||||
// 跨域
|
||||
module.exports = {
|
||||
sort: 0, //排序
|
||||
use : true, // 是否使用
|
||||
fun : cors()
|
||||
}
|
||||
@@ -3,7 +3,7 @@ const error = require('koa-json-error')
|
||||
// 错误处理
|
||||
module.exports = {
|
||||
sort: 3, //排序
|
||||
use : true, // 是否使用
|
||||
use : false, // 是否使用
|
||||
fun : error((err) => {
|
||||
return {
|
||||
status : err.status,
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
path : "app/*/model/*.js",
|
||||
prefix : "auto",//接口前缀
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
'use strict';
|
||||
/**
|
||||
* 加载模型到路由
|
||||
* 加载app/api目录下的文件到路由
|
||||
*/
|
||||
const Router = require('koa-router')
|
||||
const config = require("./config")
|
||||
|
||||
// 错误处理
|
||||
module.exports = {
|
||||
sort : 999, //排序
|
||||
use : false, // 是否使用
|
||||
loadFun: async (app, fun) => { // 自行定义中间件的加载方式,将覆盖默认加载方法
|
||||
const router = await fun(app)
|
||||
app.use(router.routes()).use(router.allowedMethods())
|
||||
},
|
||||
fun : async (app) => {
|
||||
const router = new Router({ //设置前缀
|
||||
prefix: config.prefix
|
||||
});
|
||||
let list = await app.load(config.path)
|
||||
list.forEach(item => {
|
||||
|
||||
})
|
||||
return router
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
'use strict';
|
||||
|
||||
/*封装入参*/
|
||||
module.exports = {
|
||||
sort: 3, //排序
|
||||
sort: 5, //排序
|
||||
use : true, // 是否使用
|
||||
fun : async (ctx, next, app) => {
|
||||
|
||||
ctx.params = ctx.request.body || ctx.query
|
||||
|
||||
await next()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module.exports = {
|
||||
path : "app/*/api/*.js",
|
||||
prefix : "",//接口前缀
|
||||
statusTobody: true,//是否跟随body结果(如需接口报错也返回200,那么设置为false)
|
||||
statusTobody: false,//是否跟随body结果(如需接口报错也返回200,那么设置为false)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
const Router = require('koa-router')
|
||||
const config = require("./config")
|
||||
|
||||
// const parameter = require('./parameter');
|
||||
// 错误处理
|
||||
module.exports = {
|
||||
sort : 999, //排序
|
||||
@@ -15,36 +15,56 @@ module.exports = {
|
||||
app.use(router.routes()).use(router.allowedMethods())
|
||||
},
|
||||
fun : async (app) => {
|
||||
const parameter = app.parameter
|
||||
const router = new Router({ //设置前缀
|
||||
prefix: config.prefix
|
||||
});
|
||||
let list = await app.load(config.path)
|
||||
list.forEach(item => {
|
||||
const url = item.res.path ? item.res.path : '/' + item.parse.father + '/api/' + item.parse.name
|
||||
console.log(url);
|
||||
router.all(url, async (ctx, next) => {
|
||||
await next();
|
||||
const validate = parameter.validate(item.res.params, ctx.params);
|
||||
let res = null
|
||||
if (validate) {
|
||||
ctx.body = app.res.error(validate, "参数验证不通过", 204)
|
||||
} else {
|
||||
/*处理body结果*/
|
||||
try {
|
||||
const res = await item.res.fun(ctx, app)
|
||||
res = await item.res.fun(ctx, app)
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
ctx.body = app.res.error(null, "系统错误", 500)
|
||||
}
|
||||
}
|
||||
|
||||
if (!ctx.body) {
|
||||
if (res) {
|
||||
if (res.status&&res.message) {
|
||||
ctx.body = res
|
||||
}else{
|
||||
ctx.body = app.res.success(res)
|
||||
}
|
||||
} else if (res === false) {
|
||||
ctx.body = app.res.error()
|
||||
} else {
|
||||
ctx.body = app.res.success()
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
ctx.body = app.res.error(null, "系统错误", 500)
|
||||
ctx.status = 500
|
||||
}
|
||||
|
||||
//是否跟随body结果
|
||||
ctx.status = config.statusTobody ? ctx.body.status || 400 : 200
|
||||
await next();
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
router.all('/', async (ctx, next) => {
|
||||
|
||||
ctx.body = app.res.success("ok")
|
||||
ctx.status = 200
|
||||
await next();
|
||||
})
|
||||
return router
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
const Parameter = require('parameter');
|
||||
const parameter = new Parameter();
|
||||
|
||||
//添加规则
|
||||
// parameter.addRule('123', (rule, value) => {
|
||||
// if (value !== '123') {
|
||||
// return 'must be 123';
|
||||
// }
|
||||
// });
|
||||
|
||||
module.exports = parameter
|
||||
+1
-1
@@ -5,5 +5,5 @@
|
||||
".idea",
|
||||
"node_modules/**/node_modules"
|
||||
],
|
||||
"exec": "node lib/main.js"
|
||||
"exec": "npm run start"
|
||||
}
|
||||
|
||||
+24
-11
@@ -6,24 +6,30 @@
|
||||
"scripts": {
|
||||
"dev": "nodemon",
|
||||
"start": "node lib/main.js",
|
||||
"server": "cross-env NODE_ENV=development nodemon bin/main.js"
|
||||
"server": "cross-env NODE_ENV=development nodemon bin/main.js",
|
||||
"test": "jest --forceExit"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.5.5",
|
||||
"@babel/cli": "^7.18.6",
|
||||
"@babel/core": "^7.18.6",
|
||||
"@babel/node": "^7.18.6",
|
||||
"@babel/plugin-proposal-class-properties": "^7.16.7",
|
||||
"@babel/plugin-proposal-decorators": "^7.17.9",
|
||||
"@babel/plugin-transform-runtime": "^7.5.5",
|
||||
"@babel/preset-env": "^7.5.5",
|
||||
"@babel/register": "^7.5.5",
|
||||
"@babel/preset-env": "^7.18.6",
|
||||
"@babel/register": "^7.18.6",
|
||||
"@babel/runtime": "^7.18.6",
|
||||
"art-template": "^4.13.2",
|
||||
"babel-plugin-webpack-alias": "^2.1.2",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"babel-register": "^6.26.0",
|
||||
"cross-env": "^5.2.0",
|
||||
"chai": "^4.3.6",
|
||||
"cross-env": "^7.0.3",
|
||||
"ejs": "^2.6.2",
|
||||
"jest": "^28.1.1",
|
||||
"koa": "^2.7.0",
|
||||
"koa-art-template": "^1.1.1",
|
||||
"koa-bodyparser": "^4.2.1",
|
||||
@@ -33,24 +39,28 @@
|
||||
"koa-views": "^6.2.0",
|
||||
"koa-webpack": "^6.0.0",
|
||||
"koa-webpack-middleware": "^1.0.7",
|
||||
"mocha": "^10.0.0",
|
||||
"mysql-import": "^5.0.21",
|
||||
"nodeenv": "^1.0.0",
|
||||
"nodemon": "^1.19.1"
|
||||
"nodemon": "^1.19.4",
|
||||
"sequelize-mock": "^0.10.2",
|
||||
"supertest": "^6.2.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.16.7",
|
||||
"@babel/node": "^7.16.8",
|
||||
"@babel/plugin-proposal-decorators": "^7.18.2",
|
||||
"@babel/polyfill": "^7.4.4",
|
||||
"@babel/preset-env": "^7.16.8",
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"@koa/cors": "^3.3.0",
|
||||
"ajv": "^8.11.0",
|
||||
"axios": "^0.27.2",
|
||||
"babel-loader": "^8.2.3",
|
||||
"bamboo_smf": "^1.0.5",
|
||||
"bullmq": "^1.85.1",
|
||||
"clean-webpack-plugin": "^4.0.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"crypto": "^1.0.1",
|
||||
"glob": "^8.0.1",
|
||||
"ioredis": "^5.0.5",
|
||||
"jest": "^28.1.1",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"koa-bodyparser": "^4.3.0",
|
||||
"koa-json-error": "^3.1.2",
|
||||
"koa-logger": "^2.0.1",
|
||||
@@ -58,6 +68,7 @@
|
||||
"koa-router": "^7.4.0",
|
||||
"log4js": "^6.4.4",
|
||||
"mysql2": "^2.3.3",
|
||||
"mysqldump": "^3.2.0",
|
||||
"node-schedule": "^2.1.0",
|
||||
"object-path": "^0.11.8",
|
||||
"parameter": "^3.6.0",
|
||||
@@ -68,6 +79,8 @@
|
||||
"shelljs": "^0.8.5",
|
||||
"socket.io": "^4.5.1",
|
||||
"sqlite3": "^5.0.2",
|
||||
"supertest": "^6.2.3",
|
||||
"uuid": "^8.3.2",
|
||||
"webpack": "^4.41.5",
|
||||
"webpack-cli": "3.3.10",
|
||||
"webpack-node-externals": "^3.0.0",
|
||||
|
||||
Reference in New Issue
Block a user